Node Count and JavaFX Performance
By Jim Connors on Apr 06, 2009
In a recent blog entry entitled Best Practices for JavaFX Mobile Applications (Part 2), Michael Heinrichs espouses that keeping the scenegraph as small as possible helps JavaFX applications perform optimally. Regardless what version of JavaFX you're using, this is sage advice. Having spent some time trying to create components for a scoreboard-like application, I was concerned over the amount of CPU time being consumed by the clock component pictured directly below.
You can click on the preceding image to run this mini application via Java WebStart. By placing your mouse over any of the digits and typing in, via keyboard input, a valid number, you can set the clock. Clicking on the "START/STOP" text will toggle the clock on and off. Like many scoreboard clocks, when the time remaining is less than one minute, 10ths of seconds are displayed. It is during this phase, when digits are being updated every tenth of a second, that this application can be especially taxing. You can imagine how troublesome this clock might be if it were to be part of say a hockey scoreboard which could have an additional 4 penalty clocks ticking simultaneously.
The major factor affecting performance appears to be the sheer number of nodes in the scenegraph that require recalculation for every clock tick. For this first implementation, each of the five clock digits is comprised of 27 BulbNodes, (my naming) which are switched on or off depending upon what value needs to be displayed.
In an effort to see how decreasing the node count might effect performance, this second implementation of the clock component uses the same underlying framework, except that each digit is now composed of 7 LED SegmentNodes (my naming again) instead of 27 BulbNodes. You can run this version of the clock component by clicking on the image that follows.
For our final example, in order to truly minimize node count, each digit is represented by a single ImageView node. When the value of a digit changes, a new Image
is displayed. By caching all of the possible digit values (blank, 0-9)
you can very quickly switch images. No doubt, prettier images can be created, but I think you get the point. Click on the image that follows to try this version.
The slower the compute platform, the more pronounced the differences in performance should be. Thinking along those lines, a very modest 1.4 GHz Pentium M laptop was chosen as the test environment to compare CPU utilization for these applications. OpenSolaris provides an easy-to-use well-known command-line tool called vmstat(1M), which was chosen as the mechanism to analyze the individual applications. In contrast, the Performance Tab which is part of the Windows Task Manager, seemed to produce wild performance variations.
For each run, the clocks were set to one minute, and run until the time expired. The data shown below represents the average CPU utilization, after startup, for each of the three implementations. In particular we'll look at the following fields returned by vmstat:
- us - percentage usage of CPU time in user space
- sy - percentage usage of CPU time in system space
- id - percentage usage of CPU time idling
|| Number of Nodes per Digit
|| CPU Utilization
| Implementation 1: BulbClockNode
|| 27 BulbNodes
|| us: 22% sy: 2% id: 76%
| Implementation 2: LEDClockNode
|| 7 SegmentNodes
|| us: 9% sy: 2% id: 89%
| Implementation 3: ImageClockNode
|| 1 ImageNode
|| us: 3% sy: 2% id: 95%
The JavaFX engineering team is well aware of this limitation, and hopes to redesign the underlying scenegraph plumbing in the future. Regardless, it's still a good idea to take into consideration the size of your scenegraph.