- 適用於 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 特殊化
- 基於多語言 API 的 TCK
- Truffle 編譯佇列方法
- Truffle 程式庫指南
- Truffle AOT 概觀
- Truffle AOT 編譯
- 輔助引擎快取
- Truffle 語言安全點教學
- 單態化
- 分割演算法
- 單態化使用案例
- 向執行時間回報多型特殊化
輔助引擎快取
以下文件描述 GraalVM 的輔助引擎快取如何運作。
此功能僅適用於 Oracle GraalVM。在 GraalVM 社群版中,這些選項不可用。
簡介 #
Truffle 客戶語言程式的預熱可能需要相當長的時間。預熱包含每次執行程式時重複進行的工作,直到達到最佳效能為止。這包括
- 將客戶應用程式載入並剖析為 Truffle AST 資料結構。
- 在直譯器中執行和分析客戶應用程式。
- 將 AST 編譯為機器碼。
在單一作業系統程序中,可以透過指定明確的引擎來共用預熱期間執行的工作。這要求語言實作停用與內容相關的最佳化,以避免在共用程式碼的內容之間進行反最佳化。輔助引擎快取建立在停用與內容相關的最佳化的機制之上,並增加了將具有 AST 和最佳化機器碼的引擎保存到磁碟的功能。這樣,在新程序的首次應用程式內容中,可以大幅減少預熱期間執行的工作。
我們使用 SVM 輔助映像功能將必要的資料結構保存並載入到磁碟。保存映像可能需要相當長的時間,因為需要執行編譯。但是,載入的設計盡可能快速,通常幾乎是瞬時的。這大幅減少了應用程式的預熱時間。
入門 #
從 Oracle GraalVM 安裝開始,您首先需要使用輔助引擎快取功能 (重新) 建置映像。例如,可以透過新增輔助引擎快取功能來重新建置 JavaScript 映像
graalvm/bin/native-image --macro:js-launcher -H:+AuxiliaryEngineCache -H:ReservedAuxiliaryImageBytes=1073741824
--macro
引數值取決於客戶語言。預設情況下,最多可使用 1GB 的輔助映像。可以根據需要增加或減少最大大小。保留的位元組數量實際上不會影響應用程式所消耗的記憶體。在未來版本中,當使用 --macro:js-launcher
巨集時,預設會啟用輔助引擎快取。
重新建置 JavaScript 啟動器後,此功能的使用方式如下
建立新的檔案 fib.js
function fib(n) {
if (n == 1 || n == 2) {
return 1;
}
return fib(n - 1) + fib(n - 2);
}
console.log(fib(32))
為了將分析執行時的引擎保存到磁碟,請使用以下命令列
graalvm/bin/js --experimental-options --engine.TraceCache=true --engine.CacheStore=fib.image fib.js
–engine.TraceCache=true
選項是選用的,可讓您查看正在發生的情況。
輸出如下
[engine] [cache] No load engine cache configured.
2178309
[engine] [cache] Preparing engine for store (compile policy hot)...
[engine] [cache] Force compile targets mode: hot
[engine] [cache] Prepared engine in 1 ms.
[engine] [cache] Persisting engine for store ...
[engine] [cache] Persisted engine in 20 ms.
[engine] [cache] Detecting changes (update policy always)...
[engine] [cache] New image contains 1 sources and 82 function roots.
[engine] [cache] Always persist policy.
[engine] [cache] Writing image to fib.image...
[engine] [cache] Finished writing 1,871,872 bytes in 4 ms.
現在可以使用以下命令從磁碟載入引擎
graalvm/bin/js --experimental-options --engine.TraceCache --engine.CacheLoad=fib.image fib.js
這會印出
[engine] [cache] Try loading image './fib.image'...
[engine] [cache] Loaded image in 0 ms. 1,871,872 bytes 1 sources 82 roots
[engine] [cache] Engine from image successfully patched with new options.
2178309
[engine] [cache] No store engine cache configured.
由於不需要預熱應用程式,因此應用程式的執行時間應大幅縮短。
用法 #
可以使用以下選項控制快取儲存和載入作業
--engine.Cache=<path>
從path
載入快取的引擎並儲存到path
。--engine.CacheStore=<path>
將快取的引擎儲存到path
。--engine.CacheLoad=<path>
從path
載入快取的引擎。--engine.CachePreinitializeContext=<boolean>
在映像中預先初始化新的內容 (預設為true
)。--engine.TraceCache=<boolean>
啟用偵錯輸出。--engine.TraceCompilation=<boolean>
印出強制編譯。
當使用 --engine.CacheCompile=<policy>
選項儲存映像時,可能會強制編譯根節點。支援的策略為
none
:不會保存任何編譯,而且現有的編譯將失效。compiled
:不會強制執行任何編譯,但會保存已完成的編譯。hot
:所有已開始的編譯都會完成,然後保存。(預設)aot
:所有已開始且可 AOT 編譯的根節點都會強制編譯並保存。executed
:所有已執行和可 AOT 編譯的根節點都會強制編譯。
依預設,編譯佇列中所有已開始的編譯都會完成,然後保存。函式根節點是否可 AOT 編譯由語言決定。語言會透過實作 RootNode.prepareForAOT()
來支援 AOT。
如果同時設定載入和儲存作業,可以使用 --engine.UpdatePolicy=<policy>
選項指定更新策略。可用的策略為
always
一律保存。newsource
如果載入先前載入的映像中未包含的新來源,則儲存。newroot
如果載入先前載入的映像中未包含的新根節點,則儲存。never
永不保存。
已知限制 #
-
通常,可以保存的應用程式種類沒有任何限制。如果語言支援共用內容策略,則輔助引擎快取應該有效。如果語言不支援,則不會保存任何資料。
-
保存的輔助引擎映像只能與建立它的相同 SVM 原生映像一起使用。將引擎映像與任何其他原生映像搭配使用將會失敗。
-
每個原生映像隔離區只能有一個作用中的輔助映像。嘗試同時載入多個輔助映像將會失敗。目前,輔助映像也無法卸載,但計劃在未來解除此限制。
安全性考量 #
所有保存到磁碟的資料都只代表程式碼,不包含應用程式內容特定的資料,例如全域變數。但是,分析的 AST 和程式碼可能包含在 Truffle AST 中執行的最佳化成品。例如,執行時間字串可能用於最佳化,因此會保存到引擎映像。
NativeImage 上的開發和偵錯 #
以下是一些在 NativeImage 上執行時,對於偵錯輔助引擎快取非常有用的選項
-XX:+TraceAuxiliaryImageClassHistogram
在保存時,印出映像中包含的所有物件的類別直方圖。-XX:+TraceAuxiliaryImageReferenceTree
在保存時,印出映像中包含的所有物件的類別參考樹狀結構。
HotSpot 上的開發和偵錯 #
在 HotSpot 上偵錯與輔助映像相關的語言實作問題可能會很有用。在 JVM 模式下的 Oracle GraalVM 上,我們有其他選項可用於協助偵錯此功能的問題:由於 HotSpot 不支援在 HotSpot 上儲存部分堆積,因此這些偵錯功能在 HotSpot 上無法運作。
--engine.DebugCacheStore=<boolean>
準備快取的引擎,並將其儲存到靜態欄位,而不是寫入磁碟。--engine.DebugCacheLoad=<boolean>
準備引擎以使用儲存在靜態欄位中的引擎,而不是從磁碟讀取。--engine.DebugCacheCompile=<boolean>
用於強制在保存引擎之前編譯已執行呼叫目標的策略。這支援與--engine.CacheCompile
相同的值。--engine.DebugCacheTrace=<boolean>
啟用引擎快取偵錯功能的追蹤。
例如
js --experimental-options --engine.TraceCompilation --engine.DebugCacheTrace --engine.DebugCacheStore --engine.DebugCacheCompile=executed fib.js
印出以下輸出
[engine] opt done fib |ASTSize 32 |Time 231( 147+84 )ms |Tier Last |DirectCallNodes I 6/D 8 |GraalNodes 980/ 1857 |CodeSize 7611 |CodeAddress 0x10e20e650 |Source fib.js:2
2178309
[engine] [cache] Preparing debug engine for storage...
[engine] [cache] Force compile targets mode: executed
[engine] [cache] Force compiling 4 roots for engine caching.
[engine] opt done @72fa3b00 |ASTSize 3 |Time 211( 166+45 )ms |Tier Last |DirectCallNodes I 2/D 1 |GraalNodes 500/ 1435 |CodeSize 4658 |CodeAddress 0x10e26c8d0 |Source n/a
[engine] opt done :program |ASTSize 25 |Time 162( 123+39 )ms |Tier Last |DirectCallNodes I 1/D 1 |GraalNodes 396/ 1344 |CodeSize 4407 |CodeAddress 0x10e27fd50 |Source fib.js:1
[engine] opt done Console.log |ASTSize 3 |Time 26( 11+15 )ms |Tier Last |DirectCallNodes I 0/D 0 |GraalNodes 98/ 766 |CodeSize 2438 |CodeAddress 0x10e285710 |Source <builtin>:1
[engine] [cache] Stored debug engine in memory.
這可讓您快速迭代處理與編譯相關的問題,以及附加 Java 偵錯工具。可以使用 --vm.Xdebug --vm.Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
附加 Java 偵錯工具。
偵錯保存的引擎載入會比較困難,因為 HotSpot 不支援將引擎寫入磁碟。但是,可以使用多語言內嵌 API 在單元測試中模擬此使用案例。如需範例,請參閱 com.oracle.truffle.enterprise.test.DebugEngineCacheTest
類別。