hudsonb / kubed

BSD 3-Clause "New" or "Revised" License
74 stars 4 forks source link

Performance improvements #4

Open yay opened 6 years ago

yay commented 6 years ago

Hi,

I'm looking at this now and I'm quite impressed, nice work there! But one thing that concerned me when profiling the CirclesDemo is how much time is spent null checking and getting the datum:

screen shot 2018-02-26 at 15 12 34

In this example 38% of all CPU time is spent in these two methods.

Property lookup in a HashMap is bound to be slow:

internal const val DATA_PROPERTY: String = "__data__"

/**
 * The datum associated with this Node, or Selection.UNDEFINED if there is none.
 */
var Node.datum: Any?
    get() = properties[DATA_PROPERTY]
    set(value) { properties[DATA_PROPERTY] = value }

I don't have any good ideas as to how this can be improved yet, just observations.

hudsonb commented 6 years ago

Kotlin adds Intrinsics.checkParameterIsNotNull to basically every public function that uses non-null types (you can read about it in Christophe Beyls Exploring Kotlin's hidden costs - Part 2). These runtime checks can be disabled with the -Xno-param-assertions compiler option if the performance degredation from this was really a concern in release/production.

The scenegraph in the CirclesDemo is fairly large (5000 circles). On each pulse both the translateX and translateY properties of each node are updated. If we assume 60fps, that's 600,000 calls to Node.datum a second. I could add Selection.translate(x: Double, y: Double, z: Double) allowing the translation to be set along each axis in one call, this would reduce the number of calls in half.

Probably the most effective performance optimization that could be made to this demo is to reduce the number of nodes. We could do this now by generating a Path containing the circles on each pulse. I'm also working on adding support for rendering to Canvas.

I've been using CirclesDemo and ManyPointsDemo to stress the system and highlight things like this. It's easy to increase the size of the scenegraph in both of these demonstrations.

yay commented 6 years ago

Thanks for the tips! -Xno-param-assertions helps somewhat. The actual path generation is a bit over my head ATM (as I'm still going through the code of this and JavaFx itself), but yeah, simply drawing on timer with no selections involved would help. I'm just being paranoid, I guess :) This is still a lot faster than D3: https://www.youtube.com/watch?v=DwEIMOsoGqU

hudsonb commented 6 years ago

I like to use the ManyPointsDemo.kt to compare D3 and Kubed performance (mainly because it's pretty).

Here is a block of mine that uses SVG nodes rather than Canvas (like the original) for comparison to kubed: https://bl.ocks.org/hudsonb/7beba51e38676fb6bafc0f266f7fa338

The D3 version turns into a slideshow with far fewer nodes than kubed... though it does seem to initialize faster.