やっぱり Sun がスキ! : Weblog やっぱり Sun がスキ!

やっぱり Sun がスキ!

http://blogs.sun.com/yappri/date/20090421 2009年 4月 21日 火曜日

mpstat コマンドの読み方

はじめに

先日 Solaris の vmstat コマンドについての記事 を書きましたが、今回は mpstat コマンドについて解説したいと思います。最近は Linux にも mpstat コマンドがありますが、Solaris の mpstat とは出力内容や実装が大きく異なりますので注意が必要です。

mpstat について

CPU がボトルネックになっている可能性がある場合は mpstat を使用する事で CPU の使用状況を調べる事が出来ます。vmstat でも CPU の統計情報を見る事が可能ですが、mpstat ではプロセッサ毎の統計情報が見られるため、より細かな分析が可能です。

mpstat は vmstat と同様に kstat のデータを集計しています。mpstat のソースコードは以下の URL にあります。本体のソースコードは 500 行程度しかありません。

mpstat のお勧めのオプション

インターバルのみ

 % mpstat 1

オプションはインターバルのみ指定して下さい。より正確な負荷状況を見る為、長期間の性能監視の場合でもインターバルは 1 秒にする事をお勧めします。ログとして保存する場合も、今時のマシンであればファイルのサイズはそれ程気にしなくて良いと思います。

mpstat の出力例

mpstat の出力はヘッダに加えて CPU 毎に一行ずつ出力されます。4 CPU Machine の場合は毎回 5 行ずつ出力されます。

 # mpstat 1
 CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
   0  189  11  185    42   38   51    1   15    3    0   291    1   2   0  98
   1  166   9  193    22   17  191    1   16    5    0   256    1   4   0  96
   2  131  10  190    28   23   49    1   14    3    0   282    1   1   0  98
   3  119  10  207   257  154   54    1   15    5    0   230    1   2   0  97
 CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
   0    0   0    2    21   16    8    0    2    0    0     2    0   0   0 100
   1    0   0    2    19   13  121    0    5    0    0     0    0   5   0  95
   2    6   0    1    13    8    8    0    1    0    0    65    0   0   0 100
   3    0   0    1   223  120   12    0    5    0    0     1    0   0   0 100
 CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
   0    0   0    1     9    6    2    0    1    0    0     5    0   0   0 100
   1    0   0    7    10    6  121    0    1    0    0     0    0   0   0 100
   2    0   0    2    12    7    6    0    0    0    0    55    0   0   0 100
   3    0   0    2   218  115    6    0    3    0    0     0    0   3   0  97

各カラムの意味

CPU

CPU はプロセッサ番号です。

CPU の値は 0 から 517 まで(正確には _SC_CPUID_MAX の値まで)です。 0 番から順に p_online(2) で CPU が存在しているか確認し、もし存在していていたらその番号を表示しています。CPU の値は /usr/src/cmd/stat/common/acquire.c の acquire_cpus() 関数でセットされている cs_id から取られています。

_SC_CPUID_MAX は /usr/src/uts/common/sys/unistd.h で定義されています。

    211 #define	_SC_CPUID_MAX		517	/* maximum CPU id */

minf

minf はマイナーフォルトが発生した回数です。現在はアドレススペースフォルトが発生した回数がそのままマイナーフォルトの回数として計算されています。

minf の値は /usr/src/uts/common/vm/vm_as.c の as_fault() 関数の中の CPU_STATS_ADDQ(CPU, vm, as_fault, 1); で加算されています。

minf の値は kstat -p 'cpu::vm:as_fault' 1" でも取得出来ます。

mjf

mjf はメジャーフォルトが発生した回数です。メジャーフォルトはメモリページを読み込む際に物理 I/O が発生した物のことを言います。

mjf の値は /usr/src/uts/common/os/bio.c の pageio_setup() 関数の中で集計されています。ページング用のバッファを用意する際に、B_READ フラグが立っていて B_ASYNC フラグが立っていない場合に CPU_STATS_ADDQ(cpup, vm, maj_fault, 1); で maj_fault の値がインクリメントされます。この maj_fault が mpstat の mjf の値として使用されます。

mjf の値は "kstat -p 'cpu::vm:maj_fault' 1" でも取得出来ます。

xcal

xcal はプロセッサ間のクロスコールの回数です。

xcal の値は CPU 毎に異なるコードで、カーネル内の様々な箇所で更新されています。

sun4v アーキテクチャの環境では /usr/src/uts/sun4v/os/mach_cpu_states.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); と send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); で集計されています。

x86 環境では /usr/src/uts/i86pc/os/x_call.c の xc_capture_cpus() 関数や xc_common() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); で集計されています。

sun4u 環境では CPU 毎に /usr/src/uts/sun4u/cpu/us3_cheetah.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); や CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids); 、/usr/src/uts/sun4u/cpu/us3_cheetahplus.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped);、CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids);、/usr/src/uts/sun4u/cpu/opl_olympus.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); や CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids);、send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1);、/usr/src/uts/sun4u/cpu/us3_jalapeno.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped);、/usr/src/uts/sun4u/cpu/spitfire.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1);、/usr/src/uts/sun4u/cpu/us3_common.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); 等で更新されています。

sun4 環境では /usr/src/uts/sun4/os/x_call.c の xc_some() 関数の中の SEND_MBOX_ONLY(xc_cpuset, func, arg1, arg2, lcx, XC_WAIT);(SEND_MBOX_ONLY は /usr/src/uts/sun4/sys/xc_impl.h で定義されています)で加算されています。

xcal の値は "kstat -p 'cpu::sys:xcalls' 1" でも取得出来ます。

intr

intr はインタラプトの回数です。PIL_MAX(=15) までのレベルのインタラプト回数の総計を数えています。PIL は Processor Interrupt Level の略です。

intr の値は /usr/src/uts/sun4/ml/interrupt.s の SERVE_INTR (SPARC) や /usr/src/uts/i86pc/os/intr.c の cpu_stats.sys.intr (x86) で加算した値を /usr/src/uts/common/os/cpu.c の中でインタラプトレベル毎に集計しています。

intr の値は "kstat -p 'cpu::sys:intr' 1" でも取得出来ます。

ithr

ithr はインタラプト処理用のスレッドで処理されるインタラプトの回数です。LOCK_LEVEL(=10) までのレベルのインタラプト回数の総計を数えています。

ithr の値は /usr/src/uts/sun4/ml/interrupt.s の SERVE_INTR (SPARC) や /usr/src/uts/i86pc/os/intr.c の cpu_stats.sys.intr (x86) で加算した値を /usr/src/uts/common/os/cpu.c の中でインタラプトレベル毎に集計しています。

ithr の値は "kstat -p 'cpu::sys:intrthread' 1" でも取得出来ます。

csw

csw はコンテキストスイッチの回数です。icsw と対比して、自発的なコンテキストスイッチとも呼ばれます。リソース待ち等で CPU を明け渡した回数です。

csw の値は /usr/src/uts/common/disp/disp.c の swtch() 関数や swtch_to() 関数の CPU_STATS_ADDQ(cp, sys, pswitch, 1);、swtch_from_zombie() 関数の CPU_STATS_ADDQ(CPU, sys, pswitch, 1); で加算されています。

csw の値は "kstat -p 'cpu::sys:pswitch' 1" でも取得出来ます。

icsw

icsw はインボランタリー(非自発的)なコンテキストスイッチの回数です。csw が自発的に CPU を明け渡しているのに対し、よりプライオリティの高いプロセス等に CPU を横取りされた回数です。

icsw の値は /usr/src/uts/common/disp/disp.c の preempt() 関数の中で CPU_STATS_ADDQ(CPU, sys, inv_swtch, 1); で加算されています。

icsw の値は "kstat -p 'cpu::sys:inv_swtch' 1" でも取得出来ます。

migr

migr はスレッドが他の CPU へ移動した回数です。

migr の値は /usr/src/uts/intel/ia32/ml/swtch.s の "incq CPU_STATS_SYS_CPUMIGRATE(%r13)" や "addl $1, CPU_STATS_SYS_CPUMIGRATE(%esi)" (x86)、/usr/src/uts/sun4/ml/swtch.s の "stx %g2, [%i1 + CPU_STATS_SYS_CPUMIGRATE]" (SPARC) で更新されています。CPU_STATS_SYS_CPUMIGRATE は cpu_stats.sys.cpumigrate のオフセットです。

migr の値は "kstat -p 'cpu::sys:cpumigrate' 1" でも取得出来ます。

smtx

smtx は Mutex 変数で Adaptive Lock がスピンした回数です。

Adaptive Lock で他のスレッドが別のプロセッサ上で Lock を保持している場合(その場合はスピンする)最初のスピンの前に 1 加算されます。最初から Spin Lock の場合は加算されません。

smtx の値は /usr/src/uts/common/os/mutex.c の mutex_vector_enter() 関数の中の CPU_STATS_ADDQ(cpup, sys, mutex_adenters, 1); で加算されています。

smtx の値は "kstat -p 'cpu::sys:mutex_adenters' 1" でも取得出来ます。

srw

srw は RW Lock でスピンした回数です。

srw の値は /usr/src/uts/common/os/rwlock.c の rw_enter_sleep() 関数の中の CPU_STATS_ADDQ(CPU, sys, rw_rdfails, 1); と CPU_STATS_ADDQ(CPU, sys, rw_wrfails, 1); の累積値を足し合わせた値です。

srw の値は "kstat -p 'cpu::sys:rw_rdfails' 1" と "kstat -p 'cpu::sys:rw_wrfails' 1" を足す事でも取得出来ます。

syscl

syscl はシステムコールの回数です。

syscl の値はカーネル内の様々な場所で更新されています。

syscl の値は "kstat -p 'cpu::sys:syscall' 1" でも取得可能です。

usr

usr はユーザモードで使用した CPU 時間の割合です。

usr の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。

usr の値は "kstat -p 'cpu::sys:cpu_ticks_user' 1" でも取得出来ます。

sys

sys はカーネルサービスやシステムコールなど、システムモードで使用した CPU 時間の割合です。

sys の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。

sys の値は "kstat -p 'cpu::sys:cpu_ticks_kernel' 1" でも取得出来ます。

wt

wt は I/O wait ですが、Solaris 10 では更新されておらず、常に 0 です。その為、このカラムは無視して構いません。

wt の値は "kstat -p 'cpu::sys:cpu_ticks_wait' 1" でも取得出来ます。

idl

idl は CPU が使用されていなかった時間の割合です。

idl の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。

idl の値は "kstat -p 'cpu::sys:cpu_ticks_idle' 1" でも取得出来ます。

値の見方

usr が多い場合

全ての CPU で usr が 80% 以上になっていて idl が殆ど無い場合は、システムのリソースが十分に利用されていると言って良いでしょう。多くの場合、usr の値が高い事はアプリケーション自体の処理に CPU を使えているという事です。処理のフェイズによってリソースの使い方が変わる場合もありますので、プログラムの実行開始から終了まで観察して下さい。

usr の値は TLB miss でも増加します。この場合はアプリケーション自体の処理と言うよりはリソースの確保に CPU が使われています。SPARC マシンでは trapstat(1M) コマンドで TLB miss の有無を確認する事が出来ます(x86 マシンでは trapstat は使えません)。

 # trapstat -T 1 10
 cpu m size| itlb-miss %tim itsb-miss %tim | dtlb-miss %tim dtsb-miss %tim |%tim
 ----------+-------------------------------+-------------------------------+----
   0 u   8k|        49  0.0         0  0.0 |        27  0.0         0  0.0 | 0.0
   0 u  64k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   0 u 512k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   0 u   4m|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
 - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - -
   0 k   8k|         7  0.0         0  0.0 |       262  0.0         2  0.0 | 0.0
   0 k  64k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   0 k 512k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   0 k   4m|         0  0.0         0  0.0 |         3  0.0         0  0.0 | 0.0
 ----------+-------------------------------+-------------------------------+----
   1 u   8k|       521  0.0         1  0.0 |        46  0.0         1  0.0 | 0.0
   1 u  64k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   1 u 512k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   1 u   4m|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
 - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - -
   1 k   8k|       161  0.0         0  0.0 |       222  0.0         9  0.0 | 0.0
   1 k  64k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   1 k 512k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   1 k   4m|         0  0.0         0  0.0 |         7  0.0         0  0.0 | 0.0
 ==========+===============================+===============================+====
       ttl |       738  0.0         1  0.0 |       567  0.0        12  0.0 | 0.0
 ...

trapstat の出力の一番右の %tim のカラムが各 CPU で TLB miss / TSB miss が発生している割合です。この値が 10% を超えている様であれば MPSS を使用する等の対策を取って下さい。trapstat はシステムに対する負荷が高いコマンドなので、あまり頻繁に実施しない様にして下さい。目安としては一番負荷が高い時に 10 秒程度実施します。

usr や sys の値が高く(idl の値がゼロの状態が続いて)、性能が目に見えて劣化している場合は、過負荷である可能性があります。Solaris は高負荷の状況でも非常に粘り強い OS ですが、ネットワークを使ったアプリケーションの場合は "netstat -sP tcp 1" や "dladm show-dev -s -i 1 <NIC>" 等でエラーが発生していないか確認して下さい。

 # dladm show-dev -s -i 1 e1000g0
 		ipackets  rbytes	 ierrors opackets	 obytes	     oerrors
 e1000g0		140895    9390183     0       507       75864       0       
 		ipackets  rbytes	 ierrors opackets	 obytes	     oerrors
 e1000g0		3         192         0       2         340         0       
 		ipackets  rbytes	 ierrors opackets	 obytes	     oerrors
 e1000g0		4         256         0       2         246         0

sys が多い場合

特定の CPU 又は全ての CPU で sys が 20% 以上出ている場合は、カーネルサービスの CPU 使用率が多くなっています。具体的にはシステムコールやスケジューラ、ファイルシステム等が該当します。sys が多い場合はシステムチューニングの余地があるかもしれません。

sys が多く syscl のカラムも高い数値を示している場合、システムコールが sys の発生源になっている可能性があります。まずは prstat で CPU 負荷の高いプロセスを探します。prstat のオプションは -m を付けて下さい。

 % prstat -m 1
    PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP  
  29044 root     0.0 0.1 0.0 0.0 0.0 0.0 100 0.0  42   0 256   0 prstat/1
  14923 noaccess 0.0 0.0 0.0 0.0 0.0  68  32 0.0  19   1  19   0 java/19
    751 root     0.0 0.0 0.0 0.0 0.0 3.4  97 0.0  41   0 205   0 nscd/29
   9819 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 snmpd/1
  29032 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 in.telnetd/1
  10465 smmsp    0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 sendmail/1
   9666 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 dmispd/1
   9660 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 snmpXdmid/2
   9122 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 snmpdx/1

prstat の出力は CPU 使用率の高い順にソートされるので、上の方に表示されているプロセスが一番 CPU 負荷の高いプロセスです。SYS のカラムを見るとそのプロセスがどのくらい sys を発生させているかが分かります。SYS の値が大きいプロセスを見つけたら、そのプロセスに対し truss を掛けてシステムコールの統計を観察します。

 # truss -cp <PID>

時間を多く使っているシステムコールがあれば、そのシステムコールが sys の原因である可能性があります。

syscl の値が小さい場合はシステムコール以外のカーネルサービスが時間を使っている可能性があります。もしインタラプト処理に CPU を使用している場合は intrstat や lockstat -I コマンドで調べる事が可能です。

 # intrstat 1
 # lockstat -kgIW sleep 10

Ultra SPARC T1 の浮動小数点数演算命令シミュレーションが発生していると sys が増えます。Ultra SPARC T1 の浮動小数点数演算命令のシミュレーションが起きているかどうかは kstat で確認する事が出来ます。

 % kstat -p 'unix::fpu_info:fpu_sim*' 1

idl が多い場合

どのプロセッサでも平均して idl が出ている場合は CPU 以外のリソースがボトルネックになっていると考えられます。メモリ、ネットワーク、ディスク等のリソースに不足がないか確認して下さい。

CPU 以外のリソースにも不足が無い場合はリソースが余っている可能性があります。その場合は負荷を増やして挙動を観察してみて下さい。

CPU によって idl の値に偏りがある場合

幾つかの CPU では idl が 0 なのに、残りの CPU では idl が 100 の場合があります。これはプログラムがスケールしていない状態です。その場合は prstat でアプリケーションのスレッド数を確認して下さい。prstat の出力の一番右端、NLWP のカラムがスレッド数です。スレッド数が CPU 数よりも少ない場合は、(可能であれば)スレッド数を増やしてみるのも手です。

スレッド数が CPU の数より多いのにも関わらず CPU が使い切れていない場合はプログラムの作りに問題がある可能性があります。prstat -L でスレッドのアクティビティを観察して下さい。特定のスレッドの処理量が多い場合は、そのスレッドがボトルネックになっている可能性があります。Web Server 等のネットワークサーバでは少数のディスパッチャースレッドと多数のワーカースレッドという構成になっていて、ディスパッチャーの部分がボトルネックになるケースがあります。truss でプログラムの動きをトレースすると、特定のスレッドが張り付いている場合は同じスレッド ID のスレッドばかりが処理を行うので一つの目安となります。

 % prstat -L 1
 % truss -vall -D -p <PID>

特定の CPU に張り付いているスレッドが見られない場合はロックの競合が発生している可能性があります。plockstat でどのくらい競合が発生しているか確認して下さい。例えば、Solaris の標準の malloc() 関数はシングルスレッドで性能が出る様な実装になっており、複数のスレッドで同時にメモリを確保しようとするとロックの競合が発生します。複数のスレッドで同時に動的にメモリを確保する必要がある場合は mtmalloc ライブラリをプリロードするとスケーラビリティが向上します。

 % plockstat -Cv -e 10 -p <PID>

ロックの競合が発生していると lwp_park というシステムコールが多く呼び出されている事があります。lwp_park が発生している場合はスレッドが休止しています。lwp_park の発生は truss コマンドで確認出来ます。また、どの関数コールが lwp_park の原因になっているかは DTrace を使う事で調べる事が出来ます。

 # truss -cp <PID>
 # dtrace -n 'syscall::lwp_park:entry /execname == "<PROCESS NAME>"/ { @[ustack(22)] = count() }'

スレッド数が増やせない、又はこれ以上スケールしないと分かった場合はプログラムの起動数を増やす事が出来るか確認して下さい。特定のポートで Listen する必要がある場合は Zone を構成して IP Address を分散させる事でリソースを有効に使う事が出来ます。併せて psrset でプロセッサセットを作成すると CPU の利用状況が分散されてリソース効率が上がる場合があります。

また、どのプロセッサでも平均して idl が出ているのに、実際は CPU が張り付いているというケースもあります。これを確認するには prstat でスレッド毎の CPU 使用率を観察します。-L オプションを付けるとスレッド毎の統計が表示されます。 prstat -L の CPU のカラムは 100 / CPU 数が最大です。1 つのスレッドの CPU 使用率が 100 / CPU 数に近い値になっている場合はスレッドが CPU に張り付いていると考えられます。該当のスレッドを pbind してあげると、綺麗に 1 つの CPU に張り付くと思います。

 % prstat -L 1
 % pbind -b <CPUID> <PID>/<TID>

intr が多い場合

intr が多く発生している場合は高レベルの割り込みが多く発生している状態です。NIC 等のデバイスに負荷が掛かっている場合によく発生します。インタラプトの詳細は intrstat や lockstat -I で確認して下さい。

 # intrstat 1
 # lockstat -kgIW sleep 10

icsw が多い場合

icsw が多い場合はシステムリソースに対して負荷が高すぎる可能性があります。頻繁にコンテキストスイッチが発生すると性能に大きく影響します。適切な負荷になる様にスレッド数やプロセス数を調節して下さい。

migr が多い場合

migr が 200 を超える場合は /etc/system で rechoose_interval を増やしてみると効果があるかもしれません。

smtx が多い場:

smtx が多い場合は何のロックでスピンしているのか、lockstat や plockstat で確かめて下さい。lockstat はシステム全体の統計、plockstat はプロセスレベルの統計です。

 # lockstat -g -D 10 sleep 10
 # plockstat -Cve 5 -x bufsize=10k -x aggsize=2m -p <PID>

srw が多い場合

srw が多い場合は、同様に lockstat や plockstat で調べてみて下さい。

syscl が多い場合

syscl が多い場合は truss -c や DTrace を使って、どのシステムコールが多く発生しているのかを確認して下さい。

終わりに

以上、mpstat コマンドの出力の読み方をご紹介しました。mpstat は vmstat や iostat コマンドと並んで性能解析の基本的なコマンドです。どんなベンチマークでも mpstat コマンドを使用しない事はありません。特に CPU のコア数やストランド数が多い場>合やスレッド数の多いプログラムでベンチマークを行う際には必須のコマンドです。是非ご活用下さい。

参考文献