views:

551

answers:

3

My first question =). I'm writing a video game with a user interface written in JavaFx. The behavior is correct, but I'm having performance problems. I'm trying to figure out how to figure out what is queuing up the refreshes which are slowing down the app.

I've got a relatively complex Scene Graph that represents a hexagonal map. It scales so that you could have 100 or a 1000 hexagons in the map. As the number of hexagons grow the responsiveness of the gui decreases. I've used YourKit (a Java Profiler) to trace these delays to major redraw operations.

I've spent most of the night trying to figure out how to do two things and understand one thing:

1) Cause a CustomNode to print something to the console whenever it is painted. This would help me identify exactly when these paints are being queued.

2) Identify when a CustomNode is put on the repaint queued.

If I answered 1 and 2, I might be able to figure out what it is that is binding all these different nodes together. Is it possible that JavaFX only works through global refreshes (doubtful)?

+1  A: 

Hi Spina

JavaFX script is a powerful UI language but certain practices will kill performance. Best performance generally boils down to:

  • keeping the Scene Graph small

  • keeping use of bind to a minimum (you can look at using triggers instead which are more performant)

This blog post by Jim Weaver expands these points.

I'm not sure as to the specific answers to your questions. If you examine the 1.2.1 docs you might be able to find a point in the Node documentation that you can override and add println statements but I'm not sure it can be done. You could try posting on forums.sun.com

Matthew Hegarty
Hi MashThanks for the suggestions. I've read that post and think I understand it. The problem is that the post doesn't give you any analytic methods to find out what in particular is causing a delay. I've done some profiling and believe that the majority of the computation time in my code is spent in JSGPanelRepainter.repaintAll(). The problem is that none of my model, or presentation is changing in a way to require a complete repaint. That causes me to wonder what is triggering the repaintAll(). I just don't know how to trace that.Cheers.
Spina
@Spina In JFX 1.2, redraws happen frequently, even when unnecessary. 1.3 is supposed to have MUCH better performance, selectively redrawing only when absolutely necessary. Amy Fowler points out in this presentation (http://steveonjava.com/2009/12/18/javafx-layout-secrets/) that very issue.
Mike Caron
A: 

This is a partial post. I expect to expand it after I've done some more work. I wanted to put in what I've done to date so I don't forget.

I realized that I'd need to get my IDE running with a full compliment of the JavaFx 1.2 source. This would allow me to put break points into the core code to figure out what is going on. I decided to do this configuration on Eclipse for remote debugging. I'm developing my FX in Netbeans but am more comfortable with Eclipse so that's what I want to debug in if I can.

To get this info into Eclipse, I first made a project with the Java source that my code uses. I then added external Jars to the project. On my Mac, the Jars I linked to were in /Library/Frameworks/JavaFX.framework/Versions/1.2

Then I went searching for the Source to link to these Jars. Unfortunately, it's not available. I could find some of it in /Library/Frameworks/JavaFX.framework/Versions/1.2/src.zip.

I did some research and found that the only available option left was to install a Java Decompilier. I used this one because it was easy to install into Eclipse 3.4: http colon_ //java dot decompiler _dot free.fr/ (<-- Please forgive the psudo link, I'm limited because I'm new)

This is where I am now. I can navigate into the Core FX classes and believe I'll be able to set break points and begin real analysis. I'll update this post as I progress.

I found a helpful benchmarking tool:

If you run with the JVM arg:

-Djava.util.logging.config.file=/path/to/logging/file/logging.properties

And you've put the following args into the file referenced by that arg:

handlers = java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = ALL java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter com.sun.scenario.animation.fps.level = ALL

You'll get console output that includes your frame count per second. For FX 1.2 it wasn't working for me, but it appears to be working for 1.2.1 (which was released Sept. 9, 2009.) I don't have a Netbeans that runs 1.2.1 yet.

Spina
A: 

You may want to read this article.

http://fxexperience.com/2009/09/performance-improving-insertion-times/

Basically, insertions in to the scenegraph are slow and benefits can be seen by batching up inserts

Steven Herod
Thanks Steven! I haven't encountered fxexperience.com before. It's a nice resource, and the article was definitely enlightening.I've been doing some guess and check optimization and putcache: truein some of my components, I've gone from 7 FPS for a map with 100 hexagons to 13 FPS. It's still too slow, but it's getting better. Since all 100 aren't on the screen at the same time, I'm considering some sort of dynamic addition/removal so only the visible ones are in the scene graph.
Spina
The new scene graph (Prism) should arrive later this year (Nov/Dec?), that apparently promises significantly improved performance.
Steven Herod