linux , perf , 性能診斷 , stap , systemtap , strace , dtrace , dwarf , profiler , perf_events
linux在服務端已占據非常大的比例,很多業務很多服務都跑在linux上面。
軟體運作在linux下,軟體本身、以及linux系統的性能診斷也成為熱門的話題。
例如,你要如何回答這些問題
又或者你是一名dba或者開發人員,想知道資料庫在跑某些benchmark時,性能瓶頸在哪裡,是io,是等待,還是網絡,代碼瓶頸在哪裡?
在linux下診斷的工具比較多,比如systemtap, dtrace, perf。
本文将介紹一下perf的用法,網上很多叫法如perf_events , perf profiler , performance counters for linux。叫法不同,都指perf。
perf是linux 2.6+核心中的一個工具,在核心源碼包中的位置 tools/perf。
perf利用linux的trace特性,可以用于實時跟蹤,統計event計數(perf stat);或者使用采樣(perf record),報告(perf report|script|annotate)的使用方式進行診斷。
perf指令行接口并不能利用所有的linux trace特性,有些trace需要通過ftrace接口得到。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SMwAzXjlGcfFDMfdjMxEjNxAjMvwVMxYTMwIzLcJXZ0NXYt9CX3Fmcvw1ZvxmYvwFbh92ZpR2Lc12bj5iY1hGdpd2Lc9CX6MHc0RHaiojIsJye.png)
這張圖大緻列出了perf支援的跟蹤事件,從kernerl到user space,支援塊裝置、網絡、cpu、檔案系統、記憶體等,同時還支援系統調用,使用者庫的事件跟蹤。
你可以使用perf list輸出目前核心perf 支援的預置events
我們看到perf支援這麼多的事件和trace,它依賴了很多的接口來幹這件事情。
1. symbols
沒有符号表,無法将記憶體位址翻譯成函數和變量名。
例如,無符号表的跟蹤顯示如下
有符号表的跟蹤顯示如下
如何安裝符号表?
對于核心代碼的符号表,在編譯核心時,使用config_kallsyms=y。 檢查如下
對于使用者安裝軟體的符号表,如果是yum安裝的,可以安裝對應的debuginfo包。
如果是使用者自己編譯的,例如使用gcc編譯時加上-g選項。
2. perf annotate
perf annotate can generate sourcecode level information if the application is compiled with -ggdb.
3. stack traces (使用perf record -g收集stack traces)
要跟蹤完整的stack,編譯時需要注意幾個東西。
3.1 編譯perf時包含libunwind和-g dwarf,需要3.9以上的核心版本。
3.2 有些編譯優化項會忽略frame pointer,是以編譯軟體時必須指定 -fno-omit-frame-pointer ,才能跟蹤完整的stack trace.
3.3 編譯核心時包含 config_frame_pointer=y
總結一下,要愉快的跟蹤更完備的資訊,就要在編譯軟體時打開符号表的支援(gcc -g),開啟annotate的支援(gcc -ggdb),以及stack trace的支援(gcc -fno-omit-frame-pointer)。
了解了perf event後,我們可以更精細的,有針對性的對事件進行跟蹤,采樣,報告。
當然,你也可以不指定事件,全面采樣。
例如centos你可以使用yum安裝,也可以使用源碼安裝。
perf在核心源碼的tools/perf中,是以下載下傳與你的核心大版本一緻的核心源碼即可
安裝依賴庫,有一個小竅門可以找到依賴的庫
通常依賴 gcc make bison flex elfutils libelf-dev libdw-dev libaudit-dev python-dev binutils-dev
并不是每個開關都需要,但是有些沒有就不友善或者功能缺失,例如沒有打開符号表的話,看到的是一堆記憶體位址。
一些開關的用途介紹
1. kernel-level symbols are in the kernel debuginfo package, or when the kernel is compiled with config_kallsyms.
2. the kernel stack traces are incomplete. now a similar profile with config_frame_pointer=y
3. 當我們使用perf record [stack traces (-g)]時,可以跟蹤stack,但是如果核心編譯時沒有指定config_frame_pointer=y,perf report時就會看到缺失的資訊。
不包含config_frame_pointer=y時
包含config_frame_pointer=y時 (much better -- the entire path from the write() syscall (__write_nocancel) to iowrite16() can be seen.)
4. 如果要使用動态跟蹤,即跟蹤任意指定代碼,則需要打開這些開關:
for kernel analysis, using config_kprobes=y and config_kprobe_events=y, to enable kernel dynamic tracing. and config_frame_pointer=y, for frame pointer-based kernel stacks.
for user-level analysis, config_uprobes=y and config_uprobe_events=y, for user-level dynamic tracing.
5. 如果打開了config_debug_info,則可以在動态跟蹤中列印核心變量的值。
if your kernel has debuginfo (config_debug_info=y), you can fish out kernel variables from functions. this is a simple example of examining a size_t (integer)
例如
通過以下指令可以檢視linux的config
先了解一下概貌
perf 指令用法還是挺簡單的,根據功能區分了command,每個command有各自的用法。
用得比較多的有list, record, report, script, stat, top。
要得到每個command的用法也蠻簡單,可以使用perf help command得到。
跟蹤時可以指定事件,cpu,以及是否跟蹤stack trace。
輸出如下
輸入 ? 可以得到top的幫助介紹
輸入e全部展開,展開後可以得到stack trace的結果, 如果發現有位址的資訊,但是沒有符号表的資訊,可能是軟體編譯時沒有指定-g,如果stack資訊不完整,則軟體編譯時需要加-fno-omit-frame-pointer(參考前面章節的介紹)。
輸入c全部收起
symbol列[]中字元代表的含義如下,通常是k或者.表示kernel和user space事件。
perf record用來收集統計資訊,通常的用法包括
1. 使用record收集統計資訊,可以收集全局的,指定pid或者線程id的,指定cpu的,指定user id的。
2. 收集間隔,可以指定采樣的頻率,采樣的event數,采樣時間。
3. 采集的詳細程度,可以指定event,使用cpu實時排程政策的程序(可以參考rhel 講cgroup cpu部分的文章),是否跟蹤stack chain,
例子
解讀前面收集到的perf.data.
常用的開關如下,--tui是互動式的文本顯示視窗,--stdio是文本顯示視窗。
互動式顯示例子,看概貌挺友善的 (常用的互動指令: e擴充,c收斂,q退出)
文本顯示例子,看細節挺友善
首先顯示了一些異常,如果你發現少了符号表或者什麼的,可以根據提示安裝debuginfo,或者重新編譯核心或軟體。
報告的細節如下
一條條列印perf.data内的資料,輸出的是perf record收集到的原始資料。
生成熱力圖、火焰圖也需要perf script的輸出,從最原始的資訊中提取資料,生成svg。
解讀前面收集到的perf.data,輔以彙編指令顯示。
用來測試系統的一些常見名額的性能(如ipc, message or pipe, memcpy)。
測試程序或線程通信性能
從測試來看,線程, pipe()通信效率是最高的。
測試pipe()
測試所有,包括memcpy
perf 除了可以采樣(使用perf record)(包括call stack trace),還可以用于event計數。
perf stat就是用于event計數的,可以跟蹤指定指令的event計數。
如果你想跟蹤postgresql資料庫,可以把資料庫的所有程序塞到cgroup裡,然後使用perf stat -g cgname統計整個cgroup。
perf stat還支援-e指定事件,事件支援通配符。
使用instruction:modifier可以指定要跟蹤的instruction在哪裡?在kernel space或user space,又或者在虛拟機,虛拟機os,主控端os等。
modifier用法如下,寫在event:後面。
modifiers
description
example
u
monitor at priv level 3, 2, 1 (user)
event:u
k
monitor at priv level 0 (kernel)
event:k
h
monitor hypervisor events on a virtualization environment
event:h
monitor host machine on a virtualization environment
g
monitor guest machine on a virtualization environment
event:g
例子 -e instructions:u
perf probe可以實作動态跟蹤,指哪打哪。靜态跟蹤是預置的,而動态跟蹤是補充預置不足的。
比如你想跟蹤kernel的某個function, 甚至某一行代碼,某些變量的值。
或者你想跟蹤使用者軟體的某個function,甚至某一行代碼,某些變量的值。
首先要添加需要動态跟蹤的對象(function, var, ...)
然後record,和report分析,這和前面的用法是一樣的。
跟蹤某行代碼
跟蹤使用者軟體的指定function
event中的一種類型,實際上是一些比較常見的系統調用。
不在裡面的可以使用前面介紹的動态跟蹤的方式進行跟蹤。
支援哪些tracepoint
主要包含以下tracepoint subtype
使用perf report -tui或者-stdio輸出的文本不夠直覺的話,使用火焰圖可以很直覺的表現出哪些代碼是瓶頸所在。
生成火焰圖
生成熱力圖
要完備的跟蹤和列印跟蹤(符号表、call stack trace、彙編指令)資訊,建議核心編譯時加上
編譯perf時需要支援libunwind, 并加上
軟體編譯時加上
如果是yum安裝的軟體,可以安裝對應的debuginfo包。
5. 火焰圖
<a href="https://github.com/brendangregg/flamegraph">https://github.com/brendangregg/flamegraph</a>
6. 熱力圖
<a href="https://github.com/brendangregg/heatmap">https://github.com/brendangregg/heatmap</a>