Transcript 3256 Bytecode Instrumentation Revealed
Bytecode Instrumentation Revealed
Session 3256
© 2004 Hewlett-Packard Development Company, L.P. The information contained herein is subject to change without notice Joseph Coha Enterprise Java Lab Hewlett Packard Company
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
cp_info { u1 tag; u1 info[]; }
Access Flags, this, super Implemented Interfaces Fields Methods Class Attributes
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 Fieldref Methodref InterfaceMethodref String Integer 3 5
5
5 3 5 Float Long Double NameAndType Utf8 5 9 9 5 u1 tag; u2 length; u1 bytes[length]; © Hewlett Packard Co., 2004
Java Class File – Methods
Header Constant Pool
method_info { u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_count; attribute_info attributes[attributes_count] ; }
Access Flags, this, super Implemented Interfaces Fields Methods Class Attributes
code_attribute { u2 attribute_name_index; u4 attribute_length; u2 u1 max_stack { u2 ; u2 max_locals; u4 code_length; } code[code_length] u2 start_pc end_pc ; ; u2 handler_pc; u2 catch_type; ; u2 exception_table_length; 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 return (a > b) ? a : b; } (int a, int 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 { name_type_index; (CrwClassImage *ci, CrwCpoolIndex class_index, const char *name, const char *descr) CrwCpoolIndex name_index, descr_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, JVM_CONSTANT_NameAndType , descr , len); name_type_index = add_new_cpool_entry(ci, 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 bytecodes[nbytes++] = (ByteCode) method_index ; >> 8); bytecodes[nbytes] = 0; /* Check max stack value */ if ( max_stack > mi->new_max_stack ) { mi->new_max_stack = max_stack; }
© Hewlett Packard Co., 2004
1.
2.
3.
4.
5.
6.
7.
8.
9.
Using java_crw_demo(): 19 Parameters
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
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.
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:
static void JNICALL cbClassFileLoadHook jclass class_being_redefined, jobject protection_domain, jint* new_class_data_len, unsigned char** new_class_data
Class file load callback
(jvmtiEnv *jvmti_env, JNIEnv* env, jobject loader, const char* name, jint class_data_len, const unsigned char* class_data, ){ if ( gdata->bci_counter == 0 ) { class_prime_system_classes(); } gdata->bci_counter++; ClassIndex cnum; } else {
Generating the class index
loader_index = loader_find_or_create(env,loader); if ( class_being_redefined != NULL ) { cnum = class_find_or_create(signature, loader_index); 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, "sun/tools/hprof/Tracker" , "Lsun/tools/hprof/Tracker;", "CallSite" "(II)V", , &new_image, &new_length, &my_crw_fatal_error_handler, &class_set_methods);
Class with method Method to call
NULL, NULL, NULL, NULL, NULL, NULL,
© 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
49
Demo
BCI in action Using J2SE 5.0 java.lang.instrument
© 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:
Boot-Class-Path:
© 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 “Premain Class” 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 byte[] inba) > classBeingRedefined, java.security.ProtectionDomain jspd, 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
High call rate to a1()
Dynamic BCI
2 main() 1 main() Add BCI to a1 () A1.
a1 () A1.a2() A1.a1() A1.a2() a1() call counts Switch high call rate to a2() 3 main() A1.
a1 () A1.a2() 4 main() Add BCI to a2 () Remove BCI from a1() A1.a1() A1.
a2 () a1() call counts a2() call counts © Hewlett Packard Co., 2004
MyMon.printCallNumbers: 0 0 a1() a2() MyMon.getHotMethod values: 790 191 Add instrumentation to: a1 MyMon.printCallNumbers: 236 0 MyMon.getHotMethod values: 3666 1081 MyMon.printCallNumbers: 468 0 MyMon.getHotMethod values: 801 200 MyMon.printCallNumbers: 706 0 MyMon.getHotMethod values: 842 200 MyMon.printCallNumbers: 935 0 MyMon.getHotMethod values: 791 210 MyMon.printCallNumbers: 992 0 MyMon.getHotMethod values: 200 822 Add instrumentation to: a2 MyMon.printCallNumbers: 993 232 MyMon.getHotMethod values: 191 830 MyMon.printCallNumbers: 993 462 MyMon.getHotMethod values: 230 772 MyMon.printCallNumbers: 993 707 MyMon.getHotMethod values: 200 861 MyMon.printCallNumbers: 993 941 MyMon.getHotMethod values: 190 812 MyMon.printCallNumbers: 993 999 MyMon.getHotMethod values: 781 220 Add instrumentation to: a1
Time in a1() higher Instrument a1() Time in a2() higher Instrument a2() Time in a1() higher Instrument a1() © Hewlett Packard Co., 2004
a1() a2() MyAgent.premain(): Enter MyAgent.premain(): Exit MyMonThread: Starting thread.
MyMon.printCallNumbers: 0 0 Add instrumentation to: a1 MyMon.printCallNumbers: 435 0 MyMon.printCallNumbers: 861 0 MyMon.printCallNumbers: 1295 0 MyMon.printCallNumbers: 1722 0 MyMon.printCallNumbers: 1829 0 Add instrumentation to: a2 MyMon.printCallNumbers: 1842 485 MyMon.printCallNumbers: 1842 911 MyMon.printCallNumbers: 1842 1356 MyMon.printCallNumbers: 1842 1783 MyMon.printCallNumbers: 1842 1891 Add instrumentation to: a1 MyMon.printCallNumbers: 2270 1902
No counting Counting a1() calls Counting a2() calls © 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", methods[j] = traceMethod "countMethodEntry", "(II)V"); // Select the method to instrument and find the index Method[] methods = java_class.getMethods(); (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 instructions for the method MethodGen mg = new MethodGen(m, class_name, cp); InstructionList il = mg.getInstructionList(); InstructionHandle[] 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; } } } else { il.insert
( ihs[0] , patch
Insert bytecode instructions
); // Insert the instructions!!
} // Update stack size if(code.getMaxStack() < 2) { mg.setMaxStack(2); } return mg.getMethod();
Update stack size © 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", methods[j] = traceMethod "countMethodEntry", "(II)V"); // Select the method to instrument and find the index Method[] methods = java_class.getMethods(); (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
High call rate to a1()
Dynamic BCI
2 main() 1 main() Add BCI to a1 () A1.
a1 () A1.a2() A1.a1() A1.a2() a1() call counts Switch high call rate to a2() 3 main() A1.
a1 () A1.a2() 4 main() Add BCI to a2 () Remove BCI from a1() A1.a1() A1.
a2 () a1() call counts 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.
MyMon.printCallNumbers: 0 0 Add instrumentation to: a1 MyMon.printCallNumbers: 435 0 MyMon.printCallNumbers: 861 0 MyMon.printCallNumbers: 1295 0 MyMon.printCallNumbers: 1722 0 MyMon.printCallNumbers: 1829 0 Add instrumentation to: a2 MyMon.printCallNumbers: 1842 485 MyMon.printCallNumbers: 1842 911 MyMon.printCallNumbers: 1842 1356 MyMon.printCallNumbers: 1842 1783 MyMon.printCallNumbers: 1842 1891 Add instrumentation to: a1 MyMon.printCallNumbers: 2270 1902
No counting Counting a1() calls Counting a2() calls © Hewlett Packard Co., 2004
Call Count Time Call Count Time A1.a1() Call Count increasing Time high A1.a2() © Hewlett Packard Co., 2004
Call Count Time Call Count Time A1.a1() A1.a2() Call Count increasing Times high © Hewlett Packard Co., 2004
Call Count Time Call Count Time A1.a1() A1.a2() © Hewlett Packard Co., 2004
Call Count Time Call Count Time A1.a1() A1.a2() © 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