發現工作負載使用的 Linux 核心子系統

作者:
維護者:

Shuah Khan <skhan@linuxfoundation.org>

要點

  • 瞭解構建和執行工作負載所需的系統資源非常重要。

  • Linux 跟蹤和 strace 可用於發現工作負載正在使用的系統資源。 系統使用資訊的完整性取決於工作負載覆蓋範圍的完整性。

  • 作業系統的效能和安全性可以透過以下工具進行分析:perfstress-ngpaxtest

  • 一旦我們發現並理解了工作負載的需求,我們就可以專注於它們,以避免迴歸,並用它來評估安全注意事項。

方法論

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

訊號

sys_rt_sigprocmask()

rt_sigaction

36

訊號

sys_rt_sigaction()

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

檔案系統

sys_flock()

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

訊號

sys_rt_sigaction()

rt_sigprocmask

1

訊號

sys_rt_sigprocmask()

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

訊號

sys_rt_sigaction()

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 收集有關工作負載使用的資源的細粒度資訊。

參考文獻