Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

From bytecode to native code in hot spot jvm

249 vues

Publié le

Presentation explores the process of bytecode interpretation and compilation inside HotSpot JVM. It shows how Java Virtual Machine internally works in regards to Interpreter and Just-In-Time compiler, as well as few optimizations achieved to gain better performance. Some of the shared topics are useful for programmers passionate about doing performance and understanding how to write micro-benchmark tests. The presentation contains a demonstration that figures out optimizations occurred during Just-In-Time compilation process. JITWatch tool for visualizing the generated assembly is used.

Publié dans : Technologie
  • Soyez le premier à commenter

From bytecode to native code in hot spot jvm

  1. 1. www.luxoft.com From Bytecode to Native Code in HotSpot JVM Ionuţ Baloşin Software Architect ibalosin@luxoft.com @ionutbalosin
  2. 2. www.luxoft.com About Me  Software Architect @ www.luxoft.com  9 years of software development experience  Technical Trainer @ www.luxoft-training.com  “Java Performance and Tuning” course  “Software Architecture Methodology” course
  3. 3. www.luxoft.com Agenda  Understanding Bytecode  How to Disassemble Bytecode  Bytecode Execution Workflow  Interpreter  JIT Compiler  How to see Native Code from Bytecode  Demo  Micro-benchmarking advice
  4. 4. www.luxoft.com HotSpot Java Virtual Machine  JVM  process virtual machine for application code  built-in memory management system  provides robust and secure execution  stack-based implementation Operating System Java Virtual Machine Hardware
  5. 5. www.luxoft.com javac  Bytecode is generated using javac based on Java source code  There are about 200 bytecode instructions (opcodes) in use  each opcode is represented by a single byte → bytecode  opcodes are organized in families  Bytecode does not have direct access to any memory location  Bytecode does not contain some high-level features present in the Java Source Code  E.g. comments, for, while, etc Java Source Code ( .java ) Java Bytecode ( .class ) javac
  6. 6. www.luxoft.com javap  Disassembled code is generated using javap based on generated Bytecode  javap - Java Class File Disassembler  by default it shows public and default methods  javap -c <path_to_class>  IDE Disassemblers:  Eclipse: Bytecode Visualizer  IntelliJ IDEA: ASM Bytecode Outline javap Java Disassembled Code Java Bytecode ( .class )
  7. 7. www.luxoft.com From Source Code to Disassembled Code Java Source Code ( .java ) public int add(int a, int b) { int sum = a + b; print(sum); return sum; } javac Java Bytecode ( .class ) CA FE BA BE 00 00 00 34 00 51 07 00 02 01 00 2B 63 6F 6D 2F 6C 75 78 6F 66 74 2F 6A 70 74 2F 63 6F 75 72 73 65 2F 62 79 74 65 63 6F 64 65 2F 44 69 73 61 73 73 65 6D 62 6C 65 72 07 00 04 01 00 10 6A 61 76 61 2F 6C 61 Êþº¾...4.Q. ....+com/ luxoft/jpt/ course/ bytecode/ Disassemble r......java /la javap Java Disassembled Code public int add(int a, int b) { /* L70 */ 0 iload_1; /* a */ 1 iload_2; /* b */ 2 iadd; 3 istore_3; /* sum */ /* L71 */ 4 aload_0; /* this */ 5 iload_3; /* sum */ 6 invokevirtual 73; /* void print(int b) */ /* L72 */ 9 iload_3; /* sum */ 10 ireturn; }ClassFile { u4 magic; /* CA FE BA BE */ u2 minor_version; /* 00 00 */ u2 major_version; /* 00 34 */ u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1] ... }
  8. 8. www.luxoft.com OpCode Families LOAD & STORE OPCODES load load a value from Local Variable Array into the stack ldc load a constant from the Constant Pool into the stack store store a value into Local Variable Array and remove it from stack dup duplicate the value on top of the stack ARITHMETIC OPCODES add add two values from top of stack and store the result sub subtracts two values from top of stack and store the result div divide two values from top of stack and store the result mult multiplies two values from top of stack and store the result INVOCATION OPCODES invokeinterface calls an interface method invokespecial calls a non-overridable instance method invokevirtual calls a regular overridable instance method invokestatic calls a static method invokedynamic dynamic invocation public int add(int a, int b) { /* L70 */ 0 iload_1; /* a */ 1 iload_2; /* b */ 2 iadd; 3 istore_3; /* sum */ /* L71 */ 4 aload_0; /* this */ 5 iload_3; /* sum */ 6 invokevirtual 73; /* void print(int b) */ /* L72 */ 9 iload_3; /* sum */ 10 ireturn; }
  9. 9. www.luxoft.com Local Variable Array public int add(int a, int b) { int sum = a + b; print(sum); return sum; } public int add(int a, int b) { /* L70 */ 0 iload_1; /* a */ 1 iload_2; /* b */ 2 iadd; 3 istore_3; /* sum */ /* L71 */ 4 aload_0; /* this */ 5 iload_3; /* sum */ 6 invokevirtual 73; /* void print(int sum) */ /* L72 */ 9 iload_3; /* sum */ 10 ireturn; } Local Variable Array index
  10. 10. www.luxoft.com How Operand Stack and Local Variable Array work public int add(int a, int b) { /* ... */ 0 iload_1; /* a */ 1 iload_2; /* b */ 2 iadd; 3 istore_3; /* sum */ /* ... */ } Operand Stack 98100this Local Variable Array 100 Operand Stack iload_1; 98100this Local Variable Array 98 100 Operand Stack iload_2; 98100this Local Variable Array 198 Operand Stack iadd; 98100this Local Variable Array Operand Stack istore_3; 19898100this Local Variable Array
  11. 11. www.luxoft.com Runtime Constant Pool public int add(int a, int b) { int sum = a + b; print(sum); return sum; } public int add(int a, int b) { /* L70 */ 0 iload_1; /* a */ 1 iload_2; /* b */ 2 iadd; 3 istore_3; /* sum */ /* L71 */ 4 aload_0; /* this */ 5 iload_3; /* sum */ 6 invokevirtual 73; /* void print(int sum) */ /* L72 */ 9 iload_3; /* sum */ 10 ireturn; } Local Variable Array index Runtime Constant Pool reference
  12. 12. www.luxoft.com How Runtime Constant Pool works  Ordered set of constants used by the type  Entries have usually 2 bytes, referenced by index  Plays a central role in the dynamic linking of Java Runtime Constant Pool #1: CONSTANT_Class: name_index=2 #2: CONSTANT_Utf8: com/luxoft/jpt/course/bytecode/JavapSample #29: CONSTANT_Utf8: print #30: CONSTANT_Utf8: (I)V #73: CONSTANT_Methodref: class_index=1; name_and_type_index=74 #74: CONSTANT_NameAndType: name_index=29; descriptor_index=30 public int add(int a, int b) { /* ... */ 6 invokevirtual 73; /* void print(int sum) */ /* ... */ }
  13. 13. www.luxoft.com Exceptions handling at Bytecode level public static int remainder(int a, int b) throws DivideByZeroException { try { return a % b; } catch (ArithmeticException e) { throw new DivideByZeroException(); } } public static int remainder(int a, int b) throws com.luxoft.jpt.course.bytecode.DivideByZeroException { /* L26 */ 0 iload_0; /* a */ 1 iload_1; /* b */ 2 irem; 3 ireturn; /* L27 */ 4 astore_2; /* e */ /* L28 */ 5 new 17; 8 dup; 9 invokespecial 19; /* com.luxoft.jpt.course.bytecode.DivideByZeroException() */ 12 athrow; /* ExceptionTable */ /* ----------+--------+------------+------------------------------- */ /* start_pc | end_pc | handler_pc | catch_type */ /* ----------+--------+------------+------------------------------- */ /* 0 | 3 | 4 | java.lang.ArithmeticException */ /* ----------+--------+------------+------------------------------- */ }
  14. 14. www.luxoft.com Quizz  Spot few ambiguities based on below decompiled class: public class MyDouble implements com.luxoft.jpt.course.bytecode.MyDoubleInterface<java.lang.Integer> { /* compiled from MyDouble.java */ public MyDouble() {...} public java.lang.Integer getDouble() {...} public volatile java.lang.Object getDouble() {...} } public class MyDouble implements MyDoubleInterface<Integer> { @Override public Integer getDouble() { return Integer.valueOf(10) * 2; } }
  15. 15. www.luxoft.com Quizz  Where method access$0 comes from? public class JavapOuterClass { private void foo() { } public class MyInnerClass { public void run() { foo(); } } } public class JavapOuterClass { /* compiled from JavapOuterClass.class */ public JavapOuterClass() {...} private void foo() {...} static void access$0(com.luxoft.jpt.course.bytecode.JavapOuterClass arg0) {...} } static void access$0(com.luxoft.jpt.course.bytecode.JavapOuterClass arg0) { arg0.foo(); }
  16. 16. www.luxoft.com  Where method $0 comes from? How it could be private and static inside the Interface? Quizz public interface MyPrinter { default void print() { Runnable r = () -> { System.out.println("Hello Voxxed Bucharest"); }; r.run(); } } public interface MyPrinter { /* compiled from MyPrinter.class */ public void print() {...} private static void $0() {...} } default void print() { invokedynamic [ LambdaMetafactory.metafactory, MethodHandle(Runnable.run), MethodHandle(lambda$0) ] () } private static void lambda$0() { invokevirtual java.lang.System.out.println("Hello Voxxed Bucharest") }
  17. 17. www.luxoft.com Execution Engine  HotSpot rationales  Weak Generation Hypothesis  memory management and Garbage Collector  use runtime to take best optimization decisions  Execution Engine  Execution Engine  Interpreter  Just-In-Time Compiler Operating System Java Source Code ( .java ) Java Bytecode ( .class ) javac JVM Hardware Class Loader Execution Engine JIT Compiler Bytecode Interpreter CodeCache Method
  18. 18. www.luxoft.com HotSpot Interpreter  When the JVM first starts up, thousands of methods are called  compiling all methods can significantly affect startup time  “~90% of time is spent in ~2% of methods”  Solution: methods are not compiled first time they are called, they are interpreted  HotSpot JVM starts running in Interpreter mode  Each method have a call count, once it reaches an invocation threshold it gets compiled  hence hot spots (HotSpot JVM) JVM argument Explanations -XX:CompileThreshold Number of method invocations/branches before compiling [client 1.5k invocations; server 10k invocations]
  19. 19. www.luxoft.com HotSpot Just-In-Time Compiler  Client (-client) C1  fast code generation of acceptable quality  rock-solid and proved optimizations  doesn’t need a Profiler  compilation threshold: 1,5k invocations  Server (-server) C2  highly optimized code  many aggressive and speculative optimizations  does need a Profiler  compilation threshold: 10k invocations  Tiered Mode (-XX:+TieredCompilation) C1 + C2  Level 0 = Interpreter  Level 1-3 = C1  C1 without profiling  C1 with basic profiling  C1 with full profiling  Level 4 = C2 JVM Bytecode Compilation Intermediate Representation Optimizer Code Generator Profiler Native Code Java Source Code Bytecode Native Code javac JIT
  20. 20. www.luxoft.com Welcome to HotSpot Optimizations’ World
  21. 21. www.luxoft.com Just-In-Time Compiler optimizations  Dynamic de-virtualization  if JIT only sees 1 implementation of a virtualized method  it becomes a mono-morphic call  Dynamic de-optimization  if JIT discovers another implementation it must de- optimize and might re-optimize for second implementation  it becomes a bi-morphic call  Intrinsics  optimizations done specifically to CPU  do not inline, but inserts “best” native code  Examples: CAS, String::equals; Math::*; System::arrayCopy; Object::hashCode double getInterestRate() { return (canComputeInterestRate()) ? 0 : (3 * amount / 1200); } boolean canComputeInterestRate() { return amount != 0; } double getInterestRate_() { return (amount != 0) ? 0 : (3 * amount / 1200); } Method inlining
  22. 22. www.luxoft.com HotSpot JVM arguments JVM argument Explanations -Djava.compiler=none Disables JIT Compiler -client Activates client (C1) compilation -server Activates server (C2) compilation -XX:+TieredCompilation Activates tiered (C1+C2) compilation -Xbatch Switches from background to foreground JIT compilation task until completed. It gets more deterministic behavior -XX:+PrintCompilation Prints time spent in JIT Compiler -XX:+PrintInlining Prints what methods get inlined -XX:-CITime Prints time spent in JIT Compiler. -XX:MaxInlineSize Specifies maximum number of bytecode instructions in a method which gets inlined. It does not to look at the invocation count [default 35bytes]
  23. 23. www.luxoft.com How to see Native Code from Bytecode  HSDIS  https://wiki.openjdk.java.net/display/HotSpot/PrintAssembly JVM argument Description -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly Activates for assembly printing
  24. 24. www.luxoft.com Demo Time  Direct vs. Getter/Setter fields access members  interpreted mode  mixed compiled mode  Mono-morphic / bi-morphic / mega-morphic virtual method calls  JIT Watch
  25. 25. www.luxoft.com JITWatch - bi-morphic call
  26. 26. www.luxoft.com JITWatch - mega-morphic call
  27. 27. www.luxoft.com Micro-Benchmarking advice  Avoid measuring in Interpreter while benchmarking  Have appropriate # of warmup iterations to reach steady state  Ideally several cycles of short warm ups  Be aware of Just-In-Time Compiler optimizations  Virtual method calls optimizations  Inlining  On-Stack-Replacement
  28. 28. www.luxoft.com THANK YOU Ionuţ Baloşin Software Architect ibalosin@luxoft.com @ionutbalosin

×