輔助引擎快取

以下文件描述 GraalVM 的輔助引擎快取如何運作。

此功能僅適用於 Oracle GraalVM。在 GraalVM 社群版中,這些選項不可用。

簡介 #

Truffle 客戶語言程式的預熱可能需要相當長的時間。預熱包含每次執行程式時重複進行的工作,直到達到最佳效能為止。這包括

  1. 將客戶應用程式載入並剖析為 Truffle AST 資料結構。
  2. 在直譯器中執行和分析客戶應用程式。
  3. 將 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 類別。

與我們聯繫