Как использовать инструмент linux `perf` для создания профиля "Off-CPU"

Брендан Д. Грегг (автор книги DTrace) имеет интересный вариант профилирования: "Off-CPU" профилированиеГрафик пламени вне процессора; слайды 2013, p112-137), чтобы увидеть, где поток или приложение были заблокированы (не были выполнены процессором, но ожидали ввода/вывода, обработчика страницы или отказались из-за нехватки ресурсов ЦП):

На этот раз показано, какие кодовые пути заблокированы и ждут во время работы вне CPU, и как долго точно. Это отличается от традиционного профилирования, которое часто отображает активность потоков в заданный интервал и (обычно) рассматривает только потоки, если они выполняют работу с процессором.

Он также может объединять данные профиля вне CPU и профиль On-CPU вместе: http://www.brendangregg.com/FlameGraphs/hotcoldflamegraphs.html

Примеры, приведенные Греггом, выполняются с помощью dtrace, который обычно не доступен в ОС Linux. Но есть некоторые аналогичные инструменты (ktap, systemtap, perf) и perf, как я думаю, имеет самую широкую установленную базу. Обычно perf генерируются профили On-CPU (какие функции выполнялись чаще всего на CPU).

  • Как перевести примеры Gregg Off-CPU в инструмент perf для профилирования в Linux?

PS: Существует ссылка на вариант systemtap плагинов вне CPU на слайдах из LISA13, p124: "Ичунь Чжан создал их и использует их в Linux с помощью SystemTap для сбора профильных данных. См.: http://agentzh.org/misc/slides/off-cpu-flame-graphs.pdf" "(Встреча с пивом CloudFlare 23 августа 2013 года)

Ответ 1

Первой техникой, которую я опубликовал [1], было обходное решение с большими накладными расходами, до тех пор, пока у исполнителя не будет поддержки BPF для этого.

В настоящее время самый дешевый способ создания графика пламени вне процессора в Linux находится на ядре 4.6+ (у которого есть поддержка трассировки стека BPF) и с ОЦК/БПФ. Я написал для него инструмент offcputime [2], который можно запустить с опцией -f для "сложенного вывода", подходящей для подачи на пламя .pl. Этот инструмент offcputime выполняет подсчет времени и стека в содержимом ядра и сбрасывает отчет, который затем печатается с символами.

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

В то же время мы можем использовать bcc/BPF. Если по какой-то причине вы не можете использовать bcc, вы можете прямо сейчас взять эту программу offcputime и записать ее на C. Более сложная версия доступна в источнике Linux, например sample/bpf/offwaketime *. С новыми функциями BPF в Linux, если есть желание, есть способ.

[1] http://www.brendangregg.com/blog/2015-02-26/linux-perf-off-cpu-flame-graph.html

[2] https://github.com/iovisor/bcc/blob/master/tools/offcputime_example.txt

Ответ 2

Брендан Грегг опубликовал инструкцию о генерации пламени Off-cpu: http://www.brendangregg.com/blog/2015-02-26/linux-perf-off-cpu-flame-graph.html и https://github.com/brendangregg/FlameGraph/issues/47#

Графики пламени времени вне процессора могут решить (скажем) 60% проблем, а оставшаяся часть требует прокрутки потоков, чтобы найти основную причину. Я объяснил графики пламени вне процессора, эту проблему пробуждения и дополнительную работу в моем разговоре LISA13 на графиках пламени (slides, youtube).

Здесь я покажу один способ сделать графики пламени времени вне процессора, используя Linux perf_events.

# perf record -e sched:sched_stat_sleep -e sched:sched_switch \
 -e sched:sched_process_exit -a -g -o perf.data.raw sleep 1
# perf inject -v -s -i perf.data.raw -o perf.data
# perf script -f comm,pid,tid,cpu,time,period,event,ip,sym,dso,trace | awk '
NF > 4 { exec = $1; period_ms = int($5 / 1000000) }
NF > 1 && NF <= 4 && period_ms > 0 { print $2 }
NF < 2 && period_ms > 0 { printf "%s\n%d\n\n", exec, period_ms }' | \
./stackcollapse.pl | \
./flamegraph.pl --countname=ms --title="Off-CPU Time Flame Graph" --colors=io > offcpu.svg

stackcollapse.pl и flamegraph.pl из Gregg используются для рисования пламени.

Существуют первоочередные опции, используемые из ядер 3.17 и новее...