發現工作負載使用的 Linux 核心子系統¶
- 作者:
Shuah Khan <skhan@linuxfoundation.org>
Shefali Sharma <sshefali021@gmail.com>
- 維護者:
Shuah Khan <skhan@linuxfoundation.org>
要點¶
方法論¶
strace 是一種診斷、教學和除錯工具,可用於發現工作負載正在使用的系統資源。 一旦我們發現並理解了工作負載的需求,我們就可以專注於它們,以避免迴歸,並用它來評估安全注意事項。 我們使用 strace 工具來跟蹤工作負載。
這種使用 strace 進行跟蹤的方法告訴我們工作負載呼叫的系統呼叫,但不包括它可以呼叫的所有系統呼叫。 此外,這種跟蹤方法只告訴我們這些系統呼叫中被呼叫的程式碼路徑。 例如,如果工作負載開啟一個檔案併成功從中讀取,那麼被跟蹤的是成功路徑。 該系統呼叫中的任何錯誤路徑都不會被跟蹤。 如果存在提供工作負載完全覆蓋的工作負載,那麼此處概述的方法將跟蹤並找到所有可能的程式碼路徑。 系統使用資訊的完整性取決於工作負載覆蓋範圍的完整性。
目標是在執行預設核心的系統上跟蹤工作負載,而無需自定義核心安裝。
我們如何收集細粒度的系統資訊?¶
strace 工具可用於跟蹤程序發出的系統呼叫及其接收到的訊號。 系統呼叫是應用程式和作業系統核心之間的基本介面。 它們使程式能夠從核心請求服務。 例如,Linux 中的 open() 系統呼叫用於提供對檔案系統中檔案的訪問。 strace 使我們能夠跟蹤應用程式發出的所有系統呼叫。 它列出了程序發出的所有系統呼叫及其結果輸出。
您可以生成分析資料,將 strace 和 perf record 工具結合起來,記錄與程序相關的事件和資訊。 這提供了對程序的洞察力。 “perf annotate” 工具生成程式每條指令的統計資訊。 本文件詳細介紹瞭如何收集有關工作負載對系統資源使用的細粒度資訊。
我們使用 strace 來跟蹤 perf、stress-ng、paxtest 工作負載,以說明我們發現工作負載所使用資源的方法。 此過程可應用於跟蹤其他工作負載。
準備系統進行跟蹤¶
在我們開始之前,我們將向您展示如何準備好您的系統。 我們假設您有一個在物理系統或虛擬機器上執行的 Linux 發行版。 大多數發行版都包含 strace 命令。 讓我們安裝通常不包含的構建 Linux 核心的其他工具。 請注意,以下內容適用於基於 Debian 的發行版。 您可能需要在其他 Linux 發行版上找到等效的軟體包。
安裝構建 Linux 核心和核心儲存庫中的工具的工具。 scripts/ver_linux 是檢查您的系統是否已擁有必要工具的好方法
sudo apt-get install build-essential flex bison yacc
sudo apt install libelf-dev systemtap-sdt-dev libslang2-dev libperl-dev libdw-dev
cscope 是瀏覽核心原始碼的好工具。 讓我們現在安裝它
sudo apt-get install cscope
安裝 stress-ng 和 paxtest
apt-get install stress-ng
apt-get install paxtest
工作負載概述¶
如前所述,我們使用 strace 來跟蹤 perf bench、stress-ng 和 paxtest 工作負載,以展示如何分析工作負載並識別這些工作負載使用的 Linux 子系統。 讓我們從這三個工作負載的概述開始,以便更好地瞭解它們的作用以及如何使用它們。
perf bench (all) 工作負載¶
perf bench 命令包含多個多執行緒微核心基準測試,用於執行 Linux 核心和系統呼叫中的不同子系統。 這使我們能夠輕鬆地衡量更改的影響,從而有助於減輕效能迴歸。 它還充當一個通用的基準測試框架,使開發人員能夠輕鬆建立測試用例、透明地整合並使用效能豐富的工具子系統。
Stress-ng netdev stressor 工作負載¶
stress-ng 用於對核心執行壓力測試。 它允許您使用“stressor-s”來鍛鍊計算機的各種物理子系統以及作業系統核心的介面。 它們適用於 CPU、CPU 快取、裝置、I/O、中斷、檔案系統、記憶體、網路、作業系統、管道、排程程式和虛擬機器。 請參閱 stress-ng 手冊頁,以查詢所有可用 stressor-s 的說明。 netdev stressor 啟動指定數量 (N) 的工作執行緒,這些工作執行緒在所有可用的網路裝置上執行各種 netdevice ioctl 命令。
paxtest kiddie 工作負載¶
paxtest 是一個測試核心中緩衝區溢位的程式。 它測試核心對記憶體使用的強制執行。 通常,在某些記憶體段中的執行會使緩衝區溢位成為可能。 它執行一組試圖顛覆記憶體使用的程式。 它用作 PaX 的迴歸測試套件,但可能有助於測試核心的其他記憶體保護補丁。 我們使用了 paxtest kiddie 模式,該模式查詢簡單的漏洞。
什麼是 strace 以及我們如何使用它?¶
如前所述,strace 是一種有用的診斷、教學和除錯工具,可用於發現工作負載正在使用的系統資源。 它可以用於
檢視程序如何與核心互動。
檢視程序失敗或掛起的原因。
用於逆向工程程序。
查詢程式依賴的檔案。
用於分析應用程式的效能。
用於排除與作業系統相關的各種問題。
此外,strace 可以生成有關每次系統呼叫的時間、呼叫和錯誤的執行時統計資訊,並在程式退出時報告摘要,從而抑制常規輸出。 這試圖顯示獨立於掛鐘時間的系統時間(在核心中執行花費的 CPU 時間)。 我們計劃使用這些功能來獲取有關工作負載系統使用情況的資訊。
strace 命令支援基本模式、詳細模式和統計模式。 strace 命令在詳細模式下執行時,會提供有關程序呼叫的系統呼叫的更詳細資訊。
執行 strace -c 會生成一份報告,其中包含在每個系統呼叫中花費的時間百分比、總時間(以秒為單位)、每次呼叫微秒數、呼叫總數、每個系統呼叫因錯誤而失敗的計數以及發出的系統呼叫型別。
用法: strace <我們要跟蹤的命令>
詳細模式用法: strace -v <命令>
收集統計資訊: strace -c <命令>
我們使用“-c”選項來收集我們為分析選擇的三個工作負載使用的細粒度執行時統計資訊。
perf
stress-ng
paxtest
什麼是 cscope 以及我們如何使用它?¶
現在讓我們看一下 cscope,這是一個用於瀏覽 C、C++ 或 Java 程式碼庫的命令列工具。 我們可以使用它來查詢對符號的所有引用、全域性定義、函式呼叫的函式、呼叫函式的函式、文字字串、正則表示式模式、包括檔案的檔案。
我們可以使用 cscope 來查詢哪個系統呼叫屬於哪個子系統。 這樣,我們可以找到程序執行時使用的核心子系統。
讓我們檢出最新的 Linux 儲存庫並構建 cscope 資料庫
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux
cd linux
cscope -R -p10 # builds cscope.out database before starting browse session
cscope -d -p10 # starts browse session on cscope.out database
注意:執行“cscope -R -p10”以構建資料庫,執行“cscope -d -p10”以進入瀏覽會話。 cscope 預設使用 cscope.out 資料庫。 要退出此模式,請按 ctrl+d。 -p 選項用於指定要顯示的檔案路徑元件的數量。 -p10 最適合瀏覽核心原始碼。
什麼是 perf 以及我們如何使用它?¶
Perf 是一種基於 Linux 2.6+ 系統的分析工具,它抽象了 Linux 中效能測量的 CPU 硬體差異,並提供了一個簡單的命令列介面。 Perf 基於核心匯出的 perf_events 介面。 它對於分析系統和查詢應用程式中的效能瓶頸非常有用。
如果您尚未檢出 Linux 主線儲存庫,您可以這樣做,然後構建核心和 perf 工具
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux
cd linux
make -j3 all
cd tools/perf
make
注意:perf 命令可以在不構建儲存庫中的核心的情況下構建,並且可以在較舊的核心上執行。 但是,匹配核心和 perf 版本可以更準確地瞭解子系統的使用情況。
我們使用了“perf stat”和“perf bench”選項。 有關 perf 工具的詳細資訊,請執行“perf -h”。
perf stat¶
perf stat 命令生成各種硬體和軟體事件的報告。 它藉助現代 CPU 中發現的硬體計數器暫存器來完成,這些暫存器保持著這些活動的計數。“perf stat cal”顯示 cal 命令的統計資訊。
Perf bench¶
perf bench 命令包含多個多執行緒微核心基準測試,用於執行 Linux 核心和系統呼叫中的不同子系統。 這使我們能夠輕鬆地衡量更改的影響,從而有助於減輕效能迴歸。 它還充當一個通用的基準測試框架,使開發人員能夠輕鬆建立測試用例、透明地整合並使用效能豐富的工具。
“perf bench all”命令執行以下基準測試
sched/messaging
sched/pipe
syscall/basic
mem/memcpy
mem/memset
什麼是 stress-ng 以及我們如何使用它?¶
如前所述,stress-ng 用於對核心執行壓力測試。 它允許您使用 stressor-s 來鍛鍊計算機的各種物理子系統以及作業系統核心的介面。 它們適用於 CPU、CPU 快取、裝置、I/O、中斷、檔案系統、記憶體、網路、作業系統、管道、排程程式和虛擬機器。
netdev stressor 啟動 N 個工作執行緒,這些工作執行緒在所有可用的網路裝置上執行各種 netdevice ioctl 命令。 執行以下 ioctl
SIOCGIFCONF, SIOCGIFINDEX, SIOCGIFNAME, SIOCGIFFLAGS
SIOCGIFADDR, SIOCGIFNETMASK, SIOCGIFMETRIC, SIOCGIFMTU
SIOCGIFHWADDR, SIOCGIFMAP, SIOCGIFTXQLEN
以下命令執行 stressor
stress-ng --netdev 1 -t 60 --metrics command.
我們可以使用 perf record 命令來記錄與程序相關的事件和資訊。 此命令將分析資料記錄在同一目錄中的 perf.data 檔案中。
使用以下命令,您可以記錄與 netdev stressor 相關的事件、檢視生成的報告 perf.data 並註釋以檢視程式每條指令的統計資訊
perf record stress-ng --netdev 1 -t 60 --metrics command.
perf report
perf annotate
什麼是 paxtest 以及我們如何使用它?¶
paxtest 是一個測試核心中緩衝區溢位的程式。 它測試核心對記憶體使用的強制執行。 通常,在某些記憶體段中的執行會使緩衝區溢位成為可能。 它執行一組試圖顛覆記憶體使用的程式。 它用作 PaX 的迴歸測試套件,並且對於測試核心的其他記憶體保護補丁非常有用。
paxtest 提供 kiddie 和 blackhat 模式。 paxtest kiddie 模式以普通模式執行,而 blackhat 模式試圖繞過核心的保護來測試漏洞。 我們在這裡專注於 kiddie 模式,並將“paxtest kiddie”執行與“perf record”相結合,以收集 paxtest kiddie 執行的 CPU 堆疊跟蹤,以檢視哪個函式在效能配置檔案中呼叫其他函式。 然後,“dwarf”(DWARF 的呼叫幀資訊)模式可用於展開堆疊。
以下命令可用於以呼叫圖格式檢視結果報告
perf record --call-graph dwarf paxtest kiddie
perf report --stdio
跟蹤工作負載¶
現在我們瞭解了工作負載,讓我們開始跟蹤它們。
跟蹤 perf bench all 工作負載¶
執行以下命令來跟蹤 perf bench all 工作負載
strace -c perf bench all
工作負載發出的系統呼叫
下表顯示了工作負載呼叫的系統呼叫、每個系統呼叫的呼叫次數以及相應的 Linux 子系統。
系統呼叫 |
# calls |
Linux 子系統 |
系統呼叫 (API) |
|---|---|---|---|
getppid |
10000001 |
程序管理 |
sys_getpid() |
clone |
1077 |
程序管理 |
sys_clone() |
prctl |
23 |
程序管理 |
sys_prctl() |
prlimit64 |
7 |
程序管理 |
sys_prlimit64() |
getpid |
10 |
程序管理 |
sys_getpid() |
uname |
3 |
程序管理 |
sys_uname() |
sysinfo |
1 |
程序管理 |
sys_sysinfo() |
getuid |
1 |
程序管理 |
sys_getuid() |
getgid |
1 |
程序管理 |
sys_getgid() |
geteuid |
1 |
程序管理 |
sys_geteuid() |
getegid |
1 |
程序管理 |
sys_getegid |
close |
49951 |
檔案系統 |
sys_close() |
pipe |
604 |
檔案系統 |
sys_pipe() |
openat |
48560 |
檔案系統 |
sys_opennat() |
fstat |
8338 |
檔案系統 |
sys_fstat() |
stat |
1573 |
檔案系統 |
sys_stat() |
pread64 |
9646 |
檔案系統 |
sys_pread64() |
getdents64 |
1873 |
檔案系統 |
sys_getdents64() |
access |
3 |
檔案系統 |
sys_access() |
lstat |
1880 |
檔案系統 |
sys_lstat() |
lseek |
6 |
檔案系統 |
sys_lseek() |
ioctl |
3 |
檔案系統 |
sys_ioctl() |
dup2 |
1 |
檔案系統 |
sys_dup2() |
execve |
2 |
檔案系統 |
sys_execve() |
fcntl |
8779 |
檔案系統 |
sys_fcntl() |
statfs |
1 |
檔案系統 |
sys_statfs() |
epoll_create |
2 |
檔案系統 |
sys_epoll_create() |
epoll_ctl |
64 |
檔案系統 |
sys_epoll_ctl() |
newfstatat |
8318 |
檔案系統 |
sys_newfstatat() |
eventfd2 |
192 |
檔案系統 |
sys_eventfd2() |
mmap |
243 |
記憶體管理 |
sys_mmap() |
mprotect |
32 |
記憶體管理 |
sys_mprotect() |
brk |
21 |
記憶體管理 |
sys_brk() |
munmap |
128 |
記憶體管理 |
sys_munmap() |
set_mempolicy |
156 |
記憶體管理 |
sys_set_mempolicy() |
set_tid_address |
1 |
程序管理 |
sys_set_tid_address() |
set_robust_list |
1 |
Futex |
sys_set_robust_list() |
futex |
341 |
Futex |
sys_futex() |
sched_getaffinity |
79 |
排程程式 |
sys_sched_getaffinity() |
sched_setaffinity |
223 |
排程程式 |
sys_sched_setaffinity() |
socketpair |
202 |
網路 |
sys_socketpair() |
rt_sigprocmask |
21 |
訊號 |
|
rt_sigaction |
36 |
訊號 |
|
rt_sigreturn |
2 |
訊號 |
sys_rt_sigreturn() |
wait4 |
889 |
時間 |
sys_wait4() |
clock_nanosleep |
37 |
時間 |
sys_clock_nanosleep() |
capget |
4 |
能力 |
sys_capget() |
跟蹤 stress-ng netdev stressor 工作負載¶
執行以下命令來跟蹤 stress-ng netdev stressor 工作負載
strace -c stress-ng --netdev 1 -t 60 --metrics
工作負載發出的系統呼叫
下表顯示了工作負載呼叫的系統呼叫、每個系統呼叫的呼叫次數以及相應的 Linux 子系統。
系統呼叫 |
# calls |
Linux 子系統 |
系統呼叫 (API) |
|---|---|---|---|
openat |
74 |
檔案系統 |
sys_openat() |
close |
75 |
檔案系統 |
sys_close() |
read |
58 |
檔案系統 |
sys_read() |
fstat |
20 |
檔案系統 |
sys_fstat() |
flock |
10 |
檔案系統 |
|
write |
7 |
檔案系統 |
sys_write() |
getdents64 |
8 |
檔案系統 |
sys_getdents64() |
pread64 |
8 |
檔案系統 |
sys_pread64() |
lseek |
1 |
檔案系統 |
sys_lseek() |
access |
2 |
檔案系統 |
sys_access() |
getcwd |
1 |
檔案系統 |
sys_getcwd() |
execve |
1 |
檔案系統 |
sys_execve() |
mmap |
61 |
記憶體管理 |
sys_mmap() |
munmap |
3 |
記憶體管理 |
sys_munmap() |
mprotect |
20 |
記憶體管理 |
sys_mprotect() |
mlock |
2 |
記憶體管理 |
sys_mlock() |
brk |
3 |
記憶體管理 |
sys_brk() |
rt_sigaction |
21 |
訊號 |
|
rt_sigprocmask |
1 |
訊號 |
|
sigaltstack |
1 |
訊號 |
sys_sigaltstack() |
rt_sigreturn |
1 |
訊號 |
sys_rt_sigreturn() |
getpid |
8 |
程序管理 |
sys_getpid() |
prlimit64 |
5 |
程序管理 |
sys_prlimit64() |
arch_prctl |
2 |
程序管理 |
sys_arch_prctl() |
sysinfo |
2 |
程序管理 |
sys_sysinfo() |
getuid |
2 |
程序管理 |
sys_getuid() |
uname |
1 |
程序管理 |
sys_uname() |
setpgid |
1 |
程序管理 |
sys_setpgid() |
getrusage |
1 |
程序管理 |
sys_getrusage() |
geteuid |
1 |
程序管理 |
sys_geteuid() |
getppid |
1 |
程序管理 |
sys_getppid() |
sendto |
3 |
網路 |
sys_sendto() |
connect |
1 |
網路 |
sys_connect() |
socket |
1 |
網路 |
sys_socket() |
clone |
1 |
程序管理 |
sys_clone() |
set_tid_address |
1 |
程序管理 |
sys_set_tid_address() |
wait4 |
2 |
時間 |
sys_wait4() |
alarm |
1 |
時間 |
sys_alarm() |
set_robust_list |
1 |
Futex |
sys_set_robust_list() |
跟蹤 paxtest kiddie 工作負載¶
執行以下命令來跟蹤 paxtest kiddie 工作負載
strace -c paxtest kiddie
工作負載發出的系統呼叫
下表顯示了工作負載呼叫的系統呼叫、每個系統呼叫的呼叫次數以及相應的 Linux 子系統。
系統呼叫 |
# calls |
Linux 子系統 |
系統呼叫 (API) |
|---|---|---|---|
read |
3 |
檔案系統 |
sys_read() |
write |
11 |
檔案系統 |
sys_write() |
close |
41 |
檔案系統 |
sys_close() |
stat |
24 |
檔案系統 |
sys_stat() |
fstat |
2 |
檔案系統 |
sys_fstat() |
pread64 |
6 |
檔案系統 |
sys_pread64() |
access |
1 |
檔案系統 |
sys_access() |
pipe |
1 |
檔案系統 |
sys_pipe() |
dup2 |
24 |
檔案系統 |
sys_dup2() |
execve |
1 |
檔案系統 |
sys_execve() |
fcntl |
26 |
檔案系統 |
sys_fcntl() |
openat |
14 |
檔案系統 |
sys_openat() |
rt_sigaction |
7 |
訊號 |
|
rt_sigreturn |
38 |
訊號 |
sys_rt_sigreturn() |
clone |
38 |
程序管理 |
sys_clone() |
wait4 |
44 |
時間 |
sys_wait4() |
mmap |
7 |
記憶體管理 |
sys_mmap() |
mprotect |
3 |
記憶體管理 |
sys_mprotect() |
munmap |
1 |
記憶體管理 |
sys_munmap() |
brk |
3 |
記憶體管理 |
sys_brk() |
getpid |
1 |
程序管理 |
sys_getpid() |
getuid |
1 |
程序管理 |
sys_getuid() |
getgid |
1 |
程序管理 |
sys_getgid() |
geteuid |
2 |
程序管理 |
sys_geteuid() |
getegid |
1 |
程序管理 |
sys_getegid() |
getppid |
1 |
程序管理 |
sys_getppid() |
arch_prctl |
2 |
程序管理 |
sys_arch_prctl() |
結論¶
本文件旨在用作指導,介紹如何使用 strace 收集有關工作負載使用的資源的細粒度資訊。