- 適用於 JDK 23 的 GraalVM(最新版)
- 適用於 JDK 24 的 GraalVM(搶先體驗版)
- 適用於 JDK 21 的 GraalVM
- 適用於 JDK 17 的 GraalVM
- 封存
- 開發版本
- Truffle 語言實作框架
- Truffle 分支檢測
- 動態物件模型
- 靜態物件模型
- 解譯器程式碼的主機最佳化
- Truffle 函式內聯方法
- 分析 Truffle 解譯器
- Truffle Interop 2.0
- 語言實作
- 使用 Truffle 實作新語言
- Truffle 語言和檢測遷移至 Java 模組
- Truffle 原生函式介面
- 最佳化 Truffle 解譯器
- 選項
- 堆疊上置換
- Truffle 字串指南
- 特化直方圖
- 測試 DSL 特化
- 基於 Polyglot API 的 TCK
- Truffle 編譯佇列方法
- Truffle 程式庫指南
- Truffle AOT 概述
- Truffle AOT 編譯
- 輔助引擎快取
- Truffle 語言安全點教學
- 單態化
- 分割演算法
- 單態化使用案例
- 向執行階段報告多型特化
Truffle 分支檢測
在使用 Truffle 實作的語言中,AST 實作通常包含快速和慢速的執行路徑,通常基於一些條件,例如設定檔。這些執行路徑會組織成不同的條件分支。在這些情況下,通常有助於了解執行程式是否實際執行了這些執行路徑中的程式碼。
分支檢測功能會檢測目標方法中的 if
語句,以追蹤執行期間已採用哪些分支。分支檢測透過檢測分支並使用程式碼寫入全域表格來完成。每個分支在此表格中都有一個條目。當程式結束時,表格的內容會被解碼並以可讀的形式轉儲到標準輸出。
有幾個旗標可控制分支檢測的工作方式。這些旗標會指定為系統屬性
--compiler.InstrumentBranches
- 控制是否啟用檢測(true
或false
,預設為false
)--compiler.InstrumentFilter
- 過濾應執行檢測的方法(方法過濾語法,基本上是<package>.<class>.<method>[.<signature>]
)--compiler.InstrumentationTableSize
- 控制檢測位置的最大數量--compiler.InstrumentBranchesPerInlineSite
- 控制檢測是否為每個客座語言函式/編譯單元提供獨立的分支設定檔(預設為false
)。
使用範例 #
以下是如何在程式上啟用分支檢測的範例。
當使用檢測來偵測 Truffle 語言實作中熱門或不常使用的分支時,通常從尋找具有問題方法之語言節點開始。以下命令會執行 SimpleLanguage 的單元測試,並檢測所有 if
語句
mx --jdk jvmci sl --engine.BackgroundCompilation=false \
--compiler.InstrumentBranches \
'--compiler.InstrumentFilter=*.*.*' \
../truffle/truffle/com.oracle.truffle.sl.test/src/tests/LoopObjectDyn.sl
您會得到以下輸出
Execution profile (sorted by hotness)
=====================================
0: *****************************************************
1: **************************
com.oracle.truffle.sl.nodes.access.SLPropertyCacheNode.namesEqual(SLPropertyCacheNode.java:109) [bci: 120]
[0] state = IF(if=36054#, else=0#)
com.oracle.truffle.sl.nodes.controlflow.SLWhileRepeatingNode.executeRepeating(SLWhileRepeatingNode.java:102) [bci: 5]
[1] state = BOTH(if=18000#, else=18#)
此輸出表示在檔案 SLWhileRepeatingNode.java
中第 102 行的 if
語句中兩個分支都已造訪,並且在檔案 SLPropertyCacheNode.java
中第 109 行的 if
語句中只有 true
分支已造訪。但是,它並未說明,例如,此特定 SLPropertyCacheNode
節點是從何處使用 – 同一個 execute
方法可以從許多不同的 SimpleLanguage 節點呼叫,您可能希望區分這些發生情況。因此,請將每個內嵌位置旗標設定為 true
,並變更篩選器以僅關注 SLPropertyCacheNode
mx --jdk jvmci sl -Djdk.graal.TruffleBackgroundCompilation=false \
--compiler.InstrumentBranchesPerInlineSite \
--compiler.InstrumentBranches \
'--compiler.InstrumentFilter=*.SLPropertyCacheNode.*' \
../truffle/truffle/com.oracle.truffle.sl.test/src/tests/LoopObjectDyn.sl
這次您會得到更多輸出,因為方法 namesEqual
已在多個位置內嵌(每個位置都以其內嵌鏈表示)。以下輸出片段首先顯示具有 if
語句 ID 及其出現次數的直方圖。然後,它會顯示分支的確切呼叫堆疊和執行次數。例如,對於 [1]
,當從 executeRead
呼叫 namesEqual
時,true
分支會執行 18018
次。當從 executeWrite
([0]
) 呼叫 namesEqual
時,true
分支只執行 18
次
Execution profile (sorted by hotness)
=====================================
1: ***************************************
2: ***************************************
0:
3:
com.oracle.truffle.sl.nodes.access.SLPropertyCacheNode.namesEqual(SLPropertyCacheNode.java:109) [bci: 120]
com.oracle.truffle.sl.nodes.access.SLReadPropertyCacheNodeGen.executeRead(SLReadPropertyCacheNodeGen.java:76) [bci: 88]
com.oracle.truffle.sl.nodes.access.SLReadPropertyNode.read(SLReadPropertyNode.java:71) [bci: 7]
com.oracle.truffle.sl.nodes.access.SLReadPropertyNodeGen.executeGeneric(SLReadPropertyNodeGen.java:30) [bci: 35]
com.oracle.truffle.sl.nodes.SLExpressionNode.executeLong(SLExpressionNode.java:81) [bci: 2]
com.oracle.truffle.sl.nodes.expression.SLLessThanNodeGen.executeBoolean_long_long0(SLLessThanNodeGen.java:42) [bci: 5]
com.oracle.truffle.sl.nodes.expression.SLLessThanNodeGen.executeBoolean(SLLessThanNodeGen.java:33) [bci: 14]
com.oracle.truffle.sl.nodes.controlflow.SLWhileRepeatingNode.evaluateCondition(SLWhileRepeatingNode.java:133) [bci: 5]
com.oracle.truffle.sl.nodes.controlflow.SLWhileRepeatingNode.executeRepeating(SLWhileRepeatingNode.java:102) [bci: 2]
com.oracle.truffle.runtime.OptimizedOSRLoopNode.executeLoop(OptimizedOSRLoopNode.java:113) [bci: 61]
com.oracle.truffle.sl.nodes.controlflow.SLWhileNode.executeVoid(SLWhileNode.java:69) [bci: 5]
com.oracle.truffle.sl.nodes.controlflow.SLBlockNode.executeVoid(SLBlockNode.java:84) [bci: 37]
com.oracle.truffle.sl.nodes.controlflow.SLFunctionBodyNode.executeGeneric(SLFunctionBodyNode.java:81) [bci: 5]
com.oracle.truffle.sl.nodes.SLRootNode.execute(SLRootNode.java:78) [bci: 28]
[1] state = IF(if=18018#, else=0#)
...
com.oracle.truffle.sl.nodes.access.SLPropertyCacheNode.namesEqual(SLPropertyCacheNode.java:109) [bci: 120]
com.oracle.truffle.sl.nodes.access.SLWritePropertyCacheNodeGen.executeWrite(SLWritePropertyCacheNodeGen.java:111) [bci: 244]
com.oracle.truffle.sl.nodes.access.SLWritePropertyNode.write(SLWritePropertyNode.java:73) [bci: 9]
com.oracle.truffle.sl.nodes.access.SLWritePropertyNodeGen.executeGeneric(SLWritePropertyNodeGen.java:33) [bci: 47]
com.oracle.truffle.sl.nodes.access.SLWritePropertyNodeGen.executeVoid(SLWritePropertyNodeGen.java:41) [bci: 2]
com.oracle.truffle.sl.nodes.controlflow.SLBlockNode.executeVoid(SLBlockNode.java:84) [bci: 37]
com.oracle.truffle.sl.nodes.controlflow.SLFunctionBodyNode.executeGeneric(SLFunctionBodyNode.java:81) [bci: 5]
com.oracle.truffle.sl.nodes.SLRootNode.execute(SLRootNode.java:78) [bci: 28]
[0] state = IF(if=18#, else=0#)
...
Truffle 呼叫邊界檢測 #
Truffle 呼叫邊界檢測工具會檢測具有 TruffleCallBoundary
註解之方法的呼叫位置,並計算對這些方法的呼叫次數。它由以下一組旗標控制
--compiler.InstrumentBoundaries
- 控制是否啟用檢測(true
或false
,預設為false
)--compiler.InstrumentFilter
- 過濾應執行檢測的方法(方法過濾語法,基本上是<package>.<class>.<method>[.<signature>]
)--compiler.InstrumentationTableSize
- 控制檢測位置的最大數量--compiler.InstrumentBoundariesPerInlineSite
- 控制檢測是依每個 Truffle 邊界呼叫的宣告 (false
) 執行,還是依該呼叫位置內嵌的每個呼叫堆疊 (true
) 執行
此工具可與分支檢測工具一起使用。
假設您需要尋找經常發生的方法,但這些方法並未內嵌。識別 Truffle 呼叫邊界的通常步驟是先執行程式,並將 InstrumentBoundariesPerInlineSite
旗標設定為 false
,然後在識別出問題方法後,將該旗標設定為 true
,並設定 InstrumentFilter
以識別這些方法的特定呼叫堆疊。