5 ms·
Nitpicking here. > JIT compiler can see that a function has never been passed a null object It cannot. It can only see that function has never been passed a n
by hbrn 4y ago
Nitpicking here.
> JIT compiler can see that a function has never been passed a null object
It cannot. It can only see that function has never been passed a null object so far.
And the cost of such optimization might be that edge cases are way slower than anticipated. But what if those edge cases are actually the only thing that provide value for your business?
Imagine you're building a monitoring system that alerts very rarely, but reaction time is really critical for you. Do you really want to JIT compiler to optimize the alerting branch out because it hasn't seen any alerts yet?
My bet is that JIT compiler rarely does those optimizations by default, because it cannot know which branches in your code contain business value. I don't need my code to be twice as fast on average but twice as slow on critical branches.
Now, what would be great if profiler would make suggestions about how to modify your code for performance based on usage. But those should be approved and commented by humans, because humans know whether those are valuable optimizations or a fad.
- vips7L 4y ago> so far This is truly a nit pick. > Imagine you're building a monitoring system that alerts very rarely, but reaction time is really critical for you. Do you really want to JIT compiler to optimize the alerting branch out because it hasn't seen any alerts yet? Yes I do, because once the constraints are invalidated the the runtime system will instruct the JIT to recompile the code with the now uncommon branch [0]. [0] https://shipilev.net/jvm/anatomy-quarks/29-uncommon-traps/ https://shipilev.net/jvm/anatomy-quarks/29-uncommon-traps/
- hbrn 4y agoWe're talking about optimizations that JIT can do compared to AOT. The link you shared talks about skipping compilation for certain branches to speed up the JIT compilation. Such optimization makes startup faster, but it doesn't make code execution faster. AOT compiled languages don't have slow startup problem in the first place. It's like saying paper books are worse than e-ink readers because you cannot charge paper books.
- kaba0 4y agoEliding a branch makes not only compilation faster, but the resulting code as well. That’s how for example some logging statements become zero-cost when the debug level is set lower than their corresponding one. JIT compiled languages don’t care too deeply about startup, they shine with longer runtimes.
- hbrn 4y agoAre you sure you're not confusing zero-cost with almost zero-cost? Even zerolog talks about negligible costs after most aggressive optimizations, not zero: https://github.com/obsidiandynamics/zerolog https://github.com/obsidiandynamics/zerolog If you're just using constants in your code to set logging level, AOT compilation can do exactly the same optimizations.
- blackoil 4y agoAOT would require recompilation and deployment. JIT can do it for the same code with final params. When the log level is not final, branch prediction Will ensure JIT code is faster.
- garblegarble 4y ago>> JIT compiler can see that a function has never been passed a null object >>... so far. >This is truly a nit pick. It's not even a nitpick, it's just wrong - your original statement is true: you said "has never been". The "so far" reply you received mistakenly implies you said "will never be" (given that HotSpot will deoptimise+reoptimise if its assumptions are invalidated) That said, the remainder of their point I think is reasonable in the extremely specific (I think to the point of being unrealistic, given this seems like a hand-optimised assembly level of perf importance they have alluded to) scenario they mentioned - the JIT optimiser can't know that the user wants to optimise an extremely rare branch for performance to the point where the overwhelmingly common case should be degraded. Another useful jumping off point to explore for HotSpot's performance techniques is [1] 1: https://wiki.openjdk.org/display/HotSpot/PerformanceTechniques https://wiki.openjdk.org/display/HotSpot/PerformanceTechniqu...
- hbrn 4y agoCan you show me how exactly does the optimization/deoptimization of unused branch look like? You need detect that you got into an unused branch and that requires... a branch! In order to be able to optimize presumably dead branches you need a primitive that: 1. Can detect entering "dead" branches 2. Is faster than branch. I'm not saying JIT optimizations are not possible, JIT compiler can totally choose to inline function call based on frequency or loop length. It can make "better" time/space complexity decisions (though "better" is still going to be controversial). But optimizing branches because they were not called in runtime seems like common a myth. Like previous commenter who confused startup optimization with code optimization.
- kaba0 4y agoOne trick that OpenJDK uses is optimization of null checks. Since in Java memory has to be initialized, null pointers will have the value 0. If a given function using a null check gets called many times, and all these times it was called with a non-null object the JVM can compile the branch totally away. If the function is finally called with ‘null’ the compiled code will try to load the memory at address zero, causing the TLB to trigger and the OS to send a segfault. This can be handled safely by the JVM which will interpret it in accordance with the above and will deoptimize the code (with all possible side effects reverted) and either run it in interpreted mode or an optimized mode that does contain the null check “properly”.
- Karellen 4y agoHow will the runtime system know to invalidate and recompile the code, if the alert check isn't being done on every call? At some level, the check for the alert has to be done on every call. If it isn't being done, the one time there should be an alert it will be missed. If it is being done, where is it being done if not in the optimised JITted code, and how is that code even more optimised than the JITted version would be? Why not just put that optimisation in the JITted code?
- kjeetgill 4y agoThe terms you'll want to read up on are JIT speculation and deoptimisation. There's a whole range of things that can be done like trapping the null derefrence instead of an explicit check, once hot code is inlined the check could be lifted out several call frames outside of loops. Then you can ignore the check later. All sortsa stuff can happen.
- pron 4y agoJIT compilers do exactly that. Not only do they have more information, they are also allowed to -- and very frequently do -- perform speculative optimisations. If proven wrong, they incur "deoptimisations" and then recompile with more information.