Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Bytecode Instrumentation Revealed Session 3256 Joseph Coha Enterprise Java Lab Hewlett Packard Company © 2004 Hewlett-Packard Development Company, L.P. The information contained herein is subject to change without notice Learning Goals Understand bytecode instrumentation (BCI) Use BCI as a tool to answer questions about your application’s performance © Hewlett Packard Co., 2004 Agenda What is bytecode instrumentation? Class file format What’s hard about implementation? Examples of how it’s done Transformations Selecting methods to instrument Collecting the data Experience Summary © Hewlett Packard Co., 2004 Bytecode Instrumentation Modification of the class file content Based on early object code modification work Applied to Java™ as bytecode manipulation – Support for optimization, generics, AOP, … – JVM™ hooks • -Xprep, preprocessor as a property – Special class loader hooks Java Virtual Machine Tools Interface (JVMTI) – Includes callback mechanism for class loading – Enables bytecode instrumentation – JVMTI (JSR 163) in J2SE 5.0 © Hewlett Packard Co., 2004 Publicly Available BCI Tools ASM: ObjectWeb Consortium – __asm__ BCEL: Apache – Bytecode Engineering Library BIT: University of Colorado – Bytecode Instrumenting Tool Javassist: JBoss – Java Programming Assistant java_crw_demo: J2SE 5.0 JVMTI class load jclasslib: JProfiler – ej-technologies JikesBT: IBM – Jikes Bytecode Toolkit JOIE: Duke University Others … © Hewlett Packard Co., 2004 Products Using BCI Borland – Optimizeit ServerTrace Borland – Optimizeit Profiler HP – OpenView Transaction Analyzer (OVTA) Wily Technology – Introscope AdventNet – JMX + BCI Eclipse – JUnit – Profiler AOP: AspectJ, AspectWerkz Most Java profilers: JProbe, JProfiler, … © Hewlett Packard Co., 2004 Java Class File Constant Pool Header Constant Pool Access Flags, this, super Implemented Interfaces Fields Methods Class Attributes cp_info { u1 tag; u1 info[]; } CONSTANT_Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } CONSTANT_NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; } CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; } © Hewlett Packard Co., 2004 Java Class File Constant Pool Constant Type Size (bytes) Class 3 Fieldref 5 Methodref 5 InterfaceMethodref 5 String 3 Integer 5 Float 5 Long 9 Double 9 NameAndType 5 Utf8 u1 tag; u2 length; u1 bytes[length]; © Hewlett Packard Co., 2004 Java Class File – Methods Header Constant Pool Access Flags, this, super Implemented Interfaces Fields Methods Class Attributes method_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count]; } code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; u2 max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; } exception_table[exception_table_length]; u2 attributes_count; attribute_info attributes[attributes_count]; } © Hewlett Packard Co., 2004 Bytecode Instructions Interesting instructions and their side-effects Control flow – goto, jsr, ret, if*, *cmp*, athrow – Table jumping: lookupswitch, tableswitch • Challenging because of the jump table representation – Targets are indices into the array of bytecodes Method invocation – Method call: invokestatic, invokevirtual, invokespecial, invokeinterface – Method return: return, {I,l,f,d,a}return Stack operations and loads/stores – Push, pop, dup, load, *load, *store, … – max_stack must be updated with control flow information after traversal of the basic blocks © Hewlett Packard Co., 2004 Bytecode Instructions Interesting instructions and their side-effects Field access – get/put field and static Arithmetic operations – Impact the stack size Type conversions and checks – checkcast, typecast, instanceof Object allocation – new – Arrays: newarray, anewarray, multianewarray © Hewlett Packard Co., 2004 BCI Transformations When – Ahead-of-time / static – At run-time / dynamic • Load time • Arbitrary time Requires class loader interaction (pre 5.0) RedefineClasses() in 5.0 Scope – Whole program – Selective • Class • Method Operations – Replacement – Insertion – Deletion © Hewlett Packard Co., 2004 Parsing the Class File Goal: Rapid parsing and low memory usage Methods: – Ad hoc – Intermediate representation (IR) • Abstraction of class file elements • All elements as objects: BCEL Fly weight constants for immutables (stack ops) • Lightweight alternatives Visitor pattern for simple transformations: ASM Must provide good public interface for chosen audiences – BCEL targets bytecode experts – Javassist targets Java programmers © Hewlett Packard Co., 2004 BCEL UML Overview JavaClass and Code details From Dahm, et. al. © Hewlett Packard Co., 2004 Agenda What is bytecode instrumentation? Class file format What’s hard about implementation? Examples of how it’s done Transformations Selecting methods to instrument Collecting the data Experience Summary © Hewlett Packard Co., 2004 What’s Hard? Creating an intermediate form – Deserialization • All objects as intermediate representation • Less costly alternatives – bookeeping overhead – Size of intermediate representation Applying multiple transformations – May require update to abstract representation with each change • Look for rewind() methods Keeping the class file verifiable – Consistency – Size © Hewlett Packard Co., 2004 What’s Hard? Class Pool size bloat – Only adding items to the Class Pool – “Dead entry” elimination requires whole class analysis Method size bloat – Multiple return points Exception unwinding through frames – Keeping entry/exit data consistent Instrumenting classes early – BCI in Java Making BCI work – Debugging BCI written in C © Hewlett Packard Co., 2004 What’s Hard? Making BCI fast – Required for adaptive profiling systems Inserting correct instrumentation – Correctness – Verification – Consistency: max stack, max locals, sizes, … Thread safety – Race conditions – Deadlocks “Stale” frames when re-instrumenting © Hewlett Packard Co., 2004 Creating Instrumentation Hooks (pre-5.0) Experience with BCEL and class loaders [McPhail] Custom class loader – Finds, instruments, and loads class before system class loader – System classes (java.* and javax.*) still loaded by the system class loader – Type problem with classes loaded by both class loaders – ClassCastException © Hewlett Packard Co., 2004 Creating Instrumentation Hooks (pre-5.0) Hidden classpath – Follows delegation model for class loading – Requires the classes be found through some mechanism other than the classpath – Does not work if software expects to find classes or resources in the classpath – Remedy by creating class loader with parent set to getClass().getClassLoader() instead of the system class loader © Hewlett Packard Co., 2004 Agenda What is bytecode instrumentation? Class file format What’s hard about implementation? Examples of how it’s done Transformations Selecting methods to instrument Collecting the data Experience Summary © Hewlett Packard Co., 2004 BCI Instrumentation Traversal of elements Filter that selects instrumentation site Generator inserts transformation © Hewlett Packard Co., 2004 Approaches for Method Instrumentation Rename – Entry point renamed Wrap – Original method’s name • Add instrumentation • Call original target method Insert – Directly modify the method/class Mixin – Add field, interface, method to class – Add prefix/suffix to method(s) © Hewlett Packard Co., 2004 JRat (BCEL-based) jrat.sourceforge.net public class MyMath { public int max(int a, int b) { return (a > b) ? a : b; } } public class MyMath { static final MethodHandler HANDLER_FOR_max_0 = HandlerFactory.getMethodHandler( "org.package.MyMath", "max", "(II)I"); private final int max__shiftone_JRat (int a, int b) { return (a > b) ? a : b; } Wrapping for collection of timing information public int max (int a, int b) { long start = 0L; Object args[] = null; boolean success = false; try { HANDLER_FOR_max_0.onMethodStart(this, args); start = System.currentTimeMillis(); int result = max__shiftone_JRat(a,b); success = true; return result; } catch (Throwable t) { HANDLER_FOR_max_0.onMethodError(this, args, t); throw t; } finally { HANDLER_FOR_max_0.onMethodFinish(this, args, null, System.currentTimeMillis() - start, success); } } } © Hewlett Packard Co., 2004 java_crw_demo BCI Library C library in 5.0 JRE used by HPROF and other JVMTI agents BCI support: [O’Hair] – Class initialization • Entry to the java.lang.Object init method (signature "()V") • Inject invokestatic call to tclass.obj_init_method(object) – Method instrumentation • Entry Inject invokestatic call to tclass.call_method(class_num,method_num) Map the class_num and method_num using the crw library • Return (each site) Inject invokestatic call to tclass.return_method(class_num,method_num) – newarray type opcode • Duplicate array object on the stack • Inject invokestatic call to tclass.newarray_method(object) © Hewlett Packard Co., 2004 java_crw_demo BCI Library Non-instrumented methods – init methods – finalize methods whose length is 1 – "system" classes clinit methods – java.lang.Thread.currentThread() Modifications – No methods or fields added to any class – Only add new constant pool entries at end of original constant pool table – Exception, line, and local variable tables for each method adjusted – Bytecode optimization to use • • Smaller offsets Fewest 'wide' opcodes Goals – Minimize number of bytecodes at each injection site • Classes with N return opcodes or N newarray opcodes will get N injections – Input arguments to java_crw_demo determine injections made © Hewlett Packard Co., 2004 java_crw_demo Example: Constant Pool Addition fillin_cpool_entry – Write the information as a constant pool entry add_new_cpool_entry – Call to fillin_cpool_entry add_new_method_cpool_entry – Call to add UTF8 name to constant pool – Call to add UTF8 descr index to constant pool – Call to add name type to constant pool – Call to add method type to constant pool cpool_setup (index 0 not in pool) – add_new_method_cpool_entry inject_class – cpool_setup © Hewlett Packard Co., 2004 Add the runtime tracking method to the Constant Pool static CrwCpoolIndex add_new_method_cpool_entry(CrwClassImage *ci, CrwCpoolIndex class_index, const char *name, const char *descr) { CrwCpoolIndex name_index, descr_index, name_type_index; name_index = add_new_cpool_entry(ci, JVM_CONSTANT_Utf8, len, 0, name, len); descr_index = add_new_cpool_entry(ci, JVM_CONSTANT_Utf8, len, 0, descr, len); name_type_index = add_new_cpool_entry(ci, JVM_CONSTANT_NameAndType, name_index, descr_index, NULL, 0); return add_new_cpool_entry(ci, JVM_CONSTANT_Methodref, class_index, name_type_index, NULL, 0); © Hewlett Packard Co., 2004 java_crw_demo Example: Injection at Method Entry injection_template – Insertion of the actual bytecodes entry_injection_code - create injection code at entry to a method – injection_template method_inject_and_write_code – entry_injection_code – Write bytecode image method_write_bytecodes – method_inject_and_write_code – Adjust all offsets: • • • • • Code length Maximum stack Exception table Code attributes Attribute length © Hewlett Packard Co., 2004 Generating the bytecodes static ByteOffset injection_template(MethodImage *mi, ByteCode *bytecodes, ByteOffset max_nbytes, CrwCpoolIndex method_index) { max_stack = mi->max_stack + 2; nbytes += push_pool_constant_bytecodes( bytecodes+nbytes, ci->class_number_index); nbytes += push_short_constant_bytecodes( bytecodes+nbytes, mi->number); bytecodes[nbytes++] = (ByteCode)opc_invokestatic; bytecodes[nbytes++] = (ByteCode)(method_index >> 8); bytecodes[nbytes++] = (ByteCode)method_index; bytecodes[nbytes] = 0; /* Check max stack value */ if ( max_stack > mi->new_max_stack ) { mi->new_max_stack = max_stack; } © Hewlett Packard Co., 2004 Using java_crw_demo(): 19 Parameters 1. 2. 3. 4. 5. 6. 7. 8. 9. Caller assigned class number for class Internal class name – Example: java/lang/Object (use “/” separator) Pointer to class file image for the class Length of the class file in bytes Set to 1 if this is a system class – Prevents injections into empty <clinit>, finalize, and <init> methods Class that has methods to call at the injection sites (tclass) Signature of tclass – Format: "L" + tclass_name + ";" Method name in tclass to call at offset 0 for every method Signature of this method – Format: "(II)V" © Hewlett Packard Co., 2004 Using java_crw_demo 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. Method name in tclass to call at all return opcodes in every method Signature of the method – Format: "(II)V" Method name in tclass to call when injecting java.lang.Object.<init> Signature of the method – Format: "(Ljava/lang/Object;)V" Method name in tclass to call after every newarray opcode in every method Signature of the method – Format: "(Ljava/lang/Object;II)V" Returns a pointer to new class file image Returns the length of the new image Pointer to function to call on any fatal error – NULL sends error to stderr Pointer to function that gets called with all details on methods in the class – NULL means skip this call © Hewlett Packard Co., 2004 java_crw_demo parameters JNIEXPORT void JNICALL java_crw_demo( unsigned class_number, const char *name, const unsigned char *file_image, long file_len, int system_class, char* tclass_name, char* tclass_sig, char* call_name, char* call_sig, char* return_name, char* return_sig, char* obj_init_name, char* obj_init_sig, char* newarray_name, char* newarray_sig, unsigned char **pnew_file_image, long *pnew_file_len, FatalErrorHandler fatal_error_handler, MethodNumberRegister mnum_callback ); © Hewlett Packard Co., 2004 Start-up Using JVMTI Native Interface Start-up – -agentlib:<agent-lib-name>=<options> – Agent_OnLoad() called when library loaded • Set-up the callbacks jvmtiEventCallbacks callbacks; Callbacks.ClassFileLoadHook = &cbClassFileLoadHook; • Load the java_crw_demo native BCI library Application running – When class loaded (or reloaded): • Callback made to cbClassFileLoadHook() Generate unique class identification number Instrument bytecode » Supply Java method(s) to call from instrumentation Return modified class file © Hewlett Packard Co., 2004 Class file load callback static void JNICALL cbClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv* env, jclass class_being_redefined, jobject loader, const char* name, jobject protection_domain, jint class_data_len, const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data){ if ( gdata->bci_counter == 0 ) { class_prime_system_classes(); } gdata->bci_counter++; Generating the class index ClassIndex cnum; loader_index = loader_find_or_create(env,loader); if ( class_being_redefined != NULL ) { cnum = class_find_or_create(signature, loader_index); } else { cnum = class_create(signature, loader_index); } © Hewlett Packard Co., 2004 Call BCI library to instrument ((JavaCrwDemo)(gdata->java_crw_demo_function))( cnum, name, class_data, class_data_len, system_class, Class with method "sun/tools/hprof/Tracker", "Lsun/tools/hprof/Tracker;", Method to call "CallSite", "(II)V", NULL, NULL, NULL, NULL, NULL, NULL, &new_image, &new_length, &my_crw_fatal_error_handler, &class_set_methods); © Hewlett Packard Co., 2004 Return the new class file if ( new_length > 0 ) { unsigned char *jvmti_space; jvmti_space = (unsigned char *) jvmtiAllocate((jint)new_length); (void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length); *new_class_data_len = (jint)new_length; *new_class_data = jvmti_space; } else … © Hewlett Packard Co., 2004 Agenda What is bytecode instrumentation? Class file format What’s hard about implementation? Examples of how it’s done Transformations Selecting methods to instrument Collecting the data Experience Summary © Hewlett Packard Co., 2004 Method Selection Constraints BCI library determines constraints – Avoid circular dependencies with Java library Load-time instrumentation problem – JVMPI – Java-based BCI • No instrumentation of BCI classes – Non-issue with ahead-of-time instrumentation Dynamic instrumentation adds significant flexibility – Allows class redefinition after first use © Hewlett Packard Co., 2004 Method Selection Functional Goals Depends on technical demands of environment Transaction measurement tool – Instrument top-level J2EE classes Development-time tool – Instrument user-level code • Filters to select classes/methods Application server Third party classes AOP tool – Method selection for function • Special logging • Special debug support © Hewlett Packard Co., 2004 Method Selection Performance Goals Overall goal: Minimal performance impact – Runtime overhead • BCI injection • Modified control flow • BCI data collection © Hewlett Packard Co., 2004 Method Selection Performance Solutions Optimize injected code aggressively Filtering opportunities to minimize overhead – Accessor methods – Small methods – Third party code – Well-understood, application-specific code Make most expensive instrumentation conditional – Sample application performance – Turn on data collection selectively © Hewlett Packard Co., 2004 Method Selection New Opportunities JVMTI allows staged instrumentation Make conservative decisions initially Remove or add instrumentation as data is collected and application understood Adaptive opportunities – Efficient profiling – Targeted optimizations – Find and fix bugs © Hewlett Packard Co., 2004 Agenda What is bytecode instrumentation? Class file format What’s hard about implementation? Examples of how it’s done Transformations Selecting methods to instrument Collecting the data Experience Summary © Hewlett Packard Co., 2004 Approaches for Data Collection C heap data structures – Requires call to native code from Java Java heap – Measurement data structures interfere with program Files – I/O can be slow, even with buffering Pipes Sockets/Network RMI, RMI/SSL JMX © Hewlett Packard Co., 2004 Efficient Collection Minimize method calls – Finding class and method names – Thread information – Native calls – Cross language calls Keep critical sections short Use thread local storage to avoid contention – Global data structures need locks © Hewlett Packard Co., 2004 Efficient Collection Persist data that will no longer be modified – Data from thread that has exited can be written to file Long term collection – Minimize total amount of data collected • Toggle on/off • Sample • Filter © Hewlett Packard Co., 2004 Agenda What is bytecode instrumentation? Class file format What’s hard about implementation? Examples of how it’s done Transformations Selecting methods to instrument Collecting the data Experience Summary © Hewlett Packard Co., 2004 Demo BCI in action Using J2SE 5.0 java.lang.instrument 49 © Hewlett Packard Co., 2004 java.lang.instrument © Hewlett Packard Co., 2004 Start-up java.lang.instrument Support for Agents (J2SE 5.0) – -javaagent:jarpath[=options] – jarfile meta information specifies method to call • Premain-Class:<class-name> • Boot-Class-Path:<boot-class-pathappend> • Can-Redefine-Classes:<true|false> © Hewlett Packard Co., 2004 Start-up java.lang.instrument Support for Agents – Method premain() • public static void premain(String agentArgs, Instrumentation inst); • premain() called before application’s main() Interfaces – ClassFileTransformer – Instrumentation • Services needed to instrument Classes – ClassDefinition • Parameter to Instrumentation.redefineClasses() method © Hewlett Packard Co., 2004 BCEL [Dahm, et. al.] © Hewlett Packard Co., 2004 Interface ClassFileTransformer byte[] transform( ClassLoader loader, // null if system String className, // java/util/List Class<?> classBeingRedefined, // null if not ProtectionDomain protectionDomain, byte[] classfileBuffer) // input class file throws IllegalClassFormatException Returns null if no modifications made New class definition: ClassLoader.defineClass Redefinition: Instrumentation.redefineClasses © Hewlett Packard Co., 2004 Interface Instrumentation void addTransformer( ClassFileTransformer transformer) boolean removeTransformer( ClassFileTransformer transformer) void redefineClasses( ClassDefinition[] definitions) throws ClassNotFoundException,UnmodifiableClass Exception Class[] getAllLoadedClasses() … © Hewlett Packard Co., 2004 Dynamic BCI Start-up Start java with option: -javaagent:Sample.jar On start-up, Java runtime calls “PremainClass” Save object that implements Instrumentation Add the transformer – Called for every class loaded – inst.addTransformer(myTrans); © Hewlett Packard Co., 2004 MyAgent.premain() Save Instrumentation object Call addTransformer() import java.lang.instrument.*; public class MyAgent { static Instrumentation myInst; static String myArgs; static MyTransformer myTrans; public static void premain(String agentArgs, Instrumentation inst) { myInst = inst; myArgs = agentArgs; myTrans = new MyTransformer(); inst.addTransformer(myTrans); MyMonThread myMonThread = new MyMonThread(); myMonThread.start(); } © Hewlett Packard Co., 2004 Dynamic BCI Implementation ClassFileTransformer Input parameters – Classloader – Class name – Class © Hewlett Packard Co., 2004 public class MyTransformer implements ClassFileTransformer { MyTransformer.transform() public byte[] transform( java.lang.ClassLoader inLoader, java.lang.String className, java.lang.Class<?> classBeingRedefined, java.security.ProtectionDomain jspd, byte[] inba) throws IllegalClassFormatException { byte[] lba = inba; if ( className.equals(classToModify) ) { lba = mytransform(className, methodName); } return lba; } © Hewlett Packard Co., 2004 Dynamic BCI Program Example Goal: Count method entries for method consuming most time Class A1 has two methods: a1() and a2() – Collect amount of time spent in each A separate thread wakes up periodically – Switches preference for calling a1() or a2() Monitor thread launched from Agent – Periodically wakes up – Accesses performance information – Instruments the method with the highest time © Hewlett Packard Co., 2004 Dynamic BCI High call rate to a1() 1 main() 2 main() Add BCI to a1() A1.a1() A1.a2() A1.a1() A1.a2() 3 Switch high call rate to a2() a1() call counts 4 main() A1.a1() A1.a2() a1() call counts Add BCI to a2() Remove BCI from a1() main() A1.a1() A1.a2() a2() call counts © Hewlett Packard Co., 2004 a1() a2() MyMon.getHotMethod values: 790 191 MyMon.printCallNumbers: 0 0 Add instrumentation to: a1 Time in a1() higher Instrument a1() MyMon.printCallNumbers: 236 0 MyMon.getHotMethod values: 3666 1081 MyMon.printCallNumbers: 468 0 MyMon.getHotMethod values: MyMon.printCallNumbers: 842 200 791 210 200 822 935 0 MyMon.getHotMethod values: MyMon.printCallNumbers: 200 706 0 MyMon.getHotMethod values: MyMon.printCallNumbers: 801 992 0 MyMon.getHotMethod values: Add instrumentation to: a2 MyMon.printCallNumbers: 993 232 MyMon.getHotMethod values: MyMon.printCallNumbers: 230 772 200 861 190 812 781 220 993 941 MyMon.getHotMethod values: MyMon.printCallNumbers: 830 993 707 MyMon.getHotMethod values: MyMon.printCallNumbers: 191 993 462 MyMon.getHotMethod values: MyMon.printCallNumbers: Time in a2() higher Instrument a2() 993 999 MyMon.getHotMethod values: Time in a1() higher Instrument a1() Add instrumentation to: a1 © Hewlett Packard Co., 2004 a1() a2() MyAgent.premain(): Enter MyAgent.premain(): Exit MyMonThread: Starting thread. No counting MyMon.printCallNumbers: 0 0 Add instrumentation to: a1 MyMon.printCallNumbers: 435 0 Counting a1() calls MyMon.printCallNumbers: 861 0 MyMon.printCallNumbers: 1295 0 MyMon.printCallNumbers: 1722 0 MyMon.printCallNumbers: 1829 0 Add instrumentation to: a2 MyMon.printCallNumbers: 1842 485 Counting a2() calls MyMon.printCallNumbers: 1842 911 MyMon.printCallNumbers: 1842 1356 MyMon.printCallNumbers: 1842 1783 MyMon.printCallNumbers: 1842 1891 Add instrumentation to: a1 MyMon.printCallNumbers: 2270 1902 © Hewlett Packard Co., 2004 Dynamic BCI Thread Wake-up and Check Monitoring thread periodically wakes up and calls: – MyAgent.update() • Select hot class-method to instrument • MyTransformer.mytransform() Add method we want to call to the Constant Pool MyTransformer.traceMethod() » Modify the bytecode of the hot method » Update the max stack value Reset the Constant Pool Create new class file • inst.redefineClasses(class, bytecodes) © Hewlett Packard Co., 2004 MyAgent.update() – page 1 Find class and method public static void update() { Class[] loadedClass = null; Instrumentation inst = MyAgent.getMyInst(); loadedClass = inst.getAllLoadedClasses(); Class classOfInterest = null; ClassAndMethod hotClassAndMethod = MyMon.getHotClassAndMethod(); String classToInstrument = hotClassAndMethod.getMyClass(); String classToFind = new String("class " + classToInstrument); // Find classToFind in loadedClass[] classOfInterest = loadedClass[i]; String methodToInstrument = hotClassAndMethod.getMyMethod(); byte[] newClass = MyTransformer.mytransform( classToInstrument, methodToInstrument); © Hewlett Packard Co., 2004 Dynamic BCI Add Method - Constant Pool Monitoring thread periodically wakes up and calls: – MyAgent.update() • Select hot class-method to instrument • MyTransformer.mytransform() Add method we want to call to the Constant Pool MyTransformer.traceMethod() » Modify the bytecode of the hot method » Update the max stack value Reset the Constant Pool Create new class file • inst.redefineClasses(class, bytecodes) © Hewlett Packard Co., 2004 MyTransformer.mytransform() public public static byte[] mytransform(String classToInst, String methodToInst) { try { JavaClass java_class = Repository.lookupClass(classToInst); // Add method to CP we will call from the instrumented method ConstantPool constants = java_class.getConstantPool(); cp = new ConstantPoolGen(constants); monitoringMethodToCall = cp.addMethodref("MyMon", "countMethodEntry", "(II)V"); // Select the method to instrument and find the index Method[] methods = java_class.getMethods(); methods[j] = traceMethod(methods[j], methodIndex); // Set the constant pool java_class.setConstantPool(cp.getFinalConstantPool()); } catch( Exception e) { e.printStackTrace();} return java_class.getBytes(); } © Hewlett Packard Co., 2004 Dynamic BCI Modify the Selected Method Monitoring thread periodically wakes up and calls: – MyAgent.update() • Select hot class-method to instrument • MyTransformer.mytransform() Add method we want to call to the Constant Pool MyTransformer.traceMethod() » Modify the bytecode of the hot method » Update the max stack value Reset the Constant Pool Create new class file • inst.redefineClasses(class, bytecodes) © Hewlett Packard Co., 2004 Create the Instruction List private static Method traceMethod(Method m, int methodIndex) { Code code = m.getCode(); int flags = m.getAccessFlags(); String name = m.getName(); Create bytecode instructions // Create instruction list to be inserted at method start. InstructionList patch = new InstructionList(); patch.append(new PUSH(cp, 0)); patch.append(new PUSH(cp, methodIndex)); patch.append(new INVOKESTATIC(monitoringMethodToCall)); // Get the bytecode MethodGen InstructionList InstructionHandle[] instructions for the method mg = new MethodGen(m, class_name, cp); il = mg.getInstructionList(); ihs = il.getInstructionHandles(); © Hewlett Packard Co., 2004 Insert Bytecodes Update Stack // First let the super or other constructor be called if(name.equals("")) { for(int j=1; j < ihs.length; j++) { if(ihs[j].getInstruction() instanceof INVOKESPECIAL) { il.append(ihs[j], patch); break; } } } Insert bytecode instructions else { il.insert(ihs[0], patch); // Insert the instructions!! } // Update stack size if(code.getMaxStack() < 2) { mg.setMaxStack(2); } Update stack size return mg.getMethod(); } © Hewlett Packard Co., 2004 Dynamic BCI Reset CP / Create Class File Monitoring thread periodically wakes up and calls: – MyAgent.update() • Select hot class-method to instrument • MyTransformer.mytransform() Add method we want to call to the Constant Pool MyTransformer.traceMethod() » Modify the bytecode of the hot method » Update the max stack value Reset the Constant Pool Create new class file • inst.redefineClasses(class, bytecodes) © Hewlett Packard Co., 2004 MyTransformer.mytransform() public public static byte[] mytransform(String classToInst, String methodToInst) { try { JavaClass java_class = Repository.lookupClass(classToInst); // Add method to CP we will call from the instrumented method ConstantPool constants = java_class.getConstantPool(); cp = new ConstantPoolGen(constants); monitoringMethodToCall = cp.addMethodref("MyMon", "countMethodEntry", "(II)V"); // Select the method to instrument and find the index Method[] methods = java_class.getMethods(); methods[j] = traceMethod(methods[j], methodIndex); Update the constant pool // Set the constant pool java_class.setConstantPool(cp.getFinalConstantPool()); } catch( Exception e) { e.printStackTrace();} return java_class.getBytes(); } © Hewlett Packard Co., 2004 Dynamic BCI Reset CP / Create Class File Monitoring thread periodically wakes up and calls: – MyAgent.update() • Select hot class-method to instrument • MyTransformer.mytransform() Add method we want to call to the Constant Pool MyTransformer.traceMethod() » Modify the bytecode of the hot method » Update the max stack value Reset the Constant Pool Create new class file • inst.redefineClasses(class, bytecodes) © Hewlett Packard Co., 2004 MyAgent.update() – page 2 Redefine class byte[] newClass = MyTransformer.mytransform( classToInstrument, methodToInstrument); ClassDefinition cd = new ClassDefinition(classOfInterest, newClass); ClassDefinition cda [] = new ClassDefinition[1]; cda[0] = cd; try { inst.redefineClasses(cda); } catch ( ClassNotFoundException cnfe ) { } catch ( UnmodifiableClassException uce ) { } } © Hewlett Packard Co., 2004 Dynamic BCI High call rate to a1() 1 main() 2 main() Add BCI to a1() A1.a1() A1.a2() A1.a1() A1.a2() 3 Switch high call rate to a2() a1() call counts 4 main() A1.a1() A1.a2() a1() call counts Add BCI to a2() Remove BCI from a1() main() A1.a1() A1.a2() a2() call counts © Hewlett Packard Co., 2004 Monitoring using MBeans import javax.management.*; import java.lang.management.*; class MethodInfoMBeanCreator { public static void createMBean(String className, String methodName, int classNum, int methodNum ) { // Register the MBean MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); ObjectName name = new ObjectName("com.hp.perf:type=MethodInfo_" + className + "_" + methodName); MethodInfo mI = new MethodInfo(classNum, methodNum); mbs.registerMBean(mI, name); } } © Hewlett Packard Co., 2004 Monitoring using MBeans public class MethodInfo implements MethodInfoMBean { private int myClassNum; private int myMethodNum; public MethodInfo(inClassNum, int inMethodNum) { myClassNum = inClassNum; myMethodNum = inMethodNum; } public long getTime() { return MyMon.getTime(inClassNum, myMethodNum); } public long getCallCount() { return MyMon.getCallCount(inClassNum, myMethodNum); } } © Hewlett Packard Co., 2004 a1() a2() MyAgent.premain(): Enter MyAgent.premain(): Exit MyMonThread: Starting thread. No counting MyMon.printCallNumbers: 0 0 Add instrumentation to: a1 MyMon.printCallNumbers: 435 0 Counting a1() calls MyMon.printCallNumbers: 861 0 MyMon.printCallNumbers: 1295 0 MyMon.printCallNumbers: 1722 0 MyMon.printCallNumbers: 1829 0 Add instrumentation to: a2 MyMon.printCallNumbers: 1842 485 Counting a2() calls MyMon.printCallNumbers: 1842 911 MyMon.printCallNumbers: 1842 1356 MyMon.printCallNumbers: 1842 1783 MyMon.printCallNumbers: 1842 1891 Add instrumentation to: a1 MyMon.printCallNumbers: 2270 1902 © Hewlett Packard Co., 2004 A1.a1() Call Count Call Count increasing Time high Time A1.a2() Call Count Time © Hewlett Packard Co., 2004 A1.a1() Call Count Time A1.a2() Call Count Call Count increasing Times high Time © Hewlett Packard Co., 2004 A1.a1() Call Count Time A1.a2() Call Count Time © Hewlett Packard Co., 2004 A1.a1() Call Count Time A1.a2() Call Count Time © Hewlett Packard Co., 2004 Analyzing your changes Use the BCEL dump() method for JavaClass – Writes a class file to disk try { java_class.dump(java_class.getClassName() + "_0.class"); } catch (java.io.IOException jiio) { System.out.println("IO Except at dump"); } © Hewlett Packard Co., 2004 Analyzing your changes Use javap to analyze the file created public void a1(); Code: 0: iconst_0 1: iconst_0 2: invokestatic #37; //Method MyMon.countMethodEntry:(II)V 5: ldc #5; //int 1000000 7: istore_1 … 36: return public void a2(); Code: 0: ldc #5; //int 1000000 2: istore_1 … © Hewlett Packard Co., 2004 Bytecode sequence writing It’s easy when you use: java –jar bcel-5.1.jar org.apache.bcel.util.BCELifier A1_mod.class private void createMethod_1() { InstructionList il = new InstructionList(); MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] { }, "a1", "A1", il, _cp); InstructionHandle ih_0 = il.append(new PUSH(_cp, 0)); il.append(new PUSH(_cp, 0)); il.append(_factory.createInvoke("MyMon", "countMethodEntry", Type.VOID, newType[] { Type.INT, Type.INT }, Constants.INVOKESTATIC)); © Hewlett Packard Co., 2004 Agenda What is bytecode instrumentation? Class file format What’s hard about implementation? Examples of how it’s done Transformations Selecting methods to instrument Collecting the data Experience Summary © Hewlett Packard Co., 2004 Summary BCI is powerful BCI is accessible to everyone © Hewlett Packard Co., 2004 References Alan Bateman and David Seidman – Much thanks for advice and contributions to this presentation. Geoff A. Cohen and Jeffrey S. Chase. An architecture for safe bytecode insertion. In Software – Practice and Experience, volume 34, pages 1-12, John Wiley & Sons, 2001. Eric Burneton, Romain Lenglet, Thierry Coupaye. ASM: a code manipulation tool to implement adaptable systems. Adaptable and Extensible Component Systems, November, 2002. Java 5.0 crw demo. /opt/java1.5/demo/jvmti/src/share/demo/jvmti/java_crw_demo/index.html. John Meyer and Troy Downing. Java Virtual Machine, O’Reilly, 1997. Tim Lindholm and Frank Yellin. The Java Virtual Machine Specification, Second Edition, Addison-Wesley, 1999. JRat. http://sourceforge.net. Misha Dmitriev. Jfluid. http://research.sun.com/projects/jfluid. Michael McPhail. org.jmonde.debug.Trace. http://www.jmonde.org/Trace. JVMTI Reference Manual. http://java.sun.com/j2se/1.5/docs/guide/jvmti. Shigeru Chiba. javassist. http://www.jboss.org/developers/projects/javassist.html. Markus Dahm, Conor MacNeill, Costin Manolache, Jason van Zyl, David Dixon-Peugh, and Enver Haase. Bytecode Engineering Library. http://jakarta.apache.org/bcel. Kelly O’Hair. java_crw_demo BCI implementation in J2SE 5.0. http://java.sun.com/developer/technicalArticles/Programming/jvmpitransition. Douglas J Brear, Thibaut Weise, Tim Wiffen, Kwok Cheung Yeung, Sarah A M Bennett and Paul H J Kelly. Search strategies for Java bottleneck location by dynamic instrumentation. UK Performance Engineering Workshop, Warwick, UK, 2003. © Hewlett Packard Co., 2004 Questions? Bytecode Instrumentation Revealed © 2004 Hewlett-Packard Development Company, L.P. The information contained herein is subject to change without notice Thank You Session 3256 Bytecode Instrumentation Revealed Please fill out the speaker evaluation You can contact me further at … [email protected] © Hewlett Packard Co., 2004