實踐環境 CentOS-7-x86_64-DVD-2009 簡介 Firewalld是一種簡單的、有狀態的、基於區域(zone-based)的防火牆。策略和區域用於組織防火牆規則。網路在邏輯上被劃分為多個區域,它們之間的流量可以通過策略進行管理。 查看防火牆狀態 # service firewall ...
1 Linux perf 簡介
perf 是 Linux 內核自帶的一個強大的性能分析工具,它能夠深入到內核和用戶空間,提供豐富的性能計數器和事件跟蹤功能,幫助開發者和系統管理員精確地定位系統性能瓶頸。
1.1 perf 的主要功能:
- 性能事件採樣: 可以採樣各種硬體性能事件,如 CPU 周期、緩存命中率、指令退休率等,從而分析程式在 CPU 上的執行情況。
- 軟體事件跟蹤: 可以跟蹤內核和用戶空間的函數調用、系統調用等軟體事件,分析程式的執行流程和函數調用關係。
- 性能計數器: 提供了大量的硬體性能計數器,可以用來分析 CPU、記憶體、緩存等硬體資源的使用情況。
- 火焰圖生成: 可以生成火焰圖,直觀地展示程式的調用棧,快速定位性能熱點。
- 實時監控: 可以實時監控系統的性能指標,幫助快速發現性能問題。
1.2 perf 的工作原理:
perf 主要通過以下方式來收集性能數據:
- 硬體性能計數器: 利用 CPU 內置的性能計數器,直接獲取硬體的性能數據。
- 軟體事件跟蹤: 在內核和用戶空間插入探針,跟蹤軟體事件的發生。
- 內核協作: perf 與內核緊密協作,通過內核介面獲取性能數據。
1.3 perf 的常用命令:
- perf list: 列出所有可用的性能事件。
- perf stat: 統計性能事件的計數。
- perf record: 記錄性能數據。
- perf report: 分析記錄的數據,生成報告。
- perf top: 實時顯示占用 CPU 時間最多的函數。
- perf trace: 追蹤系統調用和軟中斷。
1.4 perf 的應用場景:
- 定位性能瓶頸: 通過分析性能數據,找出程式中消耗時間最長的部分。
- 優化代碼: 根據性能分析結果,有針對性地優化代碼。
- 分析系統問題: 分析系統性能問題,如 CPU 負載過高、記憶體泄漏等。
- 調優內核參數: 調整內核參數,提高系統性能。
1.5 perf 的優勢:
- 功能強大: 提供了豐富的性能分析功能。
- 靈活易用: 命令行界面簡單易學。
- 開源免費: 作為 Linux 內核的一部分,完全免費。
- 社區活躍: 有一個龐大的社區,提供豐富的文檔和支持。
2 使用 perf probe測量Linux用戶空間代碼的執行時間
2.1 測量的示常式序evenodd.c
#include <stdio.h>
#include <unistd.h>
void even(void)
{
printf("it is even\n");
}
void odd(void)
{
printf("it is odd\n");
}
int main()
{
int i;
for (i = 0; ;i++) {
usleep(500);
if (i % 2)
odd();
else
even();
}
}
參考資料
- 軟體測試精品書籍文檔下載持續更新 https://github.com/china-testing/python-testing-examples 請點贊,謝謝!
- 本文涉及的python測試開發庫 謝謝點贊! https://github.com/china-testing/python_cn_resouce
- python精品書籍下載 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
- Linux精品書籍下載 https://www.cnblogs.com/testing-/p/17438558.html
- https://bristot.me/using-perf-probe-to-measure-execution-time-of-user-space-code-on-linux/
- https://github.com/open-power-sdk/curt/blob/master/curt.py
- https://opensource.com/article/18/7/fun-perf-and-python
- https://man7.org/linux/man-pages/man1/perf-script-python.1.html
- https://github.com/torvalds/linux/blob/master/tools/perf/scripts/python/stackcollapse.py
- https://www.brendangregg.com/perf.html
- https://github.com/brendangregg/FlameGraph
- https://medium.com/@techhara/profiling-visualize-program-bottleneck-with-flamegraph-3e0c5855b2fe
- https://perf.wiki.kernel.org/index.php/Tutorial#Flame_Graph
- 如需技術支持聯繫釘ding或微信pythontesting , 郵箱: xurongzhong#126.com
2.2 使用調試符號編譯 even odd:
# gcc -o -g evenodd evenodd.c
# perf probe --line even -x evenodd
<even@/root/code/evenodd.c:0>
0 void even(void)
{
2 printf("it is even\n");
3 }
void odd(void)
{
2.3 添加探針
在 even() 函數的開頭添加 perf 探針,請運行以下命令:
# objdump -t evenodd
evenodd: file format elf64-littleaarch64
SYMBOL TABLE:
0000000000400238 l d .interp 0000000000000000 .interp
0000000000400254 l d .note.gnu.build-id 0000000000000000 .note.gnu.build-id
0000000000400278 l d .note.ABI-tag 0000000000000000 .note.ABI-tag
0000000000400298 l d .gnu.hash 0000000000000000 .gnu.hash
...
# perf probe -x evenodd 'even'
要獲取給定函數的執行時間,我們需要在函數的最後一行添加探針。如 perf probe -line 示例所示,是第 3 行。下麵的命令在 evenondd 二進位文件的函數 event() 的第 3 行添加了名為 even_end event 的探針。
# perf probe -x evenodd 'even_end=even:3'
開始運行evenodd應用程式後,運行以下命令記錄 even() 執行 10 秒的進入和退出探針:
# perf record -e probe_evenodd:even -e probe_evenodd:even_end -a sleep 10
記錄結束後,可以使用以下命令列印跟蹤結果:
# perf script
evenodd 2342328 [034] 1232877.416865: probe_evenodd:even: (4006c4)
evenodd 2342328 [034] 1232877.416875: probe_evenodd:even_end: (4006d8)
evenodd 2342328 [034] 1232877.417990: probe_evenodd:even: (4006c4)
evenodd 2342328 [034] 1232877.417996: probe_evenodd:even_end: (4006d8)
evenodd 2342328 [034] 1232877.419109: probe_evenodd:even: (4006c4)
...
2.4 python分析
還可以使用 perf python腳本自動計算執行時間。捕獲這兩個事件的跟蹤後,以下命令將生成名為 perf-script.py 的 python 腳本框架:
# perf script -g python
然後編輯探測處理程式,計算執行時間:
# perf script event handlers, generated by perf script -g python
# Licensed under the terms of the GNU GPL License version 2
# The common_* event handler fields are the most useful fields common to
# all events. They don't necessarily correspond to the 'common_*' fields
# in the format files. Those fields not available as handler params can
# be retrieved using Python functions of the form common_*(context).
# See the perf-script-python Documentation for the list of available functions.
from __future__ import print_function
import os
import sys
sys.path.append(os.environ['PERF_EXEC_PATH'] + \
'/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
from perf_trace_context import *
from Core import *
def trace_begin():
print("in trace_begin")
def trace_end():
print("in trace_end")
start=0
def probe_evenodd__even(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, __probe_ip, perf_sample_dict):
global start
start=(common_secs * 1000000000) + common_nsecs
def probe_evenodd__even_end(event_name, context, common_cpu, common_secs, common_nsecs, common_pid, common_comm, common_callchain, __probe_ip, perf_sample_dict):
now=common_secs * 1000000000 + common_nsecs
duration=now - start
print("even runtime: " + str(duration) + " ns")
def trace_unhandled(event_name, context, event_fields_dict, perf_sample_dict):
print(get_dict_as_string(event_fields_dict))
print('Sample: {'+get_dict_as_string(perf_sample_dict['sample'], ', ')+'}')
def print_header(event_name, cpu, secs, nsecs, pid, comm):
print("%-20s %5u %05u.%09u %8u %-20s " % \
(event_name, cpu, secs, nsecs, pid, comm), end="")
def get_dict_as_string(a_dict, delimiter=' '):
return delimiter.join(['%s=%s'%(k,str(v))for k,v in sorted(a_dict.items())])
然後,運行以下命令,就可以列印出函數 even 的執行時間:
# perf script -s perf-script.py | tail
even runtime: 6540 ns
even runtime: 7080 ns
even runtime: 6770 ns
even runtime: 7220 ns
even runtime: 6850 ns
even runtime: 6390 ns
even runtime: 6910 ns
even runtime: 6760 ns
even runtime: 7460 ns
in trace_end