An important difference twixt server and client VM

You have heard many times the mantra “code in because the JVM that makes it free.”

Think again, Buster!

Dynamic dead code elimination is not performed by the client VM! Consider this bit of code, like I was the other day:


if (Sys.DEBUG) {
checkGLError();
}

Sys.DEBUG is a static final boolean but it’s not known what value it will take until classloading; therefore the java compiler can’t simply remove the code during the build.

A few experiments with commenting out the code:


//if (Sys.DEBUG) {
//checkGLError();
//}

and timing it using our hires timer show us that the Hotspot Server VM eliminates it immediately and completely - the commented out code runs at exactly the same speed as the uncommented out code when Sys.DEBUG is false.

The lamentable client VM, on the other hand, retains the check, and executes slower, even though it will always be false. Bah.

Where’s my two-stage-compile converged JVM eh??? The client VM is definitely a performance hobbler when you start to do clever stuff that’s not actually rendering - like shadow volume calculations and such…

Cas :slight_smile:

Which is why Java 1.4 assertions are not as free as we’ve been told:
http://wiki.java.net/bin/view/Javapedia/AssertionsAreFreeMisconception

Umn, I think we need to take a closer look at your benchmark.

While you would think this is true, that a static final shouldn’t be resovled til runtime, I’ve always been told that Javac in fact DOES determine static final values from otehr classes by lookup at compile time.

I’ve had long debates with some oterhs as to whether this is symaticly correct, which is why this statement caught my eye in the first place.

I’ve been told that pre-resolving static finals is necessary in order to preserve the security structure of the language…

SO I have a strong suspicion you aren’t measuring what you think you are… which is a common failing of microbenchrmarks.

Present your complete benchmark and maybe we can figure out where the result is really coming from.

That wouldn’t work for dynamic values however would it? For example lets say this boolean random, or maybe true only when the day was a Monday? Or perhaps it was passed in as property (eg.

public static final boolean USE_CACHE = “true”.equalsIgnoreCase(System.getProperty(“xith3d.cache.transients”));

This topic is currently also being debated in this thread: http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=xith3d;action=display;num=1066672655;start=

Will.

Hmm. A good point. That would have to be deferred til run-time assuming its a legal construct. Id really have to take 20 min and program a bunch of quick unambiguos test cases before I’d have a lot of confidence in how it all worked.

It’s almost certainly true what I’m saying. The code is very simple and easy to measure:

class X {
void y(int[] value) {
if (Sys.DEBUG) { // Sys.DEBUG cannot be determined until runtime
throw new RuntimeException();
}
value[0] ++;
}
}

X x = new X();
int[] v = new int[1];
long then = Sys.getTime();
for (int i = 0; i < 10000000; i ++) {
x.y(v);
}
long now = Sys.getTime();
System.out.println(v[0]);
System.out.println( (float) (now - then) / (float) Sys.getTimerResolution() );

Cas :slight_smile:

Oh dear. We checked this with 1.3.x, and have been using static-final-boolean’s for debug ever since. I’d assumed that it had worked on both client and server - certainly it did work. However, we nerly always use the server VM, and don’t guarantee support for the client, so I guess I just didn’t pay enough attention when someone told me the results :).

I agree this is very worrying though, since server VM isn’t available with JRE :(.

It’s freely distributable separately to the JRE. The real problem is that the server VM is fantastically slow starting up, yet it’s the only VM fast enough to compete with C++. There were rumours that the two were going to be consolidated into a two-phase compilation VM a couple of years ago but it’s gone quiet since then.

I’m also wondering how other implementations handle it. The Mac port is of particular interest suddenly…

Just realised you may be thinking about something different to me here: a static final boolean that can be resolved at compile time causes JavaC to eliminate dead code for you. But if it has to wait until classload to determine it - the server VM’s the only one that knows how to handle it.

Cas :slight_smile:

[quote]Just realised you may be thinking about something different to me here: a static final boolean that can be resolved at compile time causes JavaC to eliminate dead code for you. But if it has to wait until classload to determine it - the server VM’s the only one that knows how to handle it.

Cas :slight_smile:
[/quote]
I was just about to point out that this is the key difference. Some static finals are known at compile time - in which case the dead code is eliminated before the VM ever sees it. If the value is established at run time it is a different story.

Ok I’ll bite, how far do you have to go to get the compiler able to strip out the dead code? I assume that a static final within a class will trigger this optimisation within a class, and I guess that a system property as shown before will have to be left until runtime.

But what about constants declared in an external class? What with dynamic class loading and all, does this mean that these must be left until runtime? Thats a real pain if you want to use Sys.DEBUG style flags since to be sure of the compiler doing its magic you’ll have to define it in every source file, not just in one global class :o

Will a few if statements really kill your performance anyway? It’s only a few more instructions per frame and a few more bytes in memory after all.

Will.

Well, yes - because I have been using Sys.DEBUG as freely as I was using assert - right in the middle of my rendering loops, and they’ve been costing a lot it turns out. That bit of code above executes 30% faster on the client VM when it’s commented out.

Cas :slight_smile:

[quote]Will a few if statements really kill your performance anyway? It’s only a few more instructions per frame and a few more bytes in memory after all.

Will.
[/quote]
In game servers, (Cas has already done the client story) you will typically call these more than a hundred thousand times a second, maybe a lot more.

If you have a sensible logging framework, a single logging call is likely to go through several objects and several methods, usually down a filtering chain (have a look at log4J, which IIRC is now part of the standard libs. It’s not a good logging framework - it’s too basic - but it does some things very well. IIRC it has a decent filtering system, allowing you to divert different log-messages to different sinks, multicast them, etc.)

Since your logging framework will tend to be more powerful and complex the more powerful and complex your app/server is, yeah this stuff really matters :(.

…P.S. you guessed right my mistake :). As it happens, we also actually only use class-local vars for this - mainly I expect because of your problem :(. If I’d found someone who remembered the original results, they’d probably have pointed that out to me in the first place :slight_smile:

Kinda moot though if you’re writing serverside code, because you can then use the server vm anyway which does successfully remove dynamically dead code.

Cas :slight_smile:

Ah. Okay, that fits with what I know.

JK

[quote]But what about constants declared in an external class? What with dynamic class loading and all, does this mean that these must be left until runtime?
[/quote]
No.

True constants are resolved at comp[iel time.

Yes this DOES mean that the value in use for the constant in one class may NOT match the value in another if they were compield against different versions of the class containing the constant.

Fortunately I discovered that a long, long time ago :slight_smile: Source of many strange bugs until I realised. More of a problem with command line compilation than IDEs though which recompile all the touched classes automatically.

…any internal news about the “hybrid” two-phase VM…?

Cas :slight_smile: