現代處理器內建硬體效能計數器(HPC),可記錄指令數、Cache Miss、分支預測失敗等微架構事件。PAPI (Performance API) 提供跨平台標準介面存取 HPC。本文結合 JVMTI (JVM Tool Interface),實現對 Java 線程級硬體事件的精準監測。
PAPI_TOT_INS 總指令數),可能對應多個 Native Event。
PAPI_library_init → PAPI_create_eventset → PAPI_add_event(s)
→ PAPI_start → PAPI_read/stop → PAPI_cleanup_eventset → PAPI_destroy_eventset → PAPI_shutdown
範例代碼展示計算程式區段總指令數:
EventSet = PAPI_NULL;
PAPI_create_eventset(&EventSet);
PAPI_add_event(EventSet, PAPI_TOT_INS);
PAPI_start(EventSet);
PAPI_read(EventSet, values1);
// workload
PAPI_stop(EventSet, values2);
values[0] = values2[0] - values1[0];
Java 多線程共享 HPC,需逐線程綁定 Event Set:
PAPI_thread_init 初始化線程支援PAPI_attach(eventset, thread_id) 綁定事件組至指定線程PAPI_detach 解除綁定以動態庫形式載入 JVM,訂閱關鍵事件並回調 PAPI API:
| JVMTI 事件 | 回調內容 | |
|---|---|---|
| VMInit | PAPI_library_init, PAPI_thread_init | |
| VMDeath | PAPI_shutdown | |
| ThreadStart | create_eventset, add_event, attach, start, read | |
| ThreadEnd | stop, detach, cleanup, destroy |
| 計數器 | 事件 | 描述 |
|---|---|---|
| 0 | PM_1PLUS_PPC_CMPL | 至少 1 條 PPC 指令完成的週期 |
| 1 | PM_GCT_EMPTY_CYC | 流水線空閒週期 |
| 2 | PM_GRP_CMPL | 指令群組完成週期 |
| 3 | PM_CYC | 處理器週期 |
| 4 | PM_RUN_INST_CMPL | 執行完成指令數 |
| 5 | PM_RUN_CYC | RUN 狀態週期 |
javac Fibonacci.java
gcc -shared -lpapi -lpthread -o libPAPI_Agent.so -I $JAVA_HOME/include PAPI_Agent.c
java -agentlib:PAPI_Agent Fibonacci
Thread name: main Counter value[0] = [22140488] ... Thread name: Thread-1 Counter value[0] = [7259] ...
應用線程 Thread-1 CPI = 2.58,流水線正常 14%,空閒 15%。
結合 PAPI 底層介面與 JVMTI,可在不修改 Java 應用程式碼前提下,獲得線程級硬體執行特徵,為效能調優提供可靠依據。