分析命令列工具

GraalVM 的分析命令列工具可協助您透過分析 CPU 和記憶體使用率來最佳化程式碼。

大多數應用程式在 20% 的程式碼中花費 80% 的執行時間。因此,為了最佳化程式碼,必須了解應用程式將時間花費在哪裡。在本節中,我們將使用範例應用程式來示範 GraalVM 提供的三個主要分析功能:CPU 追蹤器、CPU 取樣器和記憶體追蹤器。

此範例應用程式使用基於埃拉托斯特尼篩法演算法的基本質數計算器。

  1. 將下列程式碼複製到名為 primes.js 的新檔案中

     class AcceptFilter {
         accept(n) {
             return true
         }
     }
    
     class DivisibleByFilter {
         constructor(number, next) {
             this.number = number;
             this.next = next;
         }
    
         accept(n) {
             var filter = this;
             while (filter != null) {
                 if (n % filter.number === 0) {
                     return false;
                 }
                 filter = filter.next;
             }
             return true;
         }
     }
    
     class Primes {
         constructor() {
             this.number = 2;
             this.filter = new AcceptFilter();
         }
    
         next() {
             while (!this.filter.accept(this.number)) {
                 this.number++;
             }
             this.filter = new DivisibleByFilter(this.number, this.filter);
             return this.number;
         }
     }
    
     var primes = new Primes();
     var primesArray = [];
     for (let i = 0; i < 5000; i++) {
         primesArray.push(primes.next());
     }
     console.log(`Computed ${primesArray.length} prime numbers. ` +
                 `The last 5 are ${primesArray.slice(-5)}.`);
    
  2. 執行 js primes.js。範例應用程式應列印如下輸出
     js primes.js
     Computed 5000 prime numbers. The last 5 are 48563,48571,48589,48593,48611.
    

    此程式需要一些時間來計算。接下來,您將檢查時間花費在哪裡。

  3. 執行 js --cpusampler primes.js 以啟用 CPU 取樣。CPU 取樣器應列印範例應用程式的如下輸出
     js --cpusampler primes.js
    
     Computed 5000 prime numbers. The last 5 are 48563,48571,48589,48593,48611.
     ----------------------------------------------------------------------------------------------
     Sampling Histogram. Recorded 250 samples with period 10ms.
       Self Time: Time spent on the top of the stack.
       Total Time: Time spent somewhere on the stack.
     ----------------------------------------------------------------------------------------------
     Thread[main,5,main]
      Name       ||             Total Time    ||              Self Time    || Location
     ----------------------------------------------------------------------------------------------
      accept     ||             2150ms  86.0% ||             2150ms  86.0% || primes.js~13-22:191-419
      next       ||             2470ms  98.8% ||              320ms  12.8% || primes.js~31-37:537-737
      :program   ||             2500ms 100.0% ||               30ms   1.2% || primes.js~1-46:0-982
     ----------------------------------------------------------------------------------------------
    

    依預設,取樣器會為每個 JavaScript 函式列印執行時間長條圖。

    您可以使用 --cpusampler=flamegraph 選項要求以 SVG 格式產生火焰圖

     js --cpusampler=flamegraph primes.js
    

    它應該產生一個名為 flamegraph.svg 的檔案,其中包含如下內容

    Profiler Flamegraph

    您可以透過按一下元素來放大圖表。

    依預設,CPU 取樣會每 10 毫秒取樣一次。從結果中,我們可以看到大約 89% 的時間花費在 DivisibleByFilter.accept 函式中。

     accept(n) {
         var filter = this;
         while (filter != null) {
             if (n % filter.number === 0) {
                 return false;
             }
             filter = filter.next;
         }
         return true;
     }
    

    如需詳細資訊,請參閱這篇部落格文章

    現在使用 CPU 追蹤器來收集每個陳述式的執行計數

  4. 執行 js primes.js --cputracer --cputracer.TraceStatements --cputracer.FilterRootName=*accept 以收集結尾為 accept 的方法中所有陳述式的執行計數
     js primes.js --cputracer --cputracer.TraceStatements --cputracer.FilterRootName=accept
     Computed 5000 prime numbers. The last 5 are 48563,48571,48589,48593,48611.
     -----------------------------------------------------------------------------------------
     Tracing Histogram. Counted a total of 468336895 element executions.
       Total Count: Number of times the element was executed and percentage of total executions.
       Interpreted Count: Number of times the element was interpreted and percentage of total executions of this element.
       Compiled Count: Number of times the compiled element was executed and percentage of total executions of this element.
     -----------------------------------------------------------------------------------------
      Name     |          Total Count |    Interpreted Count |       Compiled Count | Location
     -----------------------------------------------------------------------------------------
      accept   |     234117338  50.0% |        365660   0.2% |     233751678  99.8% | primes.js~15:245-258
      accept   |     117053670  25.0% |        182582   0.2% |     116871088  99.8% | primes.js~16-18:275-348
      accept   |     117005061  25.0% |        181001   0.2% |     116824060  99.8% | primes.js~19:362-381
      accept   |         53608   0.0% |          1829   3.4% |         51779  96.6% | primes.js~14:211-227
      accept   |         53608   0.0% |          1829   3.4% |         51779  96.6% | primes.js~13-22:191-419
      accept   |         48609   0.0% |          1581   3.3% |         47028  96.7% | primes.js~17:322-334
      accept   |          4999   0.0% |           248   5.0% |          4751  95.0% | primes.js~21:402-413
      accept   |             1   0.0% |             1 100.0% |             0   0.0% | primes.js~2-4:25-61
      accept   |             1   0.0% |             1 100.0% |             0   0.0% | primes.js~3:45-55
     -----------------------------------------------------------------------------------------
    

    輸出顯示每個陳述式的執行計數器,而不是計時資訊。追蹤長條圖通常可深入了解需要最佳化的演算法的行為。

  5. 執行 js primes.js --experimental-options --memtracer 以顯示原始程式碼位置和已報告配置的計數。請注意,用於擷取配置的記憶體追蹤器工具目前是 GraalVM 中的實驗性功能。因此,--memtracer 必須以 --experimental-options 命令列選項作為前綴。
     js primes.js --experimental-options --memtracer
     Computed 5000 prime numbers. The last 5 are 48563,48571,48589,48593,48611.
     ------------------------------------------------------------
     Location Histogram with Allocation Counts. Recorded a total of 5007 allocations.
       Total Count: Number of allocations during the execution of this element.
       Self Count: Number of allocations in this element alone (excluding sub calls).
    --------------------------------------------------------
     Name     |      Self Count |     Total Count | Location
    --------------------------------------------------------
     next     |     5000  99.9% |     5000  99.9% | primes.js~31-37:537-737
     :program |        6   0.1% |     5007 100.0% | primes.js~1-46:0-982
     Primes   |        1   0.0% |        1   0.0% | primes.js~25-38:424-739
    --------------------------------------------------------
    

    此輸出顯示每個函式記錄的配置數量。對於計算的每個質數,程式會在 DivisibleByFilternext 中配置一個物件,並在 constructor 中配置一個物件。配置的記錄與編譯器是否可以消除它們無關。

    GraalVM 編譯器在最佳化配置方面特別強大,並且可以將配置推送到不常發生的分支中,以提高執行效能。GraalVM 團隊計劃未來將有關記憶體最佳化的資訊新增至記憶體追蹤器中。

工具選項 #

在所有訪客語言啟動器中使用 --help:tools 選項來顯示 CPU 取樣器、CPU 追蹤器和記憶體追蹤器的參考資訊。目前可用的選項集如下。

CPU 取樣器選項 #

  • --cpusampler=true|false|<Output>:啟用/停用 CPU 取樣器,或使用特定輸出啟用 - 由 Output 選項指定(預設:false)。使用此選項選擇輸出預設為將輸出列印到標準輸出,火焰圖除外,該火焰圖會列印到 flamegraph.svg 檔案。
  • --cpusampler.Delay=<ms>:延遲取樣這麼多毫秒(預設:0)。
  • --cpusampler.FilterFile=<filter>:來源檔案路徑的萬用字元篩選器。(例如,program.sl)(預設:無篩選器)。
  • --cpusampler.FilterLanguage=<languageId>:僅分析具有指定 ID 的語言。(例如,js)(預設:分析所有)。
  • --cpusampler.FilterMimeType=<mime-type>:僅分析具有指定 mime 類型的語言。(例如,application/javascript)(預設:分析所有)
  • --cpusampler.FilterRootName=<filter>:程式根的萬用字元篩選器。(例如,Math.*)(預設:無篩選器)。
  • --cpusampler.GatherAsyncStackTrace=true|false:嘗試收集每個取樣的非同步堆疊追蹤元素(預設:true)。停用此選項可能會減少取樣的額外負荷。
  • --cpusampler.GatherHitTimes:儲存每個取樣的時間戳記。
  • --cpusampler.MinSamples=[0, inf):如果元素的取樣少於此值,則從輸出中移除元素(預設:0)
  • --cpusampler.Output=histogram|calltree|json|flamegraph:將輸出格式指定為下列其中之一:histogram、calltree、json 或 flamegraph(預設:histogram)。
  • --cpusampler.OutputFile=<path>:將輸出儲存到指定的檔案。輸出預設會列印到輸出串流。
  • --cpusampler.Period=<ms>:取樣堆疊的間隔(毫秒)(預設:10)
  • --cpusampler.SampleContextInitialization:啟用在內容初始化期間執行的程式碼取樣
  • --cpusampler.ShowTiers=true|false|0,1,2:指定是否顯示項目的編譯資訊。您可以指定 'true' 以顯示所有編譯資訊,指定 'false' 以不顯示任何資訊,或指定以逗號分隔的編譯層清單。注意:直譯器視為第 0 層。(預設:false)
  • --cpusampler.StackLimit=[1, inf):最大堆疊元素的最大數量(預設:10000)。
  • --cpusampler.SummariseThreads:將輸出列印為所有「每個執行緒」設定檔的摘要。

CPU 追蹤器選項 #

  • --cputracer:啟用 CPU 追蹤器(預設:false)。
  • --cputracer.FilterFile=<filter>:來源檔案路徑的萬用字元篩選器。(例如,program.sl)(預設:無篩選器)。
  • --cputracer.FilterLanguage=<languageId>:僅分析具有指定 ID 的語言。(例如,js)(預設:無篩選器)。
  • --cputracer.FilterMimeType=<mime-type>:僅分析具有 mime 類型的語言。(例如,application/javascript)(預設:無篩選器)。
  • --cputracer.FilterRootName=<filter>:程式根的萬用字元篩選器。(例如,Math.*)(預設:無篩選器)。
  • --cputracer.Output=histogram|json:以「長條圖」或「json」形式列印輸出(預設:長條圖)。
  • --cputracer.OutputFile=<path>:將輸出儲存到指定的檔案。輸出預設會列印到標準輸出串流。
  • --cputracer.TraceCalls:在追蹤時擷取呼叫(預設:false)。
  • --cputracer.TraceRoots=true|false:在追蹤時擷取根(預設:true)。
  • --cputracer.TraceStatements:在追蹤時擷取陳述式(預設:false)。

記憶體追蹤器選項 #

記憶體追蹤器工具目前是一個實驗性工具。請務必將 --experimental-options 旗標作為前綴以啟用 --memtracer

  • --memtracer:啟用記憶體追蹤器(預設:false)。
  • --memtracer.FilterFile=<filter>:來源檔案路徑的萬用字元篩選器。(例如,program.sl)(預設:無篩選器)。
  • --memtracer.FilterLanguage=<languageId>:僅分析具有指定 ID 的語言。(例如 js)(預設:無篩選器)。
  • --memtracer.FilterMimeType=<mime-type>:僅分析具有 mime 類型的語言。(例如,application/javascript)。(預設:無篩選器)
  • --memtracer.FilterRootName=<filter>:程式根的萬用字元篩選器。(例如,Math.*)(預設:無篩選器)。
  • --memtracer.Output=typehistogram|histogram|calltree:以「typehistogram」、「長條圖」或「呼叫樹狀結構」形式列印輸出。(預設:長條圖)
  • --memtracer.StackLimit=[1, inf):最大堆疊元素的最大數量。(預設:10000)
  • --memtracer.TraceCalls:在追蹤時擷取呼叫。(預設:false)
  • --memtracer.TraceRoots=true|false:在追蹤時擷取根。(預設:true)
  • --memtracer.TraceStatements:在追蹤時擷取陳述式(預設:false)。

與我們聯絡