Up Top

Serviceability 機能 : OS のトレーサ機能との連携 : DTrace との連携


概要(Summary)

HotSpot 内にはユーザー空間用 DTrace(USDT) のフック点(probes) が様々な箇所に仕掛けられている. これにより HotSpot の情報が DTrace 経由で取得できる.

内部実装的には, USDT の DTRACE_PROBE*() マクロが直接使われている箇所は (JNI 関係などの) ごく一部で, ほとんどの箇所はラッパーである HS_DTRACE_PROBE*() マクロ経由で probe が生成されている.

なお, トレースを取得すると非常に重くなる処理 (メソッド呼び出し等) については, 対応するオプションが指定された場合にのみ probe を埋め込むようにしている. また埋め込む場合でも, 動的生成したコード中に dtrace フック点を埋めるのは厳しいため, SharedRuntime や ObjectMonitor/ObjectSynchronizer といった静的に分かるコード内に probe が埋められる. 該当するオプションは以下の通り.

なお, これらのオプション値は Dynamic Attach 機能 (から呼び出せる DTrace クラス) によって動的に変更することもできる (See: here for details). (変更した場合には, 当然ながら, その時点で JIT 生成コードは全部 deopt される)

備考(Notes)

なお, 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) {;}

備考(Notes)

フック箇所の一覧は以下の通り.

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::new_entry()
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()

備考(Notes)

どの 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)
    ...

処理の流れ (概要)(Execution Flows : Summary)

... (#TODO)

(#Under Construction)

メソッド呼び出しの probe 処理 (-XX:+DTraceMethodProbes)

hotspot.method__entry の probe 処理

-> 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()
         -> (同上)

hotspot.method__exit の probe 処理

-> InterpreterMacroAssembler::notify_method_exit() が生成するコード  (Sparc, x86_64 のどちらも)
   -> SharedRuntime::dtrace_method_exit()
      -> HS_DTRACE_PROBE7() マクロ

オブジェクト確保の probe 処理 (-XX:+DTraceAllocProbes)

hotspot.object__alloc の probe 処理

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()
      -> (同上)

モニタ取得の probe 処理 (-XX:+DTraceMonitorProbes)

hotspot.monitor__wait の probe 処理

(See: here for details)
-> ObjectSynchronizer::wait()
   -> DTRACE_MONITOR_WAIT_PROBE() マクロ
      -> HS_DTRACE_PROBE5() マクロ

hotspot.monitor__waited の probe 処理

(See: here for details)
-> ObjectSynchronizer::wait()
   -> dtrace_waited_probe()
      -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/synchronizer.cpp)
         -> HS_DTRACE_PROBE4() マクロ

hotspot.monitor__notify の probe 処理

(See: here for details)
-> ObjectMonitor::notify()
   -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp)
      -> (同上)

hotspot.monitor__notifyAll の probe 処理

(See: here for details)
-> ObjectMonitor::notifyAll()
   -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp)
      -> (同上)

hotspot.monitor_contended_enter の probe 処理

(See: here and here for details)
-> ObjectMonitor::enter()
   -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp)
      -> HS_DTRACE_PROBE4() マクロ

hotspot.monitor_contended_entered の probe 処理

(See: here and here for details)
-> ObjectMonitor::enter()
   -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp)
      -> (同上)

hotspot.monitor_contended_exit の probe 処理

(See: )
-> ObjectMonitor::ExitEpilog()
   -> DTRACE_MONITOR_PROBE() マクロ (@ hotspot/src/share/vm/runtime/objectMonitor.cpp)
      -> (同上)

処理の流れ (詳細)(Execution Flows : Details)


This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.