3256 Bytecode Instrumentation Revealed

Download Report

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 , finalize, and 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. – 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_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

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: Can-Redefine-Classes: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 “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