View Command

原文はこちら。
The original article was written by Erik Gahlin (Consulting Member of Technical Staff, Java Platform Group, Oracle).
https://egahlin.github.io/2023/05/30/views.html

JDK 21で、JFRに新たにviewコマンドが追加されます。これは集約されたイベントデータをシェルで表示するものです。このコマンドを使って、アプリケーションに関する情報を表示できます。このとき記録ファイルをダンプしたり、JDK Mission Controlを開いたりする必要はありません。

JDK Mission Control (JMC)
https://jdk.java.net/jmc/

$ jcmd 1739 JFR.view hot-methods

                         Java methods that execute the most

Method                                                        Samples Percent
------------------------------------------------------------- ------- -------
sun.java2d.marlin.Renderer._endRendering(...)                    1659  42.99%
sun.java2d.marlin.MarlinTileGenerator.getAlphaRLE(...)            592  15.34%
sun.java2d.marlin.MarlinCache.copyAARowRLE_WithBlockFlags(...)    447  11.58%
sun.java2d.marlin.MarlinCache.copyAARowNoRLE(...)                 246   6.37%
sun.java2d.marlin.Renderer.addLine(...)                            89   2.31%
sun.java2d.marlin.Renderer.copyAARow(...)                          86   2.23%
sun.java2d.marlin.ArrayCacheInt.fill(...)                          73   1.89%
...

このコマンドを利用するには、まず記録を開始します。

$ java -XX:StartFlightRecording -jar my.jar

アプリケーション実行中に、jcmdツールを使って実行中の全てのJavaプロセスをリスト表示できます。

The jcmd Command
https://docs.oracle.com/en/java/javase/20/docs/specs/man/jcmd.html

$ jcmd  
37417 my.jar
37418 jdk.jcmd/sun.tools.jcmd.JCmd

PIDやjar/classファイル名をJFR.viewと表示すべきビュー名を共に利用して情報を表示します。以下はその例です。

$ jcmd 37417 JFR.view allocation-by-site

                                     Allocation by Site

Method                                                  Allocation Pressure
------------------------------------------------------- -------------------
java.lang.StringUTF16.compress(char[], int, int)                     37.50%
java.lang.Integer.valueOf(int)                                       13.75%
spec.jbb.infra.Util.TransactionLogBuffer.getLine(...)                 9.22%
java.math.BigDecimal.valueOf(long, int)                               8.92%
spec.jbb.CustomerReportTransaction.process(...)                       7.55%
java.math.BigDecimal.layoutChars(boolean)                             5.71%
...

allocation-by-siteビューは、JDK 16で追加されたjdk.ObjectAllocationSampleイベントを基に生成されるものです。ビュー名を指定しなければ、利用可能な全てのニューを確認できます。JDK 21では70個の事前定義済みのビューが付属しており、将来のリリースではさらに追加される予定です。これらのビューはJava virtual machine、Environment、そしてApplicationの3カテゴリに分類されています。

$ jcmd 37417 JFR.view
...

Java virtual machine views:
 class-modifications       gc-concurrent-phases longest-compilations   
 compiler-configuration    gc-configuration     native-memory-committed
 compiler-phases           gc-cpu-time          native-memory-reserved 
 compiler-statistics       gc-pause-phases      safepoints             
 deoptimizations-by-reason gc-pauses            tlabs                  
 deoptimizations-by-site   gc-references        vm-operations          
 gc                        heap-configuration  

Environment views:
 active-recordings        cpu-information       jvm-flags          
 active-settings          cpu-load              native-libraries   
 container-configuration  cpu-load-samples      network-utilization
 container-cpu-throttling cpu-tsc               recording          
 container-cpu-usage      environment-variables system-information 
 container-io-usage       events-by-count       system-processes   
 container-memory-usage   events-by-name        system-properties  

Application views:
 allocation-by-class   exception-count       native-methods       
 allocation-by-site    file-reads-by-path    object-statistics    
 allocation-by-thread  file-writes-by-path   pinned-threads       
 class-loaders         finalizers            socket-reads-by-host 
 contention-by-address hot-methods           socket-writes-by-host
 contention-by-class   latencies-by-type     thread-allocation    
 longest-class-loading thread-count         
 contention-by-thread  memory-leaks-by-class thread-cpu-load      
 exception-by-message  memory-leaks-by-site  thread-start         
 exception-by-site     modules       

デフォルトでは、ビューは直近10分以内のデータ32MBを範囲としますが、カスタムの時間範囲を設定することもできます。設定には、maxagemaxsizeというパラメータを使用します。これらは、JFR.dumpコマンドのmaxagemaxsizeパラメータと同様の働きをします。

$ jcmd my.jar JFR.view maxage=1h maxsize=2000MB gc-pauses

GC Pauses
---------

Total Pause Time: 2,93 s

Number of Pauses: 272

Minimum Pause Time: 0,471 ms

Median Pause Time: 7,82 ms

Average Pause Time: 10,8 ms

P90 Pause Time: 10,2 ms

P95 Pause Time: 20,9 ms

P99 Pause Time: 256 ms

P99.9% Pause Time: 256 ms

Maximum Pause Time: 256 ms

出力フォーマットはwidthcell-heighttruncateというパラメータで制御できます。widthパラメータは利用する最大文字数(例えば120)を設定します。設定しない場合は、テーブルの大きさは自動的に調整されます。

cell-heightパラメータは表のセル内で使用する行数を指定します。大抵のビューの場合、デフォルトは1ですが、文字が収まらない場合には1より大きな値を設定することもできます。このオプションは複数行のスタックトレースを表示する際に特に有用です。

最後に、truncateパラメータをbeginまたはendに設定すると、文字あふれ時に最初もしくは最後の文字を省略するかどうかを決定できます。デフォルトでは、末尾で文字を切り捨てます。

$ jcmd my.jar JFR.view cell-height=3 truncate=beginning width=80 system-processes

                                System Processes

First Observed Last Observed PID   Command Line                                
-------------- ------------- ----- --------------------------------------------
13:22:57       13:24:29      13028 C:\Program Files (x86)\Intel\Intel(R) Rapid 
                                   Storage Technology enterprise\IAStorIcon.exe
13:22:57       13:24:29      16200 C:\Program Files\Git\git-bash.exe           
13:22:57       13:24:29      7232  C:\Program Files\Microsoft Visual Studio\202
                                   2\Enterprise\Common7\IDE\PerfWatson2.exe    
13:22:57       13:24:29      18216 C:\Program Files\Microsoft Visual Studio\202
                                   2\Enterprise\Common7\IDE\VC\vcpackages\x86\V
                                   CPkgSrv.exe                                 
13:22:57       13:24:29      8536  C:\Program Files\Microsoft Visual Studio\202
                                   2\Enterprise\Common7\IDE\devenv.exe         
13:22:57       13:24:29      15228 C:\Program Files\Microsoft Visual Studio\202
                                   2\Enterprise\Common7\ServiceHub\Hosts\Servic
                                   eHub.Host.CLR.AnyCPU\ServiceHub.Host.CLR.exe
13:22:57       13:24:29      14128 ...es\Microsoft Visual Studio\2022\Enterpris
                                   e\Common7\ServiceHub\Hosts\ServiceHub.Host.C
                                   LR.AnyCPU\ServiceHub.TestWindowStoreHost.exe

bin/jfrツールを使えば、viewコマンドは記録ファイルに対しても利用できます。

The jfr Command
https://docs.oracle.com/en/java/javase/20/docs/specs/man/jfr.html

ファイル名を-XX:StartFlightRecordingオプションで設定すればファイルが作成されます。JVMが終了すると、記録コンテンツをファイルに書き出します。

viewではなく、JFRイベント名を指定できます。以下の例は、カスタムイベントをjdk.jfrイベントAPIを使って作成しています。

Event (Java SE 20 & JDK 20)
https://docs.oracle.com/en/java/javase/20/docs/api/jdk.jfr/jdk/jfr/Event.html

レンダリング出力における列ヘッダーはLabelアノテーションから、バイト・フォーマットはDataAmountアノテーションから取得します。

Label (Java SE 20 & JDK 20)
https://docs.oracle.com/en/java/javase/20/docs/api/jdk.jfr/jdk/jfr/Label.html
DataAmount (Java SE 20 & JDK 20)
https://docs.oracle.com/en/java/javase/20/docs/api/jdk.jfr/jdk/jfr/DataAmount.html

import jdk.jfr.*;

public class Example {

  @Name("example.FreeMemory")
  @Label("Free Memory")
  static class FreeMemoryEvent extends Event {
    @Description("An approximation of the amount of memory available for allocation")
    @Label("Free Memory")
    @DataAmount(DataAmount.BYTES)
    long free;
  }

  public static void main(String... args) throws Exception {
    for(int i = 0; i < 3; i++) {
      checkFreeMemory();
      Thread.sleep(1000);
    }
  }

  public static void checkFreeMemory() {
    FreeMemoryEvent event = new FreeMemoryEvent();
    event.begin();
    event.free = Runtime.getRuntime().freeMemory();
    event.commit();
  }
}

プログラムを実行し、イベントを表示します。

$ java -XX:StartFlightRecording:filename=recording.jfr Example.java
$ jfr view --cell-height 2 FreeMemory recording.jfr

                                  Free Memory

Start Time  Duration Event Thread     Stack Trace                   Free Memory
---------- --------- ---------------- ----------------------------- -----------
12:25:29   0,0213 ms main             Example.checkFreeMemory()        240,7 MB
                                      Example.main(String[])                   
12:25:30   0,0114 ms main             Example.checkFreeMemory()        238,0 MB
                                      Example.main(String[])                   
12:25:31   0,0218 ms main             Example.checkFreeMemory()        237,7 MB
                                      Example.main(String[])                   

どのイベントが記録に保持されているかを確認するには、summaryコマンドを使います。

$ jfr summary recording.jfr

ファイルを読むパーサーはビューを構成するイベントのみをパースするため、ほとんどの場合で処理時間が短くて済みます。内部的には、ビューはクエリ言語でできています。ビューを構成するクエリを見るには、--verboseパラメータを指定します。

$ jfr view --verbose gc recording.jfr

                                  Garbage Collections

Start        GC ID Type                     Heap Before GC Heap After GC  Longest Pause
(startTime) (gcId) (eventType.label)            (heapUsed)    (heapUsed) (longestPause)
----------- ------ ------------------------ -------------- ------------- --------------
13:16:44         0 Young Garbage Collection       409,7 MB        3,1 MB        10,0 ms
13:16:44         1 Old Garbage Collection           3,1 MB        2,6 MB        21,8 ms
13:16:45         2 Young Garbage Collection       330,4 MB        3,9 MB        1,40 ms
13:16:45         3 Old Garbage Collection           3,9 MB        3,5 MB        32,1 ms
13:16:45         4 Young Garbage Collection         3,5 MB        3,5 MB       0,471 ms
13:16:45         5 Old Garbage Collection           3,5 MB        3,5 MB        20,0 ms
13:16:58         6 Young Garbage Collection         2,0 GB       33,0 MB        29,4 ms
...


COLUMN 'Start', 'GC ID', 'Type', 'Heap Before GC', 'Heap After GC', 'Longest Pause'
FORMAT none, none, missing:Unknown, none, none, none SELECT G.startTime, gcId,
[Y|O].eventType.label, B.heapUsed, A.heapUsed, longestPause FROM GarbageCollection AS G,
GCHeapSummary AS B, GCHeapSummary AS A, OldGarbageCollection AS O,
YoungGarbageCollection AS Y WHERE B.when = 'Before GC' AND A.when = 'After GC' GROUP BY
gcId ORDER BY G.startTime

上記の例では、以下の4種類のイベント

  • jdk.GarbageCollection
  • jdk.GCHeapSummary
  • jdk.YoungGarbageCollection
  • jdk.OldGarbageCollection

でビューが構成されていて、これらのイベントをGROUP BY句内でgcIdを使用して結合しています。クエリ言語はOpenJDKのエンジニアがビューを定義するのを簡素化するためのものです。現在は実験的なものですが、将来的には、エンドユーザーにも公開されるかもしれません。

新しいviewコマンドを試すには、JDK 21のアーリーアクセスビルドをダウンロードしてください。

OpenJDK JDK 21 Early-Access Builds
https://jdk.java.net/21/

Command-Line Reference

jfr view [--verbose]
         [--width <integer>]
         [--truncate <mode>]
         [--cell-height <integer>]
         <view>
         <file>

  --verbose               Displays the query that makes up the view

  --width <integer>       The width of the view in characters. Default value depends on the view

  --truncate <mode>       How to truncate content that exceeds space in a table cell.
                          Mode can be 'beginning' or 'end'. Default value is 'end'

  --cell-height <integer> Maximum number of rows in a table cell. Default value depends on the view

  <view>                  Name of the view or event type to display. See list below for
                          available views

  <file>                  Location of the recording file (.jfr)




jcmd <pid> JFR.view [options]

Options:

cell-height   (Optional) Maximum number of rows in a table cell. (INTEGER, no default value)
   
maxage        (Optional) Length of time for the view to span. (INTEGER followed by  
              's' for seconds 'm' for minutes or 'h' for hours, default value is 10m)
   
maxsize       (Optional) Maximum size for the view to span in bytes if one of
              the following suffixes is not used: 'm' or 'M' for megabytes OR
              'g' or 'G' for gigabytes. (STRING, default value is 32MB)

truncate      (Optional) How to truncate content that exceeds space in a table cell.
              Mode can be 'beginning' or 'end'. (STRING, default value 'end')

verbose       (Optional) Displays the query that makes up the view.
              (BOOLEAN, default value false)

<view>        (Mandatory) Name of the view or event type to display.
              See list below for available views. (STRING, no default value)

width         (Optional) The width of the view in characters
              (INTEGER, no default value)

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください