Download 3256 Bytecode Instrumentation Revealed

Document related concepts
no text concepts found
Transcript
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