Ранее в заметке Профилирование кода на C/C++ в Linux и FreeBSD вскользь упоминалось, что аналогом perf из мира Linux во FreeBSD является утилита pmcstat. Однако не сообщалось, как именно этим pmcstat пользоваться, просто потому что на тот момент я этого и не умел. Не так давно, благодаря помощи со стороны Федора Сигаева , мне все-таки удалось осилить pmcstat. А теперь, благодаря помощи с моей стороны, осилить удастся и вам!
Примечания: (1) Также вас могут заинтересовать статьи Использование DTrace на примере FreeBSD и Linux , Установка и простые примеры использования SystemTap и Трассировка и профайлинг в Linux с помощью bcc/eBPF . (2) Насколько мне известно, в MacOS утилиты pmcstat нет.
По традиции, сначала немного матчасти. Performance Monitoring Counters, или PMC, называют набор регистров специального назначения, встроенный в современные CPU для хранения счетчиков связанных с железом событий, происходящих в системе. В качестве примера такого события можно привести промах мимо кешей процессора при обращении к оперативной памяти и, как следствие, вынужденное более дорогое обращение к оперативной памяти напрямую.
PMC устроены по-разному на разных CPU. Роль уровня абстракции над этими различиями во FreeBSD играет модуль ядра hwpmc.ko. Пользовательские приложения, такие, как pmccontrol и pmcstat, общаются с hwpmc.ko при помощи библиотеки libpmc. (В случае с Linux и perf, подозреваю, принцип аналогичный.)
От теории плавно переходим к практике.
Первым делом загружаем уже упомянутый hwpmc.ko:
Смотрим список доступных хардверных счетчиков:
Активируем все счечтики:
Теперь мы можем посмотреть самый «горячие» процедуры конкретного процесса (аналог perf top) таким образом:
Пример вывода:
Не особо уступает perf, не так ли? Хотя постойте-ка, ведь perf позволяет нам «проваливаться» в процедуры и смотреть, какие именно строчки кода тормозят. Можно ли сделать то же самое при помощи pmcstat? Оказывается, что можно:
pmcannotate out.dat / path / to / bin / postgres > annotate.txt
less -x8 annotate.txt
Пример вывода (по ширине обрезано мной):
#samples/total 875683
Profile trace for function: strcmp() [10.18%]
Profile trace for function: _bt_compare() [7.59%]
0.90%| _bt_compare(Relation rel,
| int keysz,
| ScanKey scankey,
| Page page,
| OffsetNumber offnum)
| {
0.33%| TupleDesc itupdesc = RelationGetDescr(rel);
1.98%| BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer…
4.70%|
| /*
| * Force result «>» if target item is first data item on a…
| * — see NOTE above.
| */
| if (!P_ISLEAF(opaque) && offnum == P_FIRSTDATAKEY(opaque))
0.30%| return 1;
8.19%|
| itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, …
0.81%| * We don’t test for violation of this condition here, how…
| * initial setup for the index scan had better have gotten…
| * _bt_first).
| */
|
| for (i = 1; i <= keysz; i++)
9.51%| {
| Datum datum;
| bool isNull;
| int32 result;
…
И снова ничем не уступает perf! Но постойте-ка, а как на счет построения флеймграфов? Никаких проблем, при помощи pmcstat их тоже можно строить:
pmcstat -R pmc.out -z16 -G pmc.graph
git clone https: // github.com / brendangregg / FlameGraph
perl . / FlameGraph / stackcollapse-pmc.pl pmc.graph > pmc.stack
perl . / FlameGraph / flamegraph.pl . / pmc.stack > pmc.svg
Ну и напоследок мне хотелось бы показать еще одну клевую штуку, которую умеет pmcstat — построение графа вызовов подобно тому, что мы ранее строили при помощи gprof:
sudo pip install gprof2dot
pmcstat -R pmc.out -g
gprof / path / to / bin / postgres INSTR_RETIRED_ANY / postgres.gmon > gprof.out
gprof2dot gprof.out | dot -Tsvg -o gprof.svg
Пример куска графа, полученного таким образом:
Впрочем, на мой субъективный взгляд, флеймграфы куда проще для восприятия, чем графы вызовов, а показывают они при этом одно и то же.
Также pmcstat может считать уже упомянутые кэш-мисы, и, подозреваю, делать множество других умопомрачительных штук, про большинство из которых я пока даже не догадываюсь. Но, честно говоря, особой потребности в этих самых штуках у меня пока что нет, вот и поведать я о них не могу. Подробности заинтересовавшиеся читатели могут найти в man pmcstat
, и далее по ссылкам.
А пользуетесь ли вы pmcstat, и если да, то как именно?