4

Question: This is more for curiosity's sake than anything else. If I have a Java if/else statement, and I know that one of the branches of the 'if/else' statement will be taken significantly more often than the other branch, can the way I order the two branches provide a hint to the JIT compiler that results in better performance?

Background: In my simplistic view of computer architecture an 'if/else' statement gets translated to, among other things, a conditional jump instruction followed by the instructions that should be executed if the jump wasn't executed. Somewhere else in memory would be the the code that the jump was targeting. As I understand it, the CPU loads instructions sequentially to the extent it can (I'm sure I'm overlooking the branch predictor here), and the non-jump path has a higher chance of being loaded into the instruction cache and the CPU's instruction pipeline.

Question Restated: Can a reasoned ordering of an if/else statement's branches increase the possibility that the often-executed code immediately follows the conditional jump instruction which would render the code more friendly to both the cache and the pipeline?

Reality: I wouldn't be surprised to hear that the JIT compiler is such a complicated piece of software that after all the instruction reordering, register allocation, and other bookkeeping it does, it can't make such guarantees.

Most of my 'if/else' statements will go un-executed so I wouldn't do this everywhere. Additionally, many times I will guess wrong about which branch will be executed more frequently and end up actually hurting performance.

I'd like to think that such a simple thing as being intentional with branch ordering would not be considered premature optimization but if it is, I'll only mess with the ordering if a profiler shows me the code is slow.

Thanks!

Tim Stewart
  • 5,350
  • 2
  • 30
  • 45
  • 1
    possible duplicate: http://stackoverflow.com/questions/11514097/does-jvm-has-its-runtime-branch-prediction-if-so-is-there-a-way-in-java-code-t – Athena Jul 20 '16 at 22:16
  • 5
    That is absolutely 100% premature optimization. The JIT will take care of this stuff _for you._ It's smarter than you at these things. Trust it to do its job. – Louis Wasserman Jul 20 '16 at 22:19
  • Thanks. I'm not looking for something like GCC's __builtin_expect(). I'm wondering if the order of the branches influence the code generation predictably. – Tim Stewart Jul 20 '16 at 22:20
  • 2
    You might want to read this: [Why is it faster to process a sorted array than an unsorted array?](http://stackoverflow.com/a/11227902/5221149) – Andreas Jul 20 '16 at 23:11
  • Quite frankly, instead of "uber-optimization," I'd rather have *code clarity* **every** time. If "clear, easy-to-understand, easy-to-maintain source code" is running too slow (because of *CPU* concerns, rather than the usual I/O ...), then I'll "throw *silicon* at it" in the blink of an eye. "Chips are Cheap." Bugs are not. – Mike Robinson Jul 20 '16 at 23:41

1 Answers1

3

No.

You can't. You don't need to.

It makes some sense for a compiler, as it can translate

if (improbable) {
    doSomething();
} else {
    doSomethingElse();
}
doMoreThings();
return;

into (pseudocode)

if (improbable) goto away
doSomething()
back: doMoreThings()
return
away: doSomethingElse()
goto back

so that the more probable path is streamlined. An AOT compiler could rely on the provided information.

You don't need to. But such things does the Java JIT compiler all the time after it collects statistics. Here, javac is irrelevant as the bytecode gets executed a few times by the interpreter, which is slow, but good enough for parts executed rarely and also good enough for collecting statistics. Usually, these statistics are better than what the programmer may supply, but what matters more: They get collected for every time-relevant piece of code. It's actually more complicated, as there are C1 and C2 compilers there...

You can't. There's no standardized way of expressing this in the bytecode. Moreover, the optimizer converts the code in an internal representation and such details get lost.

premature optimization Forget it. The compiler can do much more complicated things pretty well. Some low level optimizations still make sense, but only in very extreme cases. Go for clean code and maybe some high-level optimization, if needed.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • Thank you for your answer! Do you have a good reference that I could learn more from? – Tim Stewart Jul 21 '16 at 15:19
  • 1
    @TimStewart No reference, but googling for "java jit internals" returns a lot of stuff. There are also blogs, e.g., this one by the JMH author: https://shipilev.net – maaartinus Jul 21 '16 at 16:31
  • @TimStewart Have also a look at [this article](http://stackoverflow.com/questions/38491758/java-if-statement-structure-and-instruction-pipelining/38493099#38493099) for what JIT can do. It's an easy read. – maaartinus Jul 22 '16 at 14:14
  • I'm anxious to see that article but unfortunately, clicking on that link takes me to this page. – Tim Stewart Jul 22 '16 at 20:45
  • 1
    @TimStewart Sorry, I meant https://blog.jooq.org/2016/07/19/the-java-jit-compiler-is-darn-good-in-optimization/ – maaartinus Jul 23 '16 at 04:46
  • Thanks @maaartinus! – Tim Stewart Jul 23 '16 at 19:12