Подтвердить что ты не робот

Linux perf: как интерпретировать и находить горячие точки

Сегодня я опробовал утилиту linux perf, и у меня возникли проблемы с интерпретацией ее результатов. Я привык к valgrind callgrind, который, конечно же, совершенно другой подход к методу перформанса, основанному на выборке.

Что я сделал:

perf record -g -p $(pidof someapp)
perf report -g -n

Теперь я вижу что-то вроде этого:

+     16.92%  kdevelop  libsqlite3.so.0.8.6               [.] 0x3fe57                                                                                                              ↑
+     10.61%  kdevelop  libQtGui.so.4.7.3                 [.] 0x81e344                                                                                                             ▮
+      7.09%  kdevelop  libc-2.14.so                      [.] 0x85804                                                                                                              ▒
+      4.96%  kdevelop  libQtGui.so.4.7.3                 [.] 0x265b69                                                                                                             ▒
+      3.50%  kdevelop  libQtCore.so.4.7.3                [.] 0x18608d                                                                                                             ▒
+      2.68%  kdevelop  libc-2.14.so                      [.] memcpy                                                                                                               ▒
+      1.15%  kdevelop  [kernel.kallsyms]                 [k] copy_user_generic_string                                                                                             ▒
+      0.90%  kdevelop  libQtGui.so.4.7.3                 [.] QTransform::translate(double, double)                                                                                ▒
+      0.88%  kdevelop  libc-2.14.so                      [.] __libc_malloc                                                                                                        ▒
+      0.85%  kdevelop  libc-2.14.so                      [.] memcpy 
...

Хорошо, эти функции могут быть медленными, но как узнать, откуда их вызывают? Поскольку все эти горячие точки лежат во внешних библиотеках, я не вижу возможности оптимизировать свой код.

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

Возможно ли это с помощью perf? Если так - как?

Примечание. Я узнал, что "E" разворачивает callrraph и дает несколько больше информации. Но callgraph часто недостаточно глубок и/или прерывается случайным образом, не давая информации о том, сколько информации было потрачено там. Пример:

-     10.26%  kate  libkatepartinterfaces.so.4.6.0  [.] Kate::TextLoader::readLine(int&...
     Kate::TextLoader::readLine(int&, int&)                                            
     Kate::TextBuffer::load(QString const&, bool&, bool&)                              
     KateBuffer::openFile(QString const&)                                              
     KateDocument::openFile()                                                          
     0x7fe37a81121c

Может быть, проблема, которую я запускаю на 64-битной версии? Смотрите также: http://lists.fedoraproject.org/pipermail/devel/2010-November/144952.html (я не использую Fedora, но, похоже, применим ко всем 64-битным системам).

4b9b3361

Ответ 2

С Linux 3.7 perf наконец-то может использовать информацию DWARF для создания callgraph:

perf record --call-graph dwarf -- yourapp
perf report -g graph --no-children

Углубленный, но графический интерфейс curses ужасен по сравнению с VTune, KCacheGrind или аналогичным... Я рекомендую попробовать FlameGraphs, что является довольно аккуратной визуализацией: http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html

Примечание. На шаге отчета -g graph результаты, полученные в результате, просты для понимания "по отношению к общим" процентам, а не по отношению к родительским. --no-children будет показывать только собственную стоимость, а не инклюзивную стоимость - функцию, которую я также считаю неоценимой.

Если у вас есть новый процессор perf и Intel, попробуйте также разматыватель LBR, который имеет гораздо лучшую производительность и создает гораздо меньшие файлы результатов:

perf record --call-graph lbr -- yourapp

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

Ответ 3

Хорошо, эти функции могут быть медленными, но как узнать, откуда их вызывают? Поскольку все эти горячие точки лежат во внешних библиотеках, я не вижу возможности оптимизировать свой код.

Вы уверены, что ваше приложение someapp построено с опцией gcc -fno-omit-frame-pointer (и, возможно, его зависимыми библиотеками)? Что-то вроде этого:

g++ -m64 -fno-omit-frame-pointer -g main.cpp

Ответ 4

Вы можете получить очень подробный отчет об уровне источника с perf annotate, см. Анализ исходного уровня с перфомансом. Это будет выглядеть примерно так (бесстыдно украденное с сайта):

------------------------------------------------
 Percent |   Source code & Disassembly of noploop
------------------------------------------------
         :
         :
         :
         :   Disassembly of section .text:
         :
         :   08048484 <main>:
         :   #include <string.h>
         :   #include <unistd.h>
         :   #include <sys/time.h>
         :
         :   int main(int argc, char **argv)
         :   {
    0.00 :    8048484:       55                      push   %ebp
    0.00 :    8048485:       89 e5                   mov    %esp,%ebp
[...]
    0.00 :    8048530:       eb 0b                   jmp    804853d <main+0xb9>
         :                           count++;
   14.22 :    8048532:       8b 44 24 2c             mov    0x2c(%esp),%eax
    0.00 :    8048536:       83 c0 01                add    $0x1,%eax
   14.78 :    8048539:       89 44 24 2c             mov    %eax,0x2c(%esp)
         :           memcpy(&tv_end, &tv_now, sizeof(tv_now));
         :           tv_end.tv_sec += strtol(argv[1], NULL, 10);
         :           while (tv_now.tv_sec < tv_end.tv_sec ||
         :                  tv_now.tv_usec < tv_end.tv_usec) {
         :                   count = 0;
         :                   while (count < 100000000UL)
   14.78 :    804853d:       8b 44 24 2c             mov    0x2c(%esp),%eax
   56.23 :    8048541:       3d ff e0 f5 05          cmp    $0x5f5e0ff,%eax
    0.00 :    8048546:       76 ea                   jbe    8048532 <main+0xae>
[...]

Не забывайте передавать флаги -fno-omit-frame-pointer и -ggdb при компиляции кода.

Ответ 5

Если ваша программа имеет очень мало функций и вряд ли когда-либо называет системную функцию или ввод-вывод, профилировщики, которые примерят счетчик программ, не расскажут вам много, как вы обнаружите. Фактически, известный профилировщик gprof был создан специально для того, чтобы попытаться устранить бесполезность профилирования, использующего только время во времени (а не то, что это удалось).

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

Кроме того, статистика, которую вы должны искать, - это процент времени на стек, а не количество вызовов, а не среднее время включения. Особенно не "само время". Если команда вызова (или команда без вызова) находится в стеке 38% времени, то, если вы могли бы избавиться от нее, сколько бы вы спасли? 38% Довольно просто, нет?

Примером такого профилировщика является Zoom.

Есть больше вопросов, которые следует понимать по этому вопросу.

Добавлено: @caf заставил меня искать информацию perf, и поскольку вы включили аргумент командной строки -g, он собирает образцы стека. Затем вы можете получить отчет call-tree. Затем, если вы убедитесь, что вы пробуете время на стене (так что вы получаете время ожидания, а также время процессора), у вас есть почти то, что вам нужно.