perf_event_open実験
perfが実際にどのシステムコールを使って計測しているのかを、straceでperf stat自体をトレースして観察した記録。
strace -f -e trace=perf_event_open /usr/lib/linux-tools/6.8.0-100-generic/perf stat ls
#linux #performance #profiling
観察結果
lsを1回実行しただけでperf_event_open(2)が何度も呼ばれていた。task-clock, context-switches, page-faults, cycles, instructions, branches, branch-missesなど、計測したいイベント1つにつき1回呼ばれており、man 2 perf_event_openの「計測対象1つにつき1つのfdを作る」という説明と一致する。
perf_event_open({type=0xa, size=0x88, config=0xc2, ..., disabled=1, inherit=1,
exclude_kernel=1, exclude_hv=1, enable_on_exec=1, exclude_guest=1, ...},
1702198, -1, -1, PERF_FLAG_FD_CLOEXEC) = 21
EACCES→リトライのペアが頻出する
多くのイベントで、同じattrをほぼそのまま2回呼んでいるペアが見られた。
perf_event_open({..., (exclude_kernelなし) ...}) = -1 EACCES (Permission denied)
perf_event_open({..., exclude_kernel=1, ...}) = 22
1回目はカーネル空間も含めて計測しようとして権限不足で失敗し、2回目にexclude_kernel=1(ユーザー空間のみ計測)へフォールバックして成功している。原因はこのマシンの/proc/sys/kernel/perf_event_paranoidが2になっていること。
$ cat /proc/sys/kernel/perf_event_paranoid
2
perf_event_paranoidの値による制限(man 2 perf_event_openの該当箇所より):
| 値 | 意味 |
|---|---|
| -1 | 制限なし |
| 0 | rawトレースポイント含め計測可能、CAP_PERFMON/CAP_SYS_ADMINなしでも可 |
| 1 | CPUイベントはユーザー空間・カーネル空間とも計測可能 |
| 2 | ユーザー空間の計測のみ許可(デフォルト、Ubuntuの既定値) |
| 3+ | (Ubuntu独自拡張)CAP_SYS_PTRACEもなければユーザー空間すら計測不可 |
sudoersにperfをNOPASSWDで登録していても、この制限自体は別軸(カーネルのsysctl)で効くため、非rootでperf statを叩くとカーネル空間側のイベントは素通しでは取れず、exclude_kernel=1への自動フォールバックという形で観測できた。
type=0xaの謎はPMUの動的タイプ番号
straceの出力でtype=0xa /* PERF_TYPE_??? */のように?表示になっている箇所があった。straceが知っている固定のPERF_TYPE_HARDWAREなどのenumには載っていない値のため。実体はカーネルが動的に採番するPMUタイプ番号で、/sys/bus/event_source/devices/<pmu名>/typeで確認できる。
$ cat /sys/bus/event_source/devices/cpu_atom/type
10
$ cat /sys/bus/event_source/devices/cpu_core/type
4
0xa = 10、0x4 = 4と一致しており、type=0xaは「Atomコア(高効率コア)のPMUで計測せよ」という指定だったことが分かる。
ハイブリッドCPUで両コア種別が個別に計測される
このマシンのCPUは13th Gen Intel Core i7-1355U(P-core/E-coreのハイブリッド構成)。perf statの出力にもcpu_atom/cycles/uとcpu_core/cycles/uが両方現れ、後者は<not counted>だった。
664,414 cpu_atom/cycles/u
<not counted> cpu_core/cycles/u (0.00%)
perfはハイブリッドCPUに対してcpu_atom・cpu_coreそれぞれ別のPMUとしてperf_event_open()を呼んでおり、lsのような短命なプロセスがたまたまE-core(cpu_atom)側のスレッドで実行されたため、そちら側のカウンタしか値が付かなかったと考えられる。実際perf_event_openのトレース後半でも、PERF_TYPE_HARDWAREにconfig=0xa<<32|PERF_COUNT_HW_CPU_CYCLES(cpu_atom)とconfig=0x4<<32|PERF_COUNT_HW_CPU_CYCLES(cpu_core)の両方が呼ばれており、configの上位32bitにPMUタイプ番号をエンコードして「どちらのコア種別のカウンタか」を指定していることが確認できた。
perfの中での位置づけ
perfコマンド自体が何をしているかという実装原理の裏取り実験。straceでperf自身をトレースするという、実験対象と観察ツールが入れ子になった構成になっている。
出典
man 2 perf_event_open- 上記のstrace出力・
/proc/sys/kernel/perf_event_paranoid・/sys/bus/event_source/devices/*/typeは本マシン上で実際に取得した一次情報