プロセッサ: CPUとプロセス/スレッド
ps(1)やtop(1)を使うとどのプロセッサがどの程度使われているか、どのコアで実行されているのかを知ることができます。DTraceを使うとプロセッサごとにどのくらい使われているのか、どのプロセスがどのプロセッサでどの程度使われているのか、ということを調べることができます。コマンドではFreeBSDが提供しているライブラリやシステムコールを経由してこうしたデータを得ているのですが、DTraceではDTraceの機能でこうした情報を収集することができます。
次のDスクリプトは指定したプロセスに関して10秒間データを収集して、プロセッサ(論理コア)ごとにどの程度の時間実行されていたかを表示するものです。
リスト wrun.d
#!/usr/sbin/dtrace -s
#pragma D option quiet
inline int MAX = 10;
dtrace:::BEGIN
{
start = timestamp;
}
sched:::on-cpu
/pid == $target/
{
self->ts = timestamp;
}
sched:::off-cpu
/self->ts/
{
@[cpu] = sum(timestamp - self->ts);
self->ts = 0;
}
profile:::tick-1sec
/++x == MAX/
{
exit(0);
}
dtrace:::END
{
printf("\nCPU distribution over %d milliseconds:\n\n",
(timestamp - start) / 1000000);
printf("CPU microseconds\n--- ------------\n");
normalize(@, 1000);
printa("%3d %@d\n", @);
}
実行すると次のようにそれぞれの論理コアでどの程度プロセスが実行されていたのかを知ることができます。sched:::on-cpuとsched:::off-cpuでタイムスタンプを計測してその差分を加算していくことでこの計算を行っています。
図 wrun.dの実行結果
# ./wrun.sh -p 38674 2> /dev/null
CPU distribution over 10007 milliseconds:
CPU microseconds
--- ------------
1 93
0 385
2 522
3 1735
#
次のDスクリプトは先ほどのwrun.dの内容を特定のプロセスに限定せずに、すべてのプロセス(スレッド)に対して計算して、プロセッサごとに1秒間あたりのプロセス/スレッドの平均実行時間、最大実行時間、最小実行時間を集計して出力したものです。
リスト lat.d
#!/usr/sbin/dtrace -s
#pragma D option quiet
sched:::enqueue
{
s[args[0]->td_tid, args[1]->p_pid] = timestamp;
}
sched:::dequeue
/this->start = s[args[0]->td_tid, args[1]->p_pid]/
{
this->time = timestamp - this->start;
@lat_avg[cpu] = avg(this->time);
@lat_max[cpu] = max(this->time);
@lat_min[cpu] = min(this->time);
s[args[0]->td_tid, args[1]->p_pid] = 0;
}
tick-1sec
{
printf("%-8s %-12s %-12s %-12s\n",
"CPU", "AVG(ns)", "MAX(ns)", "MIN(ns)");
printa("%-8d %-@12d %-@12d %-@12d\n",
@lat_avg, @lat_max, @lat_min);
trunc(@lat_avg);
trunc(@lat_max);
trunc(@lat_min);
}
実行すると次のような結果になります。Ctrl-Cで実行を終了させることができます。
図 lat.dの実行結果
# ./lat.d 2> /dev/null
CPU AVG(ns) MAX(ns) MIN(ns)
1 18385 18385 18385
3 29818 29818 29818
2 33541 33541 33541
CPU AVG(ns) MAX(ns) MIN(ns)
1 27153 50187 4120
3 82593 82593 82593
2 206782 960847 3738
0 2311469 6928036 2883
CPU AVG(ns) MAX(ns) MIN(ns)
2 3014 3014 3014
CPU AVG(ns) MAX(ns) MIN(ns)
0 2759 2759 2759
CPU AVG(ns) MAX(ns) MIN(ns)
1 1882 1882 1882
3 1958 2116 1800
2 4090 6465 2678
CPU AVG(ns) MAX(ns) MIN(ns)
3 2088 2088 2088
1 2676 2676 2676
0 3285 3285 3285
2 14957 27360 2554
CPU AVG(ns) MAX(ns) MIN(ns)
CPU AVG(ns) MAX(ns) MIN(ns)
1 257785 257785 257785
0 1741312 3123997 358627
3 1837949 1837949 1837949
2 2422110 2422110 2422110
^C
#
lat.dの方ではDスクリプトの提供しているavg()、max()、min()を使っているあたりが見どころです。また、出力に関してprinta()を使っているあたりも押さえておきたいところです。処理がイベント駆動で動くようなものなので慣れないと動作を予測するのが難しいかもしれませんが、Dスクリプトはだいたいこんな感じで書いて使うことになります。
これと同じことをしようとした場合、同様のデータを得るためにシステムコールやライブラリの関数を実行してプログラムを組むわけですが、Dスクリプトを使うとそうしたことをせずにダイレクトに、しかも結構簡単に同じことが実現できます。いろんなところにホックが用意されているので結構自由にデータを取得できるあたりが強力なところです。
勉強会
第60回 2月23日(木)19:00~FreeBSD勉強会
発表内容検討中。発表ネタをお持ちの方、ぜひご連絡ください。
参加申請はこちら から。
第61回 3月23日(木)19:00~FreeBSD勉強会:リキャップ・ザ・AsiaBSDCon 2017~日本語でふりかえるABC~
2017年3月9~12日まで、東京でAsiaBSDCon 2017 が開催される予定です。ぜひこのカンファレンスにご参加いただきたいわけなのですが、なかにはどうしても仕事の都合で参加できなかったとか、正直英語がよくわからなかったとか、そういった方もいらっしゃるのではないかと思います。
3月のFreeBSD勉強会では、AsiaBSDCon 2017のあとというこのタイミングを活かして、AsiaBSDCon 2017の発表内容を振り返ってみよう、というのをやってみようと思います。AsiaBSDConに参加しているにもかかわらず、これまで一度もプロシーディングを読み返したことすらないというあなた、ぜひプロシーディングを持参してご参加ください :) AsiaBSDConに参加できなかったというあなたも、この機会をお見逃しなく(できればAsiaBSDConそのものに参加した方が絶対的によいです、あしからず) 。
FreeBSD勉強会 発表者募集
FreeBSD勉強会では発表者を募集しています。FreeBSDに関して発表を行いたい場合、@daichigoto までメッセージをお願いします。1時間半〜2時間ほどの発表資料を作成していただき発表をお願いできればと思います。