Is there any differences in code optimization done by same versions of:
Oracle Java compiler
Apache Java compiler
IBM Java compiler
OpenJDK Java compiler.
If there is what code would demonstrate different optimizations? Or are they using same compiler? If there is no known optimization differences then where could I find resources on how to test compilers for different optimizations?
Is there any differences in code optimization done by same versions of: Oracle Java compiler Apache Java compiler IBM Java compiler OpenJDK Java compiler.
While compiler can be very different, the javac does almost not optimisations. The main optimisation is constant inlining and this is specified in the JLS and thus standard (except for any bugs)
If there is what code would demonstrate different optimizations?
You can do this.
final String w = "world";
String a = "hello " + w;
String b = "hello world";
String c = w;
String d = "hello " + c;
System.out.prinlnt(a == b); // these are the same String
System.out.prinlnt(c == b); // these are NOT the same String
In the first case, the constant was inlined and the String concatenated at compile time. In the second case the concatenation was performed at runtime and a new String created.
Or are they using same compiler?
No, but 99% of optimisations are performed at runtime by the JIT so these are the same for a given version of JVM.
If there is no known optimization differences then where could I find resources on how to test compilers for different optimizations?
I would be surprised if there is one as this doesn't sound very useful. The problem is that the JIT optimises pre built templates of byte code and if you attempt to optimise the byte code you can end up confusing the JIT and having slower code. i.e. there is no way to evaluated an optimisation without considering the JVM it will be run on.
No, they do not use the same compiler. I can't comment much about the optimizations and stuffs, but here's an example how the compilers are different in their working.
public class Test {
public static void main(String[] args) {
int x = 1L; // <- this cannot compile
}
}
If you use the standard java compiler, it'll throw an compilation error and the class file won't be created.
But if you use the eclipse compiler for java ECJ, it'll not only throw the same compilation error, but will also create a class file(YES, a class file for an uncompilable code, which makes ECJ, I wouldn't say wrong, but a bit tricky), which looks something like this.
public static void main(String[] paramArrayOfString)
{
throw new Error("Unresolved compilation problem: \n\tType mismatch: cannot convert from long to int.\n");
}
Having said that, this is just between 2 compilers. Other compilers may have their own way of working.
P.S: I took this example from here.
The only compilers that I have spent a great deal of time with are javac (which, as others have pointed out, does very little in terms of eager optimization) and the Eclipse compiler.
While writing a Java decompiler, I have observed a few (often frustrating) differences in how Eclipse compiles code, but not many. Some of them could be considered optimizations. Among them:
The Eclipse compiler appears to perform at least some duplicate code analysis. If two (or more?) blocks of code both branch to separate but equivalent blocks of code, the equivalent target blocks may be flattened into a single block with multiple entry jumps. I have never seen javac perform this type of optimization; the equivalent blocks would always be emitted. All of the examples I can recall happened to occur in switch statements. This optimization reduces the method size (and therefore class file size), which may improve load and verification time. It may even result in improved performance in interpreted mode (particularly if the interpreter in question performs inlining), but I imagine such an improvement would be slight. I doubt it would make a difference once the method has been JIT compiled. It also makes decompilation more difficult (grrr).
Basic blocks are often emitted in a completely different order from javac. This may simply be a side effect of the compiler's internal design, or it may be that the compiler is trying to optimize the code layout to reduce the number of jumps. This is the sort of optimization I would normally leave to the JIT, and that philosophy seems to work fine for javac.
Related
I have been pulled into a performance investigation of a code that is similar to the below:
private void someMethod(String id) {
boolean isHidden = someList.contains(id);
boolean isDisabled = this.checkIfDisabled(id);
if (isHidden && isDisabled) {
// Do something here
}
}
When I started investigating it, I was hoping that the compiled version would look like this:
private void someMethod(String id) {
if (someList.contains(id) && this.checkIfDisabled(id)) {
// Do something here
}
}
However, to my surprise, the compiled version looks exactly like the first one, with the local variables, which causes the method in isDisabled to always be called, and that's where the performance problem is in.
My solution was to inline it myself, so the method now short circuits at isHidden, but it left me wondering: Why isn't the Java Compiler smart enough in this case to inline these calls for me? Does it really need to have the local variables in place?
Thank you :)
First: the java compiler (javac) does almost no optimizations, that job is almost entirely done by the JVM itself at runtime.
Second: optimizations like that can only be done when there is no observable difference in behaviour of the optimized code vs. the un-optimized code.
Since we don't know (and the compiler presumably also doesn't know) if checkIfDisabled has any observable side-effects, it has to assume that it might. Therefore even when the return value of that method is known to not be needed, the call to the method can't be optimized away.
There is, however an option for this kind of optimization to be done at runtime: If the body (or bodies, due to polymorphism) of the checkIfDisabled method is simple enough then it's quite possible that the runtime can actually optimize away that code, if it recognizes that the calls never have a side-effect (but I don't know if any JVM actually does this specific kind of optimization).
But that optimization is only possible at a point where there is definite information about what checkIfDisabled does. And due to the dynamic class-loading nature of Java that basically means it's almost never during compile time.
Generally speaking, while some minor optimizations could possibly be done during compile time, the range of possible optimizations is much larger at runtime (due to the much increased amount of information about the code available), so the Java designers decided to put basically all optimization effort into the runtime part of the system.
The most-obvious solution to this problem is simply to rewrite the code something like this:
if (someList.contains(id)) {
if (this.checkIfDisabled(id)) {
// do something here
If, in your human estimation of the problem, one test is likely to mean that the other test does not need to be performed at all, then simply "write it that way."
Java compiler optimizations are tricky. Most optimizations are done at runtime by the JIT compiler. There are several levels of optimizations, the maximum number of optimizations by default will be made after 5000 method invocations. But it is rather problematic to see which optimizations are applied, since JIT compile the code directly into the platform's native code
I have the following code in my app:
public static final boolean DEBUG = true;
public static final boolean REL = !DEBUG;
private static final String DEBUG_OR_RELEASE = (REL) ? "RELEASE_VER" : "DEBUG_VER";
I thought that the Java compiler will eliminate the "DEBUG_VER" string completely from the resulting .apk file (when exported via Proguard) but when I examine the .apk file, I see the "DEBUG_VER" string in there.
Why? What am I missing? What did I do wrong?
Compilation to java bytecode is not making optimization (except a very few exceptions).
Many books state for simplification that the 'compilation' phase is when optimization occurs, but it is wrong. When the optimization really takes place, is while bytecode files are processed by JVM. So for the clearance: optimization may occur at the time of compilation bytecode to machine native code, which is done by JVM tools.
Sometimes there is no optimization at all (JVM works in interpreting mode). Sometimes there is some optimization made by JIT (Just In Time complier). And sometimes adaptative optimizer takes care of the optimization (not only optimizing but also profiling code execution in case of additional operations to be performed).
So finally, there is nothing wrong with your file. It's just how java world works.
"But why?" -- you may ask. The reason to keep this 'useless' information in bytecode is because you would never be sure how many code can you eliminate so the optimization provided by different JVM could still work efficient. The best way is just to not erase any information and let the optimizers to do their job.
According to what you posted, DEBUG is true, so REL is false, so (REL) ? "RELEASE_VER" : "DEBUG_VER" should yield "DEBUG_VER".
This is exactly what you are observing so if you are expecting to see "RELEASE_VER" instead, you should set:
public static final boolean DEBUG = false;
Try that and see what happens.
It's still being run even when the variable is set to true. ?: statements are part of executable and operational code, and since Java doesn't have a precompiler, it will be run every time you compile.
Java does not infer and simplify operations automatically, even if logically the operations are the same each iteration.
I was curious, I see this kind of thing a lot:
Arrays.sort(array, new Comparator<Integer>() {
public int compare(Integer a, Integer b) {
return Math.abs(a) < Math.abs(b);
}
});
since the anonymous class created here has no instance variables, is the standard JDK compiler smart enough to only instantiate that anonymous class once and reuse it? Or is it advisable to instantiate that anonymous class in a static field and always pass the static Comparator object?
UPDATE: When I say "JDK compiler", I mean the JIT portion too. The above is also just an example. I was really curious if I should, as a best practice, create static fields for the above instead of inlining anonymous class instantiations. In some cases the performance/resource usage issue will be negligible. But other cases might not be...
javac will definitely not do such thing; that would violate the language semantics. JVM could optimize it in theory, but it's not that smart yet. A static one would be faster.
Ironically, such analysis and optimization would be easy for javac, and it can be done today, except it's forbidden to do so - the source says new, so javac must new.
Rumor has it that the coming lambda expression in java 8 will make an effort on this issue, in
Arrays.sort(array, (Integer a,Integer b) => Math.abs(a)<Math.abs(b) )
javac is required to analyze that the lambda is stateless, and a lazily created single instance is enough, and that's what it must compile the code into.
The answer is maybe.
javac will compile this into bytecode that is true to your code. Therefore, the class will be instantiate anew each time this code is called. However the JVM performs many sophisticated optimisations at runtime, and MIGHT - depending on many factors - perform some optimisations here.
In any case, unless you've noticed a real performance issue here, I'd recommend not trying to manually optimise.
You can use javap to check yourself; my suspicion is that it will create it on every call. Such optimizations are handled by hotspot but in this case since the anonymous only has methods (no fields to initialize) the overhead is very small.
The real question here is not what javac will do. As Steve McLeod says, javac will produce bytecode which matches your source code. The question is what hotspot will do at runtime. I imagine it will simple inline the whole lot (including the Math.abs() call).
The compiler does very little optimisation. The jit does most of it. It will optimise this code but it won't avoid creating Integer objects and unless you have an array of Integer this will be your bottle neck. So much so that any other optimisation it does won't matter.
This question has received a total of several paragraphs of answer. Here is the only sentence that actually tells me what I was looking for:
Your examples would make little difference since intermediate computations need to be stored temporarily on the stack so they can be used later on.
In fact, it answers my question perfectly and completely =)
Unlike all the cruft telling me "nooo don't ask that question". >_<
Like if you have a method, and you change it by increasing the number of local variables but make no other changes, does it make the method slower? Here's an example:
void makeWindow() {
Display
.getContext()
.windowBuilder()
.setSize(800, 600)
.setBalloonAnimal(BalloonAnimal.ELDER_GOD.withColor(PUCE))
.build();
}
or
void makeWindow() {
DisplayContext dc = Display.getContext();
WindowBuilder wb = db.windowBuilder();
BalloonAnimal god = BalloonAnimal.ELDER_GOD;
BalloonAnimal puceGod = god.withColor(PUCE);
wb.setSize(800, 600).setBalloonAnimal(puceGod).build();
}
Another example:
int beAnExample(int quiche) {
return areGlobalsEvil?
quiche * TAU/5:
highway(quiche, Globals.frenchFrenchRevolution);
}
or
int beAnExample(int quiche) {
if (areGlobalsEvil) {
int to5 = TAU/5;
int result = quiche * to5;
return result;
} else {
Game french = Globals.frenchFrenchRevolution;
int result = highway(quiche, french);
return result;
}
}
Really, what I'm asking is: Is the number of this sort of local variable even relevant by the time the method's compiled to bytecode? If so, what about once Hotspot gets to work on it?
This question is relevant to the code generator I'm working on.
The easy answer is no. Local variables consume runtime stack space. Allocating space for them only marginally increases the number of instructions. Your examples would make little difference since intermediate computations need to be stored temporarily on the stack so they can be used later on. Focus more on the readability of your programs rather than needless micro-optimizations.
If you're interested in looking at the actual bytecode of a class, investigate the javap program.
Don't worry about it. The compiler can do all sorts of crazy, make-your-head-asplode optimizations. Start with code that's correct and maintainable. Programmer time is worth far more than processor tiem.
Test it by running each method 1,000,000 times and divide the total time to calculate the cost per execution. In all likelihood, it won't be noticable.
Actually, Java compilers may even be smart enough to just compile it out.
Write your code for readability to reduce long term cost of maintenance. Then tune it in the 5% of places where you really need to.
The chances are that it will make little (if any) difference, and the "little" will be insignificant.
Focus on making your generator correct and maintainable, and let the Java compiler (particularly the JIT compiler) do the micro-optimization of the generated code.
Note that #Edawg's advice on looking at the bytecode is not necessarily helpful. The JIT compiler aggressively optimizes the native code that it generates from the bytecodes. It can be difficult to predict which of two bytecode sequences is going to be faster. Certainly, counting bytecodes, method calls and so on can be misleading.
The only way to be sure that you are generating "optimal" Java source code would be to compile it and benchmark it on your target platform. Even then, there's a good chance that your efforts at source-code level optimization will be negated ... by JIT compiler changes.
This is not a hotspot issue. There may need to be additional byte codes to load and store the local variables, but let the compiler worry about optimizing that.
You should concentrate on issues like null pointer checking in your generated code and how to report errors in a meaningful way that is tied to the source input that you are code generating from.
I know why the following code doesn't compile:
public class Main {
public static void main(String args[]) {
main((null)); // this is fine!
(main(null)); // this is NOT!
}
}
What I'm wondering is why my compiler (javac 1.6.0_17, Windows version) is complaining "The left hand side of an assignment must be a variable".
I'd expect something like "Don't put parentheses around a method invokation, dummy!", instead.
So why is the compiler making a totally unhelpful complaint about something that is blatantly irrelevant?
Is this the result of an ambiguity in the grammar? A bug in the compiler?
If it's the former, could you design a language such that a compiler would never be so off-base about a syntax error like this?
Okay, I just checked and apparently this complaint is only seen from within Eclipse. If I compile from the command line, it gives the more sensible "Not a statement" error. The mystery deepens.
Your version must be wonky. :-P When tested on OpenJDK (as distributed with Ubuntu 9.10), this is what I get:
ParensTest.java:4: not a statement
(main(null));
^
1 error
Update based on OP's edit: Eclipse uses its own Java compiler, called ecj; it does not use the JDK compiler (javac). That is why you get different output sometimes. (And yes, the bytecode generated is sometimes different too, causing funky differences in behaviour depending on whether you compiled your code in Eclipse.)
(As an aside, another difference between ecj and javac in my experience: javac will tell you to get lost if you have a string constant over 65535 bytes long (this is a limitation in the class file format). ecj will actually try to emulate such a long string constant, by piecing together shorter parts, each fitting within the 64k limit, with a StringBuilder, then finally interning the result---just as would happen with a "real" string constant.)
Java compiler messages are generally very unhelpful. They only really make sense to compiler writers.
From a parser perspective, it gets an expression and gets to the point where the only legal thing left to do is assign it to a variable, and there isn't one, so it gives up.
Could you design more helpful compiler messages? I suppose, but I doubt Sun/Oracle would regard that as a high priority.