← На главную

Профайлинг кода на C/C++ во FreeBSD с помощью pmcstat

Ранее в заметке Профилирование кода на 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:

sudo kldload hwpmc

Смотрим список доступных хардверных счетчиков:

sudo pmccontrol -l

Активируем все счечтики:

sudo pmccontrol -e*

Теперь мы можем посмотреть самый «горячие» процедуры конкретного процесса (аналог perf top) таким образом:

pmcstat -Pinstructions -T -t 19843

Пример вывода:

Топ самых горячих процедур в pmcstat

Не особо уступает perf, не так ли? Хотя постойте-ка, ведь perf позволяет нам «проваливаться» в процедуры и смотреть, какие именно строчки кода тормозят. Можно ли сделать то же самое при помощи pmcstat? Оказывается, что можно:

pmcstat -Pinstructions -t 20171 -O out.dat pmcannotate out.dat /path/to/bin/postgres > annotate.txt less -x8 annotate.txt

Пример вывода (по ширине обрезано мной):

CONVERSION STATISTICS: #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 -Pinstructions -t 22456 -O pmc.out 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 pkg install graphviz 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

Впрочем, на мой субъективный взгляд, флеймграфы куда проще для восприятия, чем графы вызовов, а показывают они при этом одно и то же.

Также pmcstat может считать уже упомянутые кэш-мисы, и, подозреваю, делать множество других умопомрачительных штук, про большинство из которых я пока даже не догадываюсь. Но, честно говоря, особой потребности в этих самых штуках у меня пока что нет, вот и поведать я о них не могу. Подробности заинтересовавшиеся читатели могут найти в man pmcstat, и далее по ссылкам.