HotSpot 内にはユーザー空間用 DTrace(USDT) のフック点(probes) が様々な箇所に仕掛けられている. これにより HotSpot の情報が DTrace 経由で取得できる.
内部実装的には, USDT の DTRACE_PROBE*() マクロが直接使われている箇所は (JNI 関係などの) ごく一部で, ほとんどの箇所はラッパーである HS_DTRACE_PROBE*() マクロ経由で probe が生成されている.
なお, トレースを取得すると非常に重くなる処理 (メソッド呼び出し等) については, 対応するオプションが指定された場合にのみ probe を埋め込むようにしている. また埋め込む場合でも, 動的生成したコード中に dtrace フック点を埋めるのは厳しいため, SharedRuntime や ObjectMonitor/ObjectSynchronizer といった静的に分かるコード内に probe が埋められる. 該当するオプションは以下の通り.
メソッド呼び出し (-XX:+DTraceMethodProbes)
オブジェクト確保 (-XX:+DTraceAllocProbes)
モニタ取得 (-XX:+DTraceMonitorProbes)
なお, これらのオプション値は Dynamic Attach 機能 (から呼び出せる DTrace クラス) によって動的に変更することもできる (See: here for details). (変更した場合には, 当然ながら, その時点で JIT 生成コードは全部 deopt される)
なお, Solaris 環境以外でもソースコードはそのままコンパイルできる. これは sdt.h がない場合には DTRACE_PROBE*() が空文字列に展開されるように #define されているため.
((cite: hotspot/src/share/vm/utilities/dtrace.hpp))
#if defined(SOLARIS) && defined(DTRACE_ENABLED)
...
#else // ndef SOLARIS || ndef DTRACE_ENABLED
...
#define DTRACE_PROBE(a,b) {;}
#define DTRACE_PROBE1(a,b,c) {;}
#define DTRACE_PROBE2(a,b,c,d) {;}
#define DTRACE_PROBE3(a,b,c,d,e) {;}
#define DTRACE_PROBE4(a,b,c,d,e,f) {;}
#define DTRACE_PROBE5(a,b,c,d,e,f,g) {;}
フック箇所の一覧は以下の通り.
Probe name | Probe point | Note |
---|---|---|
hotspot.method__entry | SharedRuntime::dtrace_method_entry() | -XX:+DTraceMethodProbes が必要 |
hotspot.method__exit | SharedRuntime::dtrace_method_exit() | -XX:+DTraceMethodProbes が必要 |
hotspot.object__alloc | SharedRuntime::dtrace_object_alloc_base() | -XX:+DTraceAllocProbes が必要 |
hotspot.monitor__wait | ObjectSynchronizer::wait() | -XX:+DTraceMonitorProbes が必要 |
hotspot.monitor__waited | dtrace_waited_probe() | -XX:+DTraceMonitorProbes が必要 |
hotspot.monitor__notify | ObjectMonitor::notify() | -XX:+DTraceMonitorProbes が必要 |
hotspot.monitor__notifyAll | ObjectMonitor::notifyAll() | -XX:+DTraceMonitorProbes が必要 |
hotspot.monitor_contended_enter | ObjectMonitor::enter() | -XX:+DTraceMonitorProbes が必要 |
hotspot.monitor_contended_entered | ObjectMonitor::enter() | -XX:+DTraceMonitorProbes が必要 |
hotspot.monitor_contended_exit | ObjectMonitor::ExitEpilog() | -XX:+DTraceMonitorProbes が必要 |
hotspot.method_compile_begin | CompileBroker::invoke_compiler_on_method() | |
hotspot.method_compile_end | CompileBroker::invoke_compiler_on_method() | |
hotspot.compiled_method_load | nmethod::post_compiled_method_load_event() | |
hotspot.compiled_method_unload | nmethod::post_compiled_method_unload() | |
hotspot.mem_poolgc_begin | GCMemoryManager::gc_begin() | |
hotspot.mem_poolgc_end | GCMemoryManager::gc_end() | |
hotspot.class_initialization_required | instanceKlass::initialize_impl() | |
hotspot.class_initialization_recursive | instanceKlass::initialize_impl() | |
hotspot.class_initialization_concurrent | instanceKlass::initialize_impl() | |
hotspot.class_initialization_erroneous | instanceKlass::initialize_impl() | |
hotspot.class_initializationsuper_failed | instanceKlass::initialize_impl() | |
hotspot.class_initialization_clinit | instanceKlass::initialize_impl() | |
hotspot.class_initialization_error | instanceKlass::initialize_impl() | |
hotspot.class_initialization_end | instanceKlass::initialize_impl() | |
hotspot.class__load | ClassLoadingService::notify_class_loaded() | |
hotspot.class__unload | ClassLoadingService::notify_class_unloaded() | |
hotspot.thread__start | JavaThread::run() | |
hotspot.thread__stop | JavaThread::thread_main_inner() | |
hotspot.thread_park_begin | Unsafe_Park() | |
hotspot.thread_park_end | Unsafe_Park() | |
hotspot.thread__unpark | Unsafe_Unpark() | |
hotspot.thread__yield | JVM_Yield() | |
hotspot.thread_sleep_begin | JVM_Sleep() | |
hotspot.thread_sleep_end | JVM_Sleep() | |
hotspot.vmops__request | VMOperationQueue::add() | |
hotspot.vmops__begin | VMThread::evaluate_operation() | |
hotspot.vmops__end | VMThread::evaluate_operation() | |
hotspot.gc__begin | VM_GC_Operation::notify_gc_begin() | |
hotspot.gc__end | VM_GC_Operation::notify_gc_end() | |
hotspot.vm__shutdown | notify_vm_shutdown() | |
hotspot.vm_init_begin | Threads::create_vm() | |
hotspot.vm_init_end | Threads::create_vm() | |
hotspot_jni.*__enter | 各種 JNI 関数 | |
hotspot_jni.*__return | 各種 JNI 関数 | |
hotspot_jni.GetDefaultJavaVMInitArgs__entry | JNI_GetDefaultJavaVMInitArgs() | |
hotspot_jni.GetCreatedJavaVMs__entry | JNI_GetCreatedJavaVMs() | |
hotspot_jni.GetCreatedJavaVMs__return | JNI_GetCreatedJavaVMs() | |
hotspot_jni.CreateJavaVM__entry | JNI_CreateJavaVM() | |
hs_private.hashtable__new_entry | Hashtable |
|
hs_private.cms_initmark_begin | VM_CMS_Initial_Mark::doit() | |
hs_private.cms_initmark_end | VM_CMS_Initial_Mark::doit() | |
hs_private.cms_remark_begin | VM_CMS_Final_Remark::doit() | |
hs_private.cms_remark_end | VM_CMS_Final_Remark::doit() | |
hs_private.safepoint__begin | RuntimeService::record_safepoint_begin() | |
hs_private.safepoint__end | RuntimeService::record_safepoint_end() |
どの HS_DTRACE_PROBE*() マクロも, 最終的には全て HS_DTRACE_PROBE_FN() にたどり着き, dtrace_**() 関数の呼び出しに展開される.
((cite: hotspot/src/share/vm/utilities/dtrace.hpp))
#define HS_DTRACE_PROBE_FN(provider,name)\
__dtrace_##provider##___##name
#define HS_DTRACE_PROBE_DECL_N(provider,name,args) \
DTRACE_ONLY(extern "C" void HS_DTRACE_PROBE_FN(provider,name) args)
#define HS_DTRACE_PROBE_CDECL_N(provider,name,args) \
DTRACE_ONLY(extern void HS_DTRACE_PROBE_FN(provider,name) args)
/* Dtrace probe declarations */
#define HS_DTRACE_PROBE_DECL(provider,name) \
HS_DTRACE_PROBE_DECL0(provider,name)
#define HS_DTRACE_PROBE_DECL0(provider,name)\
HS_DTRACE_PROBE_DECL_N(provider,name,(void))
#define HS_DTRACE_PROBE_DECL1(provider,name,t0)\
HS_DTRACE_PROBE_DECL_N(provider,name,(uintptr_t))
#define HS_DTRACE_PROBE_DECL2(provider,name,t0,t1)\
HS_DTRACE_PROBE_DECL_N(provider,name,(uintptr_t,uintptr_t))
#define HS_DTRACE_PROBE_DECL3(provider,name,t0,t1,t2)\
HS_DTRACE_PROBE_DECL_N(provider,name,(uintptr_t,uintptr_t,uintptr_t))
#define HS_DTRACE_PROBE_DECL4(provider,name,t0,t1,t2,t3)\
HS_DTRACE_PROBE_DECL_N(provider,name,(uintptr_t,uintptr_t,uintptr_t,\
uintptr_t))
#define HS_DTRACE_PROBE_DECL5(provider,name,t0,t1,t2,t3,t4)\
HS_DTRACE_PROBE_DECL_N(provider,name,(\
uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t))
#define HS_DTRACE_PROBE_DECL6(provider,name,t0,t1,t2,t3,t4,t5)\
HS_DTRACE_PROBE_DECL_N(provider,name,(\
uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t))
#define HS_DTRACE_PROBE_DECL7(provider,name,t0,t1,t2,t3,t4,t5,t6)\
HS_DTRACE_PROBE_DECL_N(provider,name,(\
uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t))
#define HS_DTRACE_PROBE_DECL8(provider,name,t0,t1,t2,t3,t4,t5,t6,t7)\
HS_DTRACE_PROBE_DECL_N(provider,name,(\
uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,\
uintptr_t))
#define HS_DTRACE_PROBE_DECL9(provider,name,t0,t1,t2,t3,t4,t5,t6,t7,t8)\
HS_DTRACE_PROBE_DECL_N(provider,name,(\
uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,\
uintptr_t,uintptr_t))
#define HS_DTRACE_PROBE_DECL10(provider,name,t0,t1,t2,t3,t4,t5,t6,t7,t8,t9)\
HS_DTRACE_PROBE_DECL_N(provider,name,(\
uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,uintptr_t,\
uintptr_t,uintptr_t,uintptr_t))
/* Dtrace probe definitions */
#define HS_DTRACE_PROBE_N(provider,name, args) \
DTRACE_ONLY(HS_DTRACE_PROBE_FN(provider,name) args)
#define HS_DTRACE_PROBE(provider,name) HS_DTRACE_PROBE0(provider,name)
#define HS_DTRACE_PROBE0(provider,name)\
HS_DTRACE_PROBE_N(provider,name,())
#define HS_DTRACE_PROBE1(provider,name,a0)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0))
#define HS_DTRACE_PROBE2(provider,name,a0,a1)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1))
#define HS_DTRACE_PROBE3(provider,name,a0,a1,a2)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2))
#define HS_DTRACE_PROBE4(provider,name,a0,a1,a2,a3)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
(uintptr_t)a3))
#define HS_DTRACE_PROBE5(provider,name,a0,a1,a2,a3,a4)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
(uintptr_t)a3,(uintptr_t)a4))
#define HS_DTRACE_PROBE6(provider,name,a0,a1,a2,a3,a4,a5)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
(uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5))
#define HS_DTRACE_PROBE7(provider,name,a0,a1,a2,a3,a4,a5,a6)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
(uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5,(uintptr_t)a6))
#define HS_DTRACE_PROBE8(provider,name,a0,a1,a2,a3,a4,a5,a6,a7)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
(uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5,(uintptr_t)a6,(uintptr_t)a7))
#define HS_DTRACE_PROBE9(provider,name,a0,a1,a2,a3,a4,a5,a6,a7,a8)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
(uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5,(uintptr_t)a6,(uintptr_t)a7,\
(uintptr_t)a8))
#define HS_DTRACE_PROBE10(provider,name,a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)\
HS_DTRACE_PROBE_N(provider,name,((uintptr_t)a0,(uintptr_t)a1,(uintptr_t)a2,\
(uintptr_t)a3,(uintptr_t)a4,(uintptr_t)a5,(uintptr_t)a6,(uintptr_t)a7,\
(uintptr_t)a8,(uintptr_t)a9))
なお, 全部 DTRACE_ONLY で括られた形になるので DTrace が無効な環境では全て空になる. そして現状では Solaris & DTRACE_ENABLED でなければ DTRACE_ONLY は空にされている.
((cite: hotspot/src/share/vm/utilities/dtrace.hpp))
#if defined(SOLARIS) && defined(DTRACE_ENABLED)
...
#define DTRACE_ONLY(x) x
...
#else // ndef SOLARIS || ndef DTRACE_ENABLED
#define DTRACE_ONLY(x)
...
(#Under Construction)
-> InterpreterMacroAssembler::notify_method_entry() が生成するコード (Sparc, x86_64 のどちらも) -> SharedRuntime::dtrace_method_entry() -> HS_DTRACE_PROBE7() マクロ -> SharedRuntime::generate_native_wrapper() が生成するコード (Sparc, x86_64 のどちらも) -> SharedRuntime::dtrace_method_entry() -> (同上) ...(#Under Construction) -> GraphKit::make_dtrace_method_entry_exit() が生成するコード -> GraphKit::make_runtime_call() が生成するコード -> SharedRuntime::dtrace_method_entry() -> (同上)
-> InterpreterMacroAssembler::notify_method_exit() が生成するコード (Sparc, x86_64 のどちらも) -> SharedRuntime::dtrace_method_exit() -> HS_DTRACE_PROBE7() マクロ
TemplateTable::_new() (Sparc, x86_64 のどちらも) -> SharedRuntime::dtrace_object_alloc() -> SharedRuntime::dtrace_object_alloc_base() -> HS_DTRACE_PROBE4() マクロ (See: here for details) -> CollectedHeap::post_allocation_setup_obj() -> post_allocation_notify() -> SharedRuntime::dtrace_object_alloc() -> (同上) (See: here for details) -> CollectedHeap::post_allocation_setup_array() -> post_allocation_notify() -> (同上) ...(#Under Construction) -> PhaseMacroExpand::expand_allocate_common() が生成するコード -> SharedRuntime::dtrace_object_alloc_base() -> (同上)
(See: here for details) -> ObjectSynchronizer::wait() -> DTRACE_MONITOR_WAIT_PROBE() マクロ -> HS_DTRACE_PROBE5() マクロ
(See: here for details) -> ObjectSynchronizer::wait() -> dtrace_waited_probe() -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/synchronizer.cpp) -> HS_DTRACE_PROBE4() マクロ
(See: here for details) -> ObjectMonitor::notify() -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp) -> (同上)
(See: here for details) -> ObjectMonitor::notifyAll() -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp) -> (同上)
(See: here and here for details) -> ObjectMonitor::enter() -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp) -> HS_DTRACE_PROBE4() マクロ
(See: here and here for details) -> ObjectMonitor::enter() -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp) -> (同上)
(See: ) -> ObjectMonitor::ExitEpilog() -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp) -> (同上)
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.