This document describes the Java Virtual Machine Profiler Interface (JVMPI) in JDK 1.2. It is intended for tools vendors to develop profilers that work in conjunction with Sun's Java virtual machine implementation.
Note: This interface is an experimental feature in the JDK 1.2 final release. The JVMPI is not yet a standard profiling interface. We provide the documentation for the benefit of tools vendors who have an immediate need for profiling hooks in the Java virtual machine. The JVMPI will continue to evolve, based on the feedback from customers and tools vendors. Please send comments to jvmpi@eng.sun.com.
The profiler front-end may or may not run in the same process as the profiler agent. It may reside in a different process on the same machine, or on a remote machine connected via the network. The JVMPI does not specify a standard wire protocol. Tools vendors may design wire protocols suitable for the needs of different profiler front-ends.
A profiling tool based on JVMPI can obtain a variety of information such as heavy memory allocation sites, CPU usage hot-spots, unnecessary object retention, and monitor contention, for a comprehensive performance analysis.
JVMPI supports partial profiling, i.e a user can selectively profile an application for certain subsets of the time the virtual machine is up and can also choose to obtain only certain types of profiling information.
In the current version of JVMPI, only one agent per virtual machine can be supported.
java -Xrunmyprofiler:heapdump=on,file=log.txt ToBeProfiledClassThe VM attempts to locate a profiler agent library called myprofiler in Java's library directory:
PATH
environment variable.
LD_LIBRARY_PATH
.
The VM calls the JVM_OnLoad function, passing a pointer to thejint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved);
JavaVM
instance as the first argument, and string
"heapdump=on,file=log.txt" as the second argument. The third
argument to JVM_OnLoad
is reserved and set to
NULL
.
On success, the JVM_OnLoad
function must return
JNI_OK
. If for some reason the JVM_OnLoad
function
fails, it must return JNI_ERR
.
GetEnv
call on the JavaVM
pointer.
For example, the following code retrieves the version of JVMPI
interface that is implemented in JDK 1.2:
TheJVMPI_Interface *jvmpi_interface; JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved) { int res = (*jvm)->GetEnv(jvm, (void **)&jvmpi_interface, JVMPI_VERSION_1); if (res < 0) { return JNI_ERR; } ... /* use entries in jvmpi_interface */ }
JVMPI_Interface
structure defines the function call interface
between the profiler agent and the VM:
The/* interface functions */ typedef struct { jint version; /* JVMPI version */ /* ------interface implemented by the profiler------ */ void (*NotifyEvent)(JVMPI_Event *event); /* ------interface implemented by the JVM------ */ jint (*EnableEvent)(jint event_type, void *arg); jint (*DisableEvent)(jint event_type, void *arg); jint (*RequestEvent)(jint event_type, void *arg); void (*GetCallTrace)(JVMPI_CallTrace *trace, jint depth); void (*ProfilerExit)(jint); JVMPI_RawMonitor (*RawMonitorCreate)(char *lock_name); void (*RawMonitorEnter)(JVMPI_RawMonitor lock_id); void (*RawMonitorExit)(JVMPI_RawMonitor lock_id); void (*RawMonitorWait)(JVMPI_RawMonitor lock_id, jlong ms); void (*RawMonitorNotifyAll)(JVMPI_RawMonitor lock_id); void (*RawMonitorDestroy)(JVMPI_RawMonitor lock_id); jlong (*GetCurrentThreadCpuTime)(void); void (*SuspendThread)(JNIEnv *env); void (*ResumeThread)(JNIEnv *env); jint (*GetThreadStatus)(JNIEnv *env); jboolean (*ThreadHasRun)(JNIEnv *env); jint (*CreateSystemThread)(char *name, jint priority, void (*f)(void *)); void (*SetThreadLocalStorage)(JNIEnv *env_id, void *ptr); void * (*GetThreadLocalStorage)(JNIEnv *env_id); void (*DisableGC)(void); void (*EnableGC)(void); void (*RunGC)(void); jobjectID (*GetThreadObject)(JNIEnv *env); jobjectID (*GetMethodClass)(jmethodID mid); } JVMPI_Interface;
GetEnv
function returns a pointer to a
JVMPI_Interface
whose version
field
indicates a JVMPI version that is compatible to the version number
argument passed in the GetEnv
call. Note that the value
of the version
field is not necessarily identical to the
version argument passed in the GetEnv
call.
The JVMPI_Interface
returned by GetEnv
has
all the functions set up except for NotifyEvent. The
profiler agent must set up the NotifyEvent function pointer
before returning from JVM_OnLoad.
Event Notification
The JVMPI_Event structure contains the event type, the
JNIEnv
pointer of the current thread, and other
event-specific information. The event specific information is
represented as a union of event-specific structures. The
JVMPI Events section provides a
complete description of all event-specific structures. For
now, we show the event-specific structures for class load and
class unload below.
typedef struct { jint event_type; /* event_type */ JNIEnv *env_id; /* env where this event occurred */ union { struct { char *class_name; /* class name */ char *source_name; /* name of source file */ jint num_interfaces; /* number of interfaces implemented */ jint num_methods; /* number of methods in the class */ JVMPI_Method *methods; /* methods */ jint num_static_fields; /* number of static fields */ JVMPI_Field *statics; /* static fields */ jint num_instance_fields; /* number of instance fields */ JVMPI_Field *instances; /* instance fields */ jobjectID class_id; /* id of the class object */ } class_load; struct { jobjectID class_id; /* id of the class object */ } class_unload; ... /* Refer to the section on JVMPI events for a full listing */ } u; } JVMPI_Event;
The JVMPI refers to entities in the Java virtual machine as various kinds of IDs. Threads, classes, methods, objects, heap arenas and JNI global references all have unique IDs.
Each ID has a defining event and an undefining event. A defining event provides the information related to an ID. For example, the defining event for a thread ID contains, among other entries, the name of the thread.
An ID is valid until its undefining event arrives. An undefining event invalidates the ID, whose value may be reused later as a different kind of ID. The value of a thread ID, for example, may be redefined as a method ID after the thread ends.
ID | data type | defining event | undefining event |
thread ID | JNIEnv * | thread start | thread end |
object ID | jobjectID | object alloc | object free, object move, and arena delete |
class ID | jobjectID | class load | class unload and object move |
method ID | jmethodID | defining class load | defining class unload |
arena ID | jint | arena new | arena delete |
JNI global ref ID | jobject | global ref alloc | global ref free |
Assuming the defining events are enabled during the profiler initialization, the profiler agent is guaranteed to be notified of an entity's creation through a defining event, before the entity appears in other JVMPI events.
If the defining events are not enabled, the profiler agent may receive an unknown ID. In that case the profiler agent may request the corresponding defining event to be sent on demand by issuing a RequestEvent call.
IDs representing objects have type jobjectID
. A class is represented by
the object ID of the corresponding java.lang.Class
object. Therefore, class IDs are also of type jobjectID
.
A jobjectID
is defined by an object
alloc event, and remains valid in the arena in which the object is
allocated until one of its undefining events arrive:
When an object free or arena delete event invalidates an object ID, the object is known as being garbage collected.
Typically, the profiler agent maintains a mapping between
jobjectID
s and its internal representation of object
identities, and updates the mapping in response to the defining and
undefining events for JVMPI object IDs.
Since object IDs may be invalidated during GC, the VM issues all
events that contain jobjectID
entries with GC disabled.
In addition, the profiling agent must disable GC when it is directly
manipulating any jobjectID
data types. Otherwise the GC
may invalidate a jobjectID
while it is being manipulated
in the agent code. The profiler agent must make sure that GC is
disabled when it calls a JVMPI function that either takes a
jobjectID
argument or returns a jobjectID
result. If the function call is inside an event handler where GC is
already disabled, then the profiler agent need not explicitly disable
the GC again.
A thread may be identified either by its JNIEnv
interface
pointer or by the object ID of the corresponding
java.lang.Thread
object. The JNIEnv
pointer
is valid between thread start and thread end events, and remains
constant during the lifetime of a thread. The
java.lang.Thread
object ID, on the other hand, could
remain valid after the thread ends, until it is garbage collected. The
profiler agent can convert a JNIEnv
pointer to the
corresponding thread object ID by calling the GetThreadObject
function.
Events are sent in the same thread where they are generated. For example, a class loading event is sent in the same thread in which the class is loaded. Multiple events may arrive concurrently in different threads. The agent program must therefore provide the necessary synchronization in order to avoid data corruption caused by multiple threads updating the same data structure at the same time.
In some cases, synchronizing on certain frequent events (such as method entry and method exit) may impose unacceptable overhead to program execution. Agents may utilize the thread-local storage support provided by the JVMPI to record profiling data without having to contend for global locks, and only merge the thread-local data into global profiles at selected intervals. The JVMPI supplies the agent with a pointer-size thread-local storage. Following is a simple example that illustrates how a profiler agent may take advantage of this feature. Suppose we need to write a profiler agent that counts the number of methods executed in each thread. The agent installs event handlers for thread start, method entry, and thread end events:
/* thread start event handler * sets up the storage for thread-local method invocation counter */ void ThreadStartHandler(JNIEnv *thread_id) { int *p_ctr = (int *)malloc(sizeof(int)); CALL(SetThreadLocalStorage)(thread_id, p_ctr); } /* method enter event handler * increments thread local method invocation counter */ void MethodEntryHandler(jmethodID method_id, JNIEnv *thread_id) { int *p_ctr = (int *)CALL(GetThreadLocalStorage)(thread_id); (*p_ctr)++; } /* thread end handler * prints the number of methods executed */ void ThreadEndHandler(JNIEnv *thread_id) { int *p_ctr = (int *)CALL(GetThreadLocalStorage)(thread_id); fprintf(stdout, "Thread %x executed %d methods\n", thread_id, (*p_ctr)); free(p_ctr); }
The following JVMPI functions can cause event notification to be sent synchronously in the same thread during the function execution:
The RequestEvent
function supplies the JVMPI event
explicitly requested by the profiler agent. The
CreateSystemThread
function causes thread object
allocation and thread start events to be issued. The
RunGC
function causes GC-related events to be generated.
When a profiling agent is loaded into the Java virtual machine, the process can either be in one of three modes: multi-threaded mode with GC enabled, multi-threaded mode with GC disabled, and the thread suspended mode. Different JVMPI events are issued in different modes. Certain JVMPI functions change the process from one mode to another.
The profiler agent must obey the following guidelines to avoid deadlocks:
CreateSystemThread
and RunGC
. In addition,
programmers need to be aware that disabling the GC creates an implicit
locking dependency among threads. When the GC is disabled, the
current thread may not be able to safely acquire certain
locks. Deadlocks may happen, for example, if one thread disables GC
and tries to acquire a lock, while another thread already acquired
that lock but is triggering a GC.
malloc
and fprintf
functions provided by the
standard C library. These functions typically acquire internal C library locks
that may be held by one of the suspended threads.
The following issues need to be considered when designing the wire protocol in order to allow the profiler agent and front-end to reside on different machines:
For example, the HPROF profiler agent shipped with JDK 1.2 sends the size of all IDs as the first record, and uses the standard network byte order for integer and floating-point data.
jint (*CreateSystemThread)(char *name, jint priority, void (*f)(void *));
It is safe for the profiler agent to make this call only after the JVM
notifies a JVMPI_EVENT_INIT_DONE
and when the system is
in a multi-threaded mode with GC enabled.
Arguments:
name
- name of the thread. priority
- thread priority; the values can be:
JVMPI_NORMAL_PRIORITY
JVMPI_MAXIMUM_PRIORITY
JVMPI_MINIMUM_PRIORITY
f
- function to be run by the thread.
Returns:
JNI_OK
- success. JNI_ERR
- failure.
jint (*DisableEvent)(jint event_type, void *arg);
All events are disabled when the VM starts up. Once enabled, an event stays enabled until it is explicitly disabled.
This function returns JVMPI_NOT_AVAILABLE
if
event_type is JVMPI_EVENT_HEAP_DUMP
,
JVMPI_EVENT_MONITOR_DUMP
or
JVMPI_EVENT_OBJECT_DUMP
.
Arguments:
event_type
- type of event, JVMPI_EVENT_CLASS_LOAD
etc.arg
- event specific information.
Returns:
JVMPI_SUCCESS
disable succeeded. JVMPI_FAIL
disable failed. JVMPI_NOT_AVAILABLE
support for disabling the given event_type
is not available.
void (*DisableGC)(void);
EnabledGC
is called. DisableGC
and
EnableGC
calls may be nested.
jint (*EnableEvent)(jint event_type, void *arg);
All events are disabled when the VM starts up. Once enabled, an event stays enabled until it is explicitly disabled.
This function returns JVMPI_NOT_AVAILABLE
if event_type is JVMPI_EVENT_HEAP_DUMP
, JVMPI_EVENT_MONITOR_DUMP
or
JVMPI_EVENT_OBJECT_DUMP
. The profiler agent must use the
RequestEvent
function to request these events.
Arguments:
event_type
- type of event, JVMPI_EVENT_CLASS_LOAD
etc.arg
- event specific argument.
Returns:
JVMPI_SUCCESS
enable succeeded. JVMPI_FAIL
enable failed. JVMPI_NOT_AVAILABLE
support for enabling the given event_type
is not available.
void (*EnableGC)(void);
DisableGC
and
EnableGC
calls may be nested.
void (*GetCallTrace)(JVMPI_CallTrace *trace, jint depth);
env_id
field in the JVMPI_CallTrace
structure. The
profiler agent should allocate a JVMPI_CallTrace
structure with
enough memory for the requested stack depth.
The VM fills in the
frames
buffer and the num_frames
field.
Arguments:
trace
- trace data structure to be filled by the VM. depth
- depth of the call stack trace.
jlong (*GetCurrentThreadCpuTime)(void);
Returns:
time in nanoseconds
jobjectID (*GetMethodClass)(jmethodID mid);
The profiler must disable GC before calling this function.
Arguments:
mid
- a method ID.
Returns:
object ID of the defining class.
void * (*GetThreadLocalStorage)(JNIEnv *env_id);
Arguments:
env_id
- the JNIEnv *
of the thread.
Returns:
the value of the thread local storage
jobjectID (*GetThreadObject)(JNIEnv *env);
JNIEnv
pointer.
The profiler must disable GC before calling this function.
Arguments:
env
- JNIEnv
pointer of the thread.
Returns:
the thread object ID.
jint (*GetThreadStatus)(JNIEnv *env);
The JVMPI functions SuspendThread
and
ResumeThread
have no affect on the status returned by
GetThreadStatus
. The status of a thread suspended through
the JVMPI remains unchanged and the status at the time of suspension
is returned.
Arguments:
env
- the JNIEnv *
of the thread.
Returns:
JVMPI_THREAD_RUNNABLE
- thread is runnable. JVMPI_THREAD_MONITOR_WAIT
- thread is waiting on a monitor. JVMPI_THREAD_CONDVAR_WAIT
- thread is waiting on a condition variable. When a thread is suspended (by
java.lang.Thread.suspend
) or interrupted in any of the above states theJVMPI_THREAD_SUSPENDED
or theJVMPI_THREAD_INTERRUPTED
bit is set.
void (*NotifyEvent)(JVMPI_Event *event);
EnableEvent
, or
requests a specific type of event by calling
RequestEvent
.
When an event is enabled by EnableEvent
, the thread
that generates the event is the thread in which the event is sent.
When an event is requested by RequestEvent
, the thread
that requests the event is the thread in which the event is sent.
Multiple threads may send multiple events concurrently.
If the event specific information contains a
jobjectID
, this function is called with GC disabled. GC
is enabled after the function returns.
The space allocated for the JVMPI_Event
structure
and any event specific information is freed by the virtual machine once
this function returns. The profiler agent must copy any necessary
data it needs to retain into its internal buffers.
Arguments:
event
- the JVMPI event sent from the VM to the profiling agent.
void (*ProfilerExit)(jint err_code);
err_code
. This
function causes the VM to also exit with the same
err_code
.
Arguments:
err_code
- exit code
JVMPI_RawMonitor (*RawMonitorCreate)(char *lock_name);
Raw monitors are similar to Java monitors. The difference is that raw monitors are not associated with Java objects.
It is not safe for the profiler agent to call this function in the
thread suspended mode because this function may call arbitrary system
functions such as malloc
and block on an internal system
library lock.
If the raw monitor is created with a name beginning with an
underscore ('_'
), then its monitor contention events are
not sent to the profiler agent.
Arguments:
lock_name
- name of raw monitor.
Returns:
a raw monitor
void (*RawMonitorDestroy)(JVMPI_RawMonitor lock_id);
Raw monitors are similar to Java monitors. The difference is that raw monitors are not associated with Java objects.
It is not safe for the profiler agent to call this function in the
thread suspended mode because this function may call arbitrary system
functions such as free
and block on a internal system
library lock.
Arguments:
lock_id
- the raw monitor to be destroyed
void (*RawMonitorEnter)(JVMPI_RawMonitor lock_id);
Raw monitors are similar to Java monitors. The difference is that raw monitors are not associated with Java objects.
It is not safe for the profiler agent to call this function in the thread suspended mode because the current thread may block on the raw monitor already acquired by one of the suspended threads.
Arguments:
lock_id
- the raw monitor to be entered
void (*RawMonitorExit)(JVMPI_RawMonitor lock_id);
Raw monitors are similar to Java monitors. The difference is that raw monitors are not associated with Java objects.
Arguments:
lock_id
- the raw monitor to exit
void (*RawMonitorNotifyAll)(JVMPI_RawMonitor lock_id);
Raw monitors are similar to Java monitors. The difference is that raw monitors are not associated with Java objects.
Arguments:
lock_id
- the raw monitor to notify
void (*RawMonitorWait)(JVMPI_RawMonitor lock_id, jlong ms);
Raw monitors are similar to Java monitors. The difference is that raw monitors are not associated with Java objects.
Arguments:
lock_id
- the raw monitor to wait on ms
- time to wait (in milliseconds).
jint (*RequestEvent)(jint event_type, void *arg);
This function can be called to request one-time events such as
JVMPI_EVENT_HEAP_DUMP
,
JVMPI_EVENT_MONITOR_DUMP
and
JVMPI_EVENT_OBJECT_DUMP
. Notification for these events
cannot be controlled by the EnableEvent
and DisableEvent
functions.
In addition, this function can be called to request the defining events for a specific class, thread, or object. This is useful when the profiler agent needs to resolve an unknown class, method, thread, or object ID received in an event, but the corresponding defining event was disabled earlier.
JVMPI_EVENT_CLASS_LOAD
event and setting the
event-specific argument to the class object ID.
JVMPI_EVENT_THREAD_START
event and setting the
event-specific argument to the thread object ID.
JVMPI_EVENT_OBJECT_ALLOC
event and setting the
event-specific argument to the object ID.
Thus the profiler agent can either enable the above three events
asynchronously by calling EnableEvent
, or request these events
synchronously by calling RequestEvent
. The requested
event is sent in the same thread that issued the
RequestEvent
call, and is sent before the
RequestEvent
function returns.
The RequestEvent
function cannot be used to request other
events not listed above.
Events requested through RequestEvent
will arrive with the
JVMPI_REQUESTED_EVENT
bit set in its event_type
.
Arguments:
event_type
- type of event, JVMPI_EVENT_CLASS_LOAD
etc.arg
- event specific argument.
Returns:
JVMPI_SUCCESS
request succeeded. JVMPI_FAIL
request failed. JVMPI_NOT_AVAILABLE
support for issuing the requested event_type
is not available.
void (*ResumeThread)(JNIEnv *env);
Note that a thread suspended by the java.lang.Thread.suspend
method
cannot be resumed by the JVMPI ResumeThread
function.
Arguments:
env
- the JNIEnv *
of the thread.
void (*RunGC)(void);
void (*SetThreadLocalStorage)(JNIEnv *env_id, void *ptr);
Arguments:
env_id
- the JNIEnv *
of the thread.ptr
- the value to be entered into the thread-local storage.
void (*SuspendThread)(JNIEnv *env);
Note that a thread suspended by the JVMPI SuspendThread
function
cannot be resumed by the java.lang.Thread.resume
method.
In the JDK 1.2 implementation, this function must be called when the GC is disabled. GC must remain disabled until all threads have been resumed.
Arguments:
env
- the JNIEnv *
of the thread.
jboolean (*ThreadHasRun)(JNIEnv *env);
JNIEnv
pointer has consumed CPU time since the last
time the thread was suspended by SuspendThread
. This function must be
called when the thread has been resumed by ResumeThread and then suspended again by the
SuspendThread
function.
Arguments:
env
- the JNIEnv *
of the thread.
Returns:
JNI_TRUE
- thread got a chance to run. JNI_FALSE
- thread did not get a chance to run.
JVMPI_EVENT_ARENA_DELETE
All objects residing in this arena are freed. An explicit
JVMPI_EVENT_OBJECT_FREE
is not
sent for those objects. The profiler agent can infer all the objects
currently residing in that arena by keeping track of the object
allocations in the arena and all the objects moved in and out of
the arena.
This event is issued in the thread suspended mode. The profiler must not
make any blocking calls such as entering a monitor or allocating from
the C heap (for example, via malloc
).
This event is always sent between a pair of
JVMPI_EVENT_GC_START
and
JVMPI_EVENT_GC_FINISH
events.
The profiler agent should acquire all the locks need for processing this
event in the event handler for JVMPI_EVENT_GC_START
.
Contents:struct { jint arena_id; } delete_arena;
arena_id
- ID of the arena being deleted.
JVMPI_EVENT_ARENA_NEW
Contents:struct { jint arena_id; char *arena_name; } new_arena;
arena_id
- ID given to the arena. arena_name
- name of the arena.
JVMPI_EVENT_CLASS_LOAD
JVMPI_EVENT_CLASS_LOAD
event by issuing
a RequestEvent
call. In the
latter case, the JVMPI_REQUESTED_EVENT
bit in the event
type is set.
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
struct { char *class_name; char *source_name; jint num_interfaces; jint num_methods; JVMPI_Method *methods; jint num_static_fields; JVMPI_Field *statics; jint num_instance_fields; JVMPI_Field *instances; jobjectID class_id; } class_load;
Contents:
class_name
- name of class being loaded. source_name
- name of source file that defines the class. num_interfaces
- number of interfaces implemented by this class. methods
- methods defined in the class. num_static_fields
- number of static fields defined in this class. statics
- static fields defined in the class. num_instance_fields
- number of instance fields defined in this class. instances
- instance fields defined in the class. class_id
- class object ID.
Note: class IDs are IDs of the class objects and are subject to change
when JVMPI_EVENT_OBJECT_MOVE
arrives.
JVMPI_EVENT_CLASS_LOAD_HOOK
The profiler must allocate the space for the modified class file data buffer using the memory allocation function pointer sent in this event, because the VM is responsible for freeing the new class file data buffer.
struct { unsigned char *class_data; jint class_data_len; unsigned char *new_class_data; jint new_class_data_len; void * (*malloc_f)(unsigned int); } class_load_hook;
Contents:
class_data
- pointer to the current class file data buffer. class_data_len
- length of current class file data buffer. new_class_data
- pointer to the instrumented class file data buffer. new_class_data_len
- length of the new class file data buffer. malloc_f
- pointer to a memory allocation function.
The profiler agent must set new_class_data
to point
to the newly instrumented class file data buffer and set
new_class_data_len
to the length of that buffer before returning
from NotifyEvent
. It must set
both new_class_data
and new_class_data_len
to
the old values if it chooses not to instrument this class.
JVMPI_EVENT_CLASS_UNLOAD
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
struct { jobjectID class_id; } class_unload;
Contents:
class_id
- class being unloaded.
JVMPI_EVENT_COMPILED_METHOD_LOAD
struct { jmethodID method_id; void *code_addr; jint code_size; jint lineno_table_size; JVMPI_Lineno *lineno_table; } compiled_method_load;
Contents:
method_id
- method being compiled and loaded. code_addr
- address where compiled method code is loaded. code_size
- size of compiled code. lineno_table_size
- size of line number table. lineno_table
- table mapping offset from beginning of method to the src file line number.
JVMPI_EVENT_COMPILED_METHOD_UNLOAD
struct { jmethodID method_id; } compiled_method_unload;
Contents:
method_id
- compiled method being unloaded.
JVMPI_EVENT_DATA_DUMP_REQUEST
There is no event specific information.
JVMPI_EVENT_DATA_RESET_REQUEST
There is no event specific information.
JVMPI_EVENT_GC_FINISH
The event-specific data contains Java heap statistics.
Contents:struct { jlong used_objects; jlong used_object_space; jlong total_object_space; } gc_info;
used_objects
- number of used objects on the heap. used_object_space
- amount of space used by the objects (in bytes). total_object_space
- total amount of object space (in bytes).
JVMPI_EVENT_GC_START
There is no event specific information.
JVMPI_EVENT_HEAP_DUMP
RequestEvent
function. The
profiler agent can specify the level of information to be dumped by
passing an JVMPI_HeapDumpArg
structure to
RequestEvent
as the second argument, with the
heap_dump_level field set to the desired dump level.
The dump level values can be one of the following:
JVMPI_DUMP_LEVEL_0
JVMPI_DUMP_LEVEL_1
JVMPI_DUMP_LEVEL_2
If a NULL value is passed, then the dump level is set to
JVMPI_DUMP_LEVEL_2
.
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
The event-specific data contains a snapshot of all live objects in the Java heap.
Contents:struct { int dump_level; char *begin; char *end; jint num_traces; JVMPI_CallTrace *traces; } heap_dump;
dump_level
- the dump level specified in RequestEvent
begin
- beginning of the heap dump end
- end of the heap dump num_traces
- number of stack traces in which the GC roots reside, 0 for JVMPI_DUMP_LEVEL_0 traces
- the stack traces in which the GC roots reside
The format of the heap dump between begin
and end
depends on the level of information requested. The formats are described
in detail in the JVMPI Dump Formats section.
JVMPI_EVENT_JNI_GLOBALREF_ALLOC
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
Contents:struct { jobjectID obj_id; jobject ref_id; } jni_globalref_alloc;
obj_id
- object ID referred to by the global reference. ref_id
- JNI global reference.
JVMPI_EVENT_JNI_GLOBALREF_FREE
Contents:struct { jobject ref_id; } jni_globalref_free;
ref_id
- JNI global reference.
JVMPI_EVENT_JNI_WEAK_GLOBALREF_ALLOC
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
Contents:struct { jobjectID obj_id; jobject ref_id; } jni_globalref_alloc;
obj_id
- object ID referred to by the weak global reference. ref_id
- JNI weak global reference.
JVMPI_EVENT_JNI_WEAK_GLOBALREF_FREE
Contents:struct { jobject ref_id; } jni_globalref_free;
ref_id
- JNI weak global reference.
JVMPI_EVENT_JVM_INIT_DONE
CreateSystemThread
only after this event is notified.
There is no event specific data.
JVMPI_EVENT_JVM_SHUT_DOWN
There is no event specific data.
JVMPI_EVENT_METHOD_ENTRY
JVMPI_EVENT_METHOD_ENTRY2
, this event does not send the
jobjectID
of the target object on
which the method is invoked.
struct { jmethodID method_id; } method;
Contents:
method_id
- the method being entered.
JVMPI_EVENT_METHOD_ENTRY2
jobjectID
of the target object is sent with the
event. If the method is a static method, the obj_id
field
in the event is set to NULL
.
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
struct { jmethodID method_id; jobjectID obj_id; } method_entry2;
Contents:
method_id
- the method being entered. obj_id
- the target object, NULL
for static methods.
JVMPI_EVENT_METHOD_EXIT
struct { jmethodID method_id; } method;
Contents:
method_id
- the method being entered.
JVMPI_EVENT_MONITOR_CONTENDED_ENTER
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
Contents:struct { jobjectID object; } monitor;
object
- object ID associated with the monitor
JVMPI_EVENT_MONITOR_CONTENDED_ENTERED
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
Contents:struct { jobjectID object; } monitor;
object
- object ID associated with the monitor
JVMPI_EVENT_MONITOR_CONTENDED_EXIT
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
Contents:struct { jobjectID object; } monitor;
object
- object ID associated with the monitor
JVMPI_EVENT_MONITOR_DUMP
RequestEvent
function.
The event-specific data contains a snapshot of all the threads and monitors in the VM.
This event is issued with GC disabled. GC is re-enabled after
NotifyEvent
returns.
Contents:struct { char *begin; char *end; jint num_traces; JVMPI_CallTrace *traces; jint *threads_status; } monitor_dump;
begin
- start of the monitor dump buffer. end
- end of the dump buffer num_traces
- number of thread traces. traces
- traces of all threads. thread_status
- status of all threads.
The format of the monitor dump buffer is described in detail in the JVMPI Dump Formats section.
JVMPI_EVENT_MONITOR_WAIT
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
Contents:struct { jobjectID object; jlong timeout; } monitor_wait;
object
- ID of object on which the current thread is going to wait. ( NULL
indicates the thread is inThread.sleep
.)timeout
- the number of milliseconds the thread will wait. (0 indicates waiting forever.)
JVMPI_EVENT_MONITOR_WAITED
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
Contents:struct { jobjectID object; jlong timeout; } monitor_wait;
object
- ID of object on which the current thread waited. ( NULL
indicates the thread is inThread.sleep
.)timeout
- the number of milliseconds the thread waited.
JVMPI_EVENT_OBJECT_ALLOC
JVMPI_EVENT_OBJECT_ALLOC
event by issuing a RequestEvent
call. In the latter case,
the JVMPI_REQUESTED_EVENT
bit in the event type is set.
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
struct { jint arena_id; jobjectID class_id; jint is_array; jint size; jobjectID obj_id; } obj_alloc;
Contents:
arena_id
- arena where allocated. class_id
- class to which this object belongs, or the array element class if is_array
isJVMPI_CLASS
.is_array
- values can be:
JVMPI_NORMAL_OBJECT
normal object JVMPI_CLASS
array of objects JVMPI_BOOLEAN
array of booleans JVMPI_BYTE
array of bytes JVMPI_CHAR
array of chars JVMPI_SHORT
array of shorts JVMPI_INT
array of ints JVMPI_LONG
array of longs JVMPI_FLOAT
array of floats JVMPI_DOUBLE
array of doubles size
- size in number of bytes. obj_id
- unique object ID.
JVMPI_EVENT_OBJECT_DUMP
RequestEvent
function.
The jobjectID
of the object for which a dump is being requested
should be passed as the second argument to RequestEvent
.
The profiler agent should request this event with GC disabled.
The event-specific data contains a snapshot of the object.
Contents:struct { jint data_len; char *data; } object_dump;
data_len
- length of the object dump buffer data
- beginning of the object dump
The format of the object dump buffer is described in detail in the JVMPI Dump Formats section.
JVMPI_EVENT_OBJECT_FREE
This event is issued in the thread suspended mode. The profiler must
not make any blocking calls such as entering a monitor or allocating
from the C heap (for example, via malloc
).
This event is always sent between a pair of JVMPI_EVENT_GC_START
and JVMPI_EVENT_GC_FINISH
events.
The profiler agent should acquire all the locks need for processing this
event in the event handler for JVMPI_EVENT_GC_START
.
struct { jobjectID obj_id; } obj_free;
Contents:
obj_id
- object being freed.
JVMPI_EVENT_OBJECT_MOVE
This event is issued in the thread suspended mode. The profiler must
not make any blocking calls such as entering a monitor or allocating
from the C heap (for example, via malloc
).
This event is always sent between a pair of
JVMPI_EVENT_GC_START
and
JVMPI_EVENT_GC_FINISH
events.
The profiler agent should acquire all the locks need for processing this
event in the event handler for JVMPI_EVENT_GC_START
.
struct { jint arena_id; jobjectID obj_id; jint new_arena_id; jobjectID new_obj_id; } obj_move;
Contents:
arena_id
- current arena. obj_id
- current object ID. new_arena_id
- new arena. new_obj_id
- new object ID.
JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTER
Contents:struct { char *name; JVMPI_RawMonitor id; } raw_monitor;
name
- name of the raw monitor id
- ID of the raw monitor
JVMPI_EVENT_RAW_MONITOR_CONTENDED_ENTERED
Contents:struct { char *name; JVMPI_RawMonitor id; } raw_monitor;
name
- name of the raw monitor id
- ID of the raw monitor
JVMPI_EVENT_RAW_MONITOR_CONTENDED_EXIT
Contents:struct { char *name; JVMPI_RawMonitor id; } raw_monitor;
name
- name of the raw monitor id
- ID of the raw monitor
JVMPI_EVENT_THREAD_END
The env_id field of the JVMPI_Event
received
in this event notification is the JNIEnv
interface
pointer of the thread that ended.
JVMPI_EVENT_THREAD_START
JVMPI_EVENT_THREAD_START
event by
issuing a RequestEvent
call. In
the latter case, the JVMPI_REQUESTED_EVENT
bit in the
event type is set.
This event is issued with GC disabled.
GC is re-enabled after NotifyEvent
returns.
struct { char *thread_name; char *group_name; char *parent_name; jobjectID thread_id; JNIEnv *thread_env_id; } thread_start;
Contents:
Threads are associated with a
thread_name
- name of thread being started. group_name
- group to which the thread belongs. parent_name
- name of parent. thread_id
- thread object ID. thread_env_id
- JNIEnv *
of the thread.
JNIEnv
pointer and a thread
object ID. The JVMPI uses the JNIEnv
pointer as the
thread ID.
u1: | 1 byte | ||||||||||||||||||||
u2: | 2 bytes | ||||||||||||||||||||
u4: | 4 bytes | ||||||||||||||||||||
u8: | 8 bytes | ||||||||||||||||||||
ty: | u1 where: | ||||||||||||||||||||
|
|||||||||||||||||||||
vl: | values, exact size depends on the type of value: | ||||||||||||||||||||
|
The heap dump format depends on the level of information requested.
JVMPI_DUMP_LEVEL_0:
The dump consists of a sequence of records of the following format:
ty
type of object jobjectID
object
JVMPI_DUMP_LEVEL_1:
The dump format is the same as
that of JVMPI_DUMP_LEVEL_2
, except that the following
values are excluded from the dump: primitive fields in object instance
dumps, primitive static fields in class dumps, and primitive array elements.
JVMPI_DUMP_LEVEL_2:
The dump consists of a
sequence of records, where each record includes an 8-bit record type
followed by data whose format is specific to each record type.
Record type Record data JVMPI_GC_ROOT_UNKNOWN
(unknown root)
jobjectID
object JVMPI_GC_ROOT_JNI_GLOBAL
(JNI global ref root)
jobjectID
object jobject
JNI global reference JVMPI_GC_ROOT_JNI_LOCAL
(JNI local ref)
jobjectID
object JNIEnv *
thread u4
frame # in stack trace (-1 for empty) JVMPI_GC_ROOT_JAVA_FRAME
(Java stack frame)
jobjectID
object JNIEnv *
thread u4
frame # in stack trace (-1 for empty) JVMPI_GC_ROOT_NATIVE_STACK
(native stack)
jobjectID
object JNIEnv *
thread JVMPI_GC_ROOT_STICKY_CLASS
(system class)
jobjectID
class object JVMPI_GC_ROOT_THREAD_BLOCK
(reference from thread block)
jobjectID
thread object JNIEnv *
thread JVMPI_GC_ROOT_MONITOR_USED
(entered monitor)
jobjectID
object JVMPI_GC_CLASS_DUMP
(dump of a class object)
jobjectID
class jobjectID
super jobjectID
class loader jobjectID
signers jobjectID
protection domain jobjectID
class name (a String
object, may beNULL
)void *
reserved u4
instance size (in bytes) [jobjectID]*
interfaces u2
size of constant pool [u2,
constant pool index, ty,
type, vl]*
value [vl]*
static field values JVMPI_GC_INSTANCE_DUMP
(dump of a normal object)
jobjectID
object jobjectID
class u4
number of bytes that follow [vl]*
instance field values (class, followed by super, super's super ...) JVMPI_GC_OBJ_ARRAY_DUMP
(dump of an object array)
jobjectID
array object u4
number of elements jobjectID
element class ID (may be NULL
in JDK 1.2)[jobjectID]*
elements JVMPI_GC_PRIM_ARRAY_DUMP
(dump of a primitive array)
jobjectID
array object u4
number of elements ty
element type [vl]*
elements
JVMPI_GC_CLASS_DUMP
JVMPI_GC_INSTANCE_DUMP
JVMPI_GC_OBJ_ARRAY_DUMP
JVMPI_GC_PRIM_ARRAY_DUMP
JVMPI_DUMP_LEVEL_2
, with all of the
following values included: primitive fields in object instance dumps,
primitive static fields in class dumps, and primitive arrays elements.
Record type Record data JVMPI_MONITOR_JAVA
(Java monitor)
jobjectID
object ID JNIEnv *
owner thread u4
entry count u4
number of threads waiting to enter [JNIEnv *]*
threads waiting to enter u4
number of threads waiting to be notified [JNIEnv *]*
threads waiting to be notified JVMPI_MONITOR_RAW
(Raw monitor)
char *
raw monitor name JVMPI_RawMonitor
raw monitor ID JNIEnv *
owner thread u4
entry count u4
number of threads waiting to enter [JNIEnv *]*
threads waiting to enter u4
number of threads waiting to be notified [JNIEnv *]*
threads waiting to be notified
jobjectID
JVMPI_CallFrame
JVMPI_CallTrace
JVMPI_Field
JVMPI_HeapDumpArg
JVMPI_Lineno
JVMPI_Method
JVMPI_RawMonitor
Characters are encoded using the UTF-8 encoding as documented in the Java virtual machine specification.
jobjectID
An opaque pointer representing an object ID.
struct _jobjectID; typedef struct _jobjectID * jobjectID;
JVMPI_CallFrame
A method being executed.
Fields:typedef struct { jint lineno; jmethodID method_id; } JVMPI_CallFrame;
line number
- line number in the source file. method_id
- method being executed.
JVMPI_CallTrace
Fields:typedef struct { JNIEnv *env_id; jint num_frames; JVMPI_CallFrame *frames; } JVMPI_CallTrace;
env_id
- ID of thread which executed this trace. num_frames
- number of frames in the trace. frames
-the JVMPI_CallFrame
s that make up this trace. Callee followed by callers.
JVMPI_Field
Fields:typedef struct { char *field_name; char *field_signature; } JVMPI_Field;
field_name
- name of field field_signature
- signature of field
JVMPI_HeapDumpArg
Additional info for requesting heap dumps.
Fields:typedef struct { jint heap_dump_level; } JVMPI_HeapDumpArg;
heap_dump_level
- level of heap dump information, values can be:
JVMPI_DUMP_LEVEL_0
JVMPI_DUMP_LEVEL_1
JVMPI_DUMP_LEVEL_2
JVMPI_Lineno
Fields:typedef struct { jint offset; jint lineno; } JVMPI_Lineno;
offset
- offset from beginning of method lineno
- lineno from beginning of source file
JVMPI_Method
Fields:typedef struct { char *method_name; char *method_signature; jint start_lineno; jint end_lineno; jmethodID method_id; } JVMPI_Method;
method_name
- name of method method_signature
- signature of method start_lineno
- start line number in the source file end_lineno
- end line number in the source file method_id
- ID given to this method
JVMPI_RawMonitor
An opaque pointer representing a raw monitor.
struct _JVMPI_RawMonitor; typedef struct _JVMPI_RawMonitor * JVMPI_RawMonitor;
JVMPI_EVENT_METHOD_ENTRY
, JVMPI_EVENT_METHOD_ENTRY2
, JVMPI_EVENT_METHOD_EXIT
, JVMPI_EVENT_COMPILED_METHOD_LOAD
, and JVMPI_EVENT_COMPILED_METHOD_UNLOAD
JVMPI_GC_CLASS_DUMP
dump record now includes a
jobjectID
denoting the class name string object. This field was reserved in JDK 1.2.
The field is maintained by the VM as a class name cache, and thus may or may
not be set for a given class.
JVMPI_EVENT_OBJECT_ALLOC
events for object arrays are issued
with unknown element class IDs (i.e., the class_id
field is always NULL
).
SuspendThread
must be called with the GC is disabled.
GC must remain disabled until all threads have been resumed.
JNIEnv
interface pointer.
JVMPI_EVENT_ARENA_NEW
and JVMPI_EVENT_ARENA_DELETE
events are never issued. Arena IDs in other events are always set to 1.
HPROF is a simple profiler agent shipped with JDK1.2. It is a dynamically-linked library that interacts with the JVMPI and writes out profiling information either to a file or to a socket in ascii or binary format. This information can be further processed by a profiler front-end tool.
It is capable of presenting CPU usage, heap allocation statistics and monitor contention profiles. In addition it can also report complete heap dumps and states of all the monitors and threads in the Java virtual machine.
HPROF can be invoked by:
java -Xrunhprof ToBeProfiledClassDepending on the type of profiling requested, HPROF instructs the virtual machine to send it the relevant JVMPI events and processes the event data into profiling information. For example, the following command obtains the heap allocation profile:
java -Xrunhprof:heap=sites ToBeProfiledClassFollowing is the complete list of options that can passed to hprof :
HPROF usage: -Xrunhprof[:help]|[option=value, ...] Option Name and Value Description Default --------------------- ----------- ------- heap=dump|sites|all heap profiling all cpu=samples|times|old CPU usage off monitor=y|n monitor contention n format=a|b ascii or binary output a file=name write data to file java.hprof(.txt for ascii) net=host:port send data over a socket write to file depth=size stack trace depth 4 cutoff=value output cutoff point 0.0001 lineno=y|n line number in traces? y thread=y|n thread in traces? n doe=y|n dump on exit? y Example: java -Xrunhprof:cpu=samples,file=log.txt,depth=3 FooClass
By default, heap profiling information (sites and dump) is written out to java.hprof.txt (ascii).
javac
) on a set of input files. Only parts of the profiler output are shown here.
Command used: javac -J-Xrunhprof:heap=sites foo.java ...
A crucial piece of information in heap profile is the amount of allocation that occurs in various parts of the program. TheSITES BEGIN (ordered by live bytes) Wed Oct 7 11:38:10 1998 percent live alloc'ed stack class rank self accum bytes objs bytes objs trace name 1 9.18% 9.18% 149224 5916 1984600 129884 1073 char [] 2 7.28% 16.45% 118320 5916 118320 5916 1090 sun/tools/java/Identifier 3 7.28% 23.73% 118320 5916 118320 5916 1091 java/util/Hashtable$Entry ... 7 3.39% 41.42% 55180 2759 55180 2759 1264 java/util/Hashtable$Entry ... SITES END
SITES
record above tells us that 9.18% of live
objects are character arrays. Note that the amount of live data is only a fraction
of the total allocation that has occurred at a given site; the rest has been garbage collected.
A good way to relate allocation sites to the source code is to record the dynamic stack traces that led to the heap allocation. Following is another part of the profiler output that illustrates the stack traces referred to by the four allocation sites in output shown above.
THREAD START (obj=1d6b20, id = 1, name="main", group="main") ... TRACE 1073: (thread=1) java/lang/String.(String.java:244) sun/tools/java/Scanner.bufferString(Scanner.java:143) sun/tools/java/Scanner.scanIdentifier(Scanner.java:942) sun/tools/java/Scanner.xscan(Scanner.java:1281) TRACE 1090: (thread=1) sun/tools/java/Identifier.lookup(Identifier.java:106) sun/tools/java/Scanner.scanIdentifier(Scanner.java:942) sun/tools/java/Scanner.xscan(Scanner.java:1281) sun/tools/java/Scanner.scan(Scanner.java:971) TRACE 1091: (thread=1) java/util/Hashtable.put(Hashtable.java:405) sun/tools/java/Identifier.lookup(Identifier.java:106) sun/tools/java/Scanner.scanIdentifier(Scanner.java:942) sun/tools/java/Scanner.xscan(Scanner.java:1281) TRACE 1264: (thread=1) java/util/Hashtable.put(Hashtable.java:405) sun/tools/java/Type. (Type.java:90) sun/tools/java/MethodType. (MethodType.java:42) sun/tools/java/Type.tMethod(Type.java:274)
Each frame in the stack trace contains class name, method name, source
file name, and the line number. The user can set the maximum number
of frames collected by the HPROF agent. The default limit is 4. Stack
traces reveal not only which methods performed heap allocation, but
also which methods were ultimately responsible for making calls that
resulted in memory allocation. For example, in the heap profile above,
instances of the same java/util/Hashtable$Entry
class are
allocated in traces 1091 and 1264, each originated from different
methods.
javac
compiler.
Command used: javac -J-Xrunhprof:cpu=samples foo.java ...
CPU SAMPLES BEGIN (total = 252378) Wed Oct 07 13:30:10 1998 rank self accum count trace method 1 4.96% 4.96% 12514 303 sun/io/ByteToCharSingleByte.convert 2 3.18% 8.14% 8022 306 java/lang/String.charAt 3 1.91% 10.05% 4828 301 sun/tools/java/ScannerInputReader.4 1.80% 11.85% 4545 305 sun/io/ByteToCharSingleByte.getUnicode 5 1.50% 13.35% 3783 304 sun/io/ByteToCharSingleByte.getUnicode 6 1.30% 14.65% 3280 336 sun/tools/java/ScannerInputReader.read 7 1.13% 15.78% 2864 404 sun/io/ByteToCharSingleByte.convert 8 1.11% 16.89% 2800 307 java/lang/String.length 9 1.00% 17.89% 2516 4028 java/lang/Integer.toString 10 0.95% 18.84% 2403 162 java/lang/System.arraycopy ... CPU SAMPLES END
The HPROF agent periodically samples the stack of all running threads
to record the most frequently active stack traces. The count
field above indicates how many times a particular stack trace was found
to be active. These stack traces correspond to the CPU usage hot spots
in the application.