Question

I'm trying to convert some Java2D code to JavaFX and I'm stuck with an issue regarding the performance of the JavaFX Canvas. At some point, I'll have to draw thousands of small circles on the screen.

My problem is that in the first drawing, my code takes a lot of time to execute. But if I have to perform a second drawing, it takes only a fraction of the time to draw (it is at least 10 times faster).

Is there anything I'm doing wrong? Is there any way to prevent that initial delay?

I wrote this code to test it. In this code I draw 500,000 circles at random positions on a 1000 x 1000 canvas (built previously). I linked this code to a button click event, and on the first time I click it takes 10 seconds to execute. But if I just click again, it takes only 0.025 seconds.

private void paintCanvas() {
    long initTime = System.currentTimeMillis();

    GraphicsContext cg = canvas.getGraphicsContext2D();
    cg.setFill(Color.WHITE);
    cg.fillRect(0, 0, canvas.getWidth(), canvas.getHeight());
    cg.setFill(Color.rgb(0, 0, 0, 0.1));

    Random rand = new Random();
    for (int i = 0; i < 500000; i++) {     
        cg.fillOval(1000 * rand.nextFloat(), 1000 * rand.nextFloat(), 2, 2);
    }

    long endTime = System.currentTimeMillis();
    System.out.println("Time spent on drawing:" + (endTime - initTime)/1000.0f);        
}

Actually there is no max number of new elements. It can vary from some hundreds to hundreds of thousands, depending of the users needs. And yes, it is ok if some elements pop in over time.

Was it helpful?

Solution

Guys I thank you for all help. I sent the same question to the OpenJFX mailing list and one of the developers answered. It seems that my JavaFX 2.2 version still use a old model for growing the command buffer. The new version, JavaFX 8, uses a more efficient model which makes the first painting as fast as the subsequent ones.

Here is the answer I got:

Jim Graham (james.graham at oracle.com)

Mon May 12 21:17:19 UTC 2014

This is likely due to growing the command buffer which was done linearly at one point (probably still done that way in 2.2), but is now exponential in 8.0. The first render time is nearly instantaneous in 8.0, but takes a long time as you found when I try it with one of my old 2.x builds...

      ...jim

OTHER TIPS

I can think of a couple things but let's start with one:

It could be that the JVM Just in Time compiler is hitting your execution. Depends on your JVM option (Whether it is client or server JIT, and whether you are using AggresiveOpts or not).

Remember, the JVM is smart enough to perform optimizations on that loop. In my opinion you can start there, put this on your JVM options when executing this: -XX:+PrintCompilation, and look at the output on console, your method should be compiled during the first execution and then you should not observe any compilations during the second. If this is so, then you know that this piece of code was compiled and stored in the CodeCache, and execution is not happening through the interpreter but through straight natively compiled code, which will have better performance.

Let us know your findings!

JVM options reference (might need to find your specific JVM doc): http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

P.S. can you try lowering the start time get right before you instantiate random?, it would be nice to be able to take two times, one at the beggining and right before the random, and the second, right after this last time and finally when the loop finished, the idea is to try and get a break down on where your code it's spending its time when you observe this (the loop, or the canvas instantiation).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top