[英]linux perf: how to interpret and find hotspots
我今天嘗試了 linux 的perf實用程序,但在解釋其結果時遇到了麻煩。 我已經習慣了 valgrind 的 callgrind,這當然是與基於采樣的 perf 方法完全不同的方法。
我做了什么:
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 ...
好的,這些函數可能很慢,但是我如何找出它們是從哪里調用的呢? 由於所有這些熱點都位於外部庫中,因此我看不到優化代碼的方法。
基本上我正在尋找某種帶有累積成本注釋的調用圖,其中我的函數比我調用的庫函數具有更高的包容性采樣成本。
這可能與性能有關嗎? 如果是這樣 - 如何?
注意:我發現“E”打開了調用圖並提供了更多信息。 但是調用圖通常不夠深和/或隨機終止,而沒有提供有關在哪里花費了多少信息的信息。 例子:
- 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 位系統)。
使用 Linux 3.7 perf 終於能夠使用 DWARF 信息來生成調用圖:
perf record --call-graph dwarf -- yourapp
perf report -g graph --no-children
整潔,但與 VTune、KCacheGrind 或類似的相比,curses GUI 很糟糕......我建議嘗試使用 FlameGraphs,這是一個非常簡潔的可視化: http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html
注意:在報告步驟中, -g graph
使結果 output 易於理解“相對於總數”的百分比,而不是“相對於父級”的數字。 --no-children
將只顯示自我成本,而不是包含成本——我也發現這個功能非常寶貴。
如果你有一個新的性能和 Intel CPU,也可以試試 LBR unwinder,它有更好的性能並產生更小的結果文件:
perf record --call-graph lbr -- yourapp
這里的缺點是調用堆棧深度與默認的 DWARF 展開器配置相比更加有限。
好的,這些函數可能很慢,但是我如何找出它們是從哪里調用的呢? 由於所有這些熱點都位於外部庫中,因此我看不到優化代碼的方法。
您確定您的應用程序someapp
是使用 gcc 選項-fno-omit-frame-pointer
(可能還有它的依賴庫)構建的嗎? 像這樣的東西:
g++ -m64 -fno-omit-frame-pointer -g main.cpp
你應該試試熱點: https://www.kdab.com/hotspot-gui-linux-perf-profiler/
它在 github 上可用: https://github.com/KDAB/hotspot
例如,它能夠為您生成火焰圖。
您可以使用 perf annotate 獲得非常詳細的源級報告,請參閱使用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
標志。
除非您的程序具有很少的功能並且幾乎不會調用系統 function 或 I/O,否則對程序計數器進行采樣的分析器不會告訴您太多,正如您所發現的那樣。 事實上,著名的分析器gprof是專門創建的,以嘗試解決僅自我分析的無用性(並不是說它成功了)。
真正起作用的是對調用堆棧進行采樣(從而找出調用來自何處),在掛鍾時間(從而包括 I/O 時間),並按行或按指令報告(從而查明 function 調用您應該調查,而不僅僅是他們所在的功能)。
此外,您應該查找的統計數據是堆棧時間百分比,而不是調用次數,而不是平均包含 function 時間。 尤其不是“自我時間”。 如果調用指令(或非調用指令)有 38% 的時間在堆棧中,那么如果你可以擺脫它,你會節省多少? 38%! 很簡單,不是嗎?
此類分析器的一個示例是Zoom 。
在這個問題上還有更多的問題需要理解。
補充: perf
讓我尋找性能信息,並且由於您包含命令行參數-g
它確實收集堆棧樣本。 然后您可以獲得調用樹報告。 然后,如果您確保您在掛鍾時間進行采樣(因此您可以獲得等待時間和 cpu 時間),那么您幾乎得到了您需要的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.