Linux性能優化實戰學習筆記:第五十一講


一、上節回顧

上一節,我帶你一起學習了常見的動態追蹤方法。所謂動態追蹤,就是在系統或者應用程序正常運行的時候,通過內核中提供的探針,來動態追蹤它們的行為,
從而輔助排查出性能問題的瓶頸。

使用動態追蹤,可以在不修改代碼、不重啟服務的情況下,動態了解應用程序或者內核的行為,這對排查線上問題、特別是不容易重現的問題尤其有效。

在 Linux 系統中,常見的動態追蹤方法包括 ftrace、perf、eBPF 以及 SystemTap 等。上節課,我們具體學習了 ftrace 的使用方法。今天,我們再來一起看看其他幾種方法。

二、perf

perf 已經是我們的老朋友了。在前面的案例中,我們多次用到它,來查找應用程序或者內核中的熱點函數,從而定位性能瓶頸。而在內核線程 CPU 高的案例中,我們還使用火焰圖動態展示
perf 的事件記錄,從而更直觀地發現了問題。

不過,我們前面使用 perf record/top 時,都是先對事件進行采樣,然后再根據采樣數,評估各個函數的調用頻率。實際上,perf 的功能遠不止於此。比如,

  • perf 可以用來分析 CPU cache、CPU 遷移、分支預測、指令周期等各種硬件事件;
  • perf 也可以只對感興趣的事件進行動態追蹤。

1、perf 動態追蹤的使用方法

接下來,我們還是以內核函數 do_sys_open,以及用戶空間函數 readline 為例,看一看 perf 動態追蹤的使用方法。

同 ftrace 一樣,你也可以通過 perf list ,查詢所有支持的事件:

perf list

然后,在 perf 的各個子命令中添加 --event 選項,設置追蹤感興趣的事件。如果這些預定義的事件不滿足實際需要,你還可以使用 perf probe 來動態添加。而且,除了追蹤內核事件外,
perf 還可以用來跟蹤用戶空間的函數。

我們先來看第一個 perf 示例,內核函數 do_sys_open 的例子。你可以執行 perf probe 命令,添加 do_sys_open 探針:

perf probe --add do_sys_open
Added new event:
  probe:do_sys_open    (on do_sys_open)
You can now use it in all perf tools, such as:
    perf record -e probe:do_sys_open -aR sleep 1

探針添加成功后,就可以在所有的 perf 子命令中使用。比如,上述輸出就是一個 perf record 的示例,執行它就可以對 10s 內的 do_sys_open 進行采樣:

perf record -e probe:do_sys_open -aR sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.148 MB perf.data (19 samples) ]

而采樣成功后,就可以執行 perf script ,來查看采樣結果了:

perf script
            perf 12886 [000] 89565.879875: probe:do_sys_open: (ffffffffa807b290)
           sleep 12889 [000] 89565.880362: probe:do_sys_open: (ffffffffa807b290)
           sleep 12889 [000] 89565.880382: probe:do_sys_open: (ffffffffa807b290)
           sleep 12889 [000] 89565.880635: probe:do_sys_open: (ffffffffa807b290)
           sleep 12889 [000] 89565.880669: probe:do_sys_open: (ffffffffa807b290)

實際安裝調試代碼:

root@luoahong ~]# perf list

List of pre-defined events (to be used in -e):

  alignment-faults                                   [Software
  bpf-output                                         [Software
  context-switches OR cs                             [Software
  cpu-clock                                          [Software
  
  
[root@luoahong ~]# perf probe --add do_sys_open
Added new event:
  probe:do_sys_open    (on do_sys_open)

You can now use it in all perf tools, such as:

	perf record -e probe:do_sys_open -aR sleep 1


[root@luoahong ~]# perf record -e probe:do_sys_open -aR sleep 10
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.153 MB perf.data (7 samples) ]
[root@luoahong ~]# perf script
            perf 10318 [001]  3749.316261: probe:do_sys_open: (ffffffff8129f030)
           sleep 10319 [000]  3749.317116: probe:do_sys_open: (ffffffff8129f030)
           sleep 10319 [000]  3749.317130: probe:do_sys_open: (ffffffff8129f030)
           sleep 10319 [000]  3749.317753: probe:do_sys_open: (ffffffff8129f030)
         systemd     1 [001]  3752.144923: probe:do_sys_open: (ffffffff8129f030)
      irqbalance  7772 [001]  3753.567150: probe:do_sys_open: (ffffffff8129f030)
      irqbalance  7772 [001]  3753.567501: probe:do_sys_open: (ffffffff8129f030)

輸出中,同樣也列出了調用 do_sys_open 的任務名稱、進程 PID 以及運行的 CPU 等信息。不過,對於 open 系統調用來說,只知道它被調用了並不夠,我們需要知道的是,進程到底在打
開哪些文件。所以,實際應用中,我們還希望追蹤時能顯示這些函數的參數。

對於內核函數來說,你當然可以去查看內核源碼,找出它的所有參數。不過還有更簡單的方法,那就是直接從調試符號表中查詢。執行下面的命令,你就可以知道 do_sys_open 的所有參數:

perf probe -V do_sys_open
Available variables at do_sys_open
        @<do_sys_open+0>
                char*   filename
                int     dfd
                int     flags
                struct open_flags       op
                umode_t mode

2、安裝調試信息后重試

從這兒可以看出,我們關心的文件路徑,就是第一個字符指針參數(也就是字符串),參數名稱為 filename。如果這個命令執行失敗,就說明調試符號表還沒有安裝。那么,你可以執行下面的
命令,安裝調試信息后重試:

# Ubuntu
$ apt-get install linux-image-`uname -r`-dbgsym
# CentOS
$ yum --enablerepo=base-debuginfo install -y kernel-debuginfo-$(uname -r)

找出參數名稱和類型后,就可以把參數加到探針中了。不過由於我們已經添加過同名探針,所以在這次添加前,需要先把舊探針給刪掉:

# 先刪除舊的探針
perf probe --del probe:do_sys_open

# 添加帶參數的探針
$ perf probe --add 'do_sys_open filename:string'
Added new event:
  probe:do_sys_open    (on do_sys_open with filename:string)
You can now use it in all perf tools, such as:
    perf record -e probe:do_sys_open -aR sleep 1

新的探針添加后,重新執行 record 和 script 子命令,采樣並查看記錄:

# 重新采樣記錄
$ perf record -e probe:do_sys_open -aR ls

# 查看結果
$ perf script
            perf 13593 [000] 91846.053622: probe:do_sys_open: (ffffffffa807b290) filename_string="/proc/13596/status"
              ls 13596 [000] 91846.053995: probe:do_sys_open: (ffffffffa807b290) filename_string="/etc/ld.so.cache"
              ls 13596 [000] 91846.054011: probe:do_sys_open: (ffffffffa807b290) filename_string="/lib/x86_64-linux-gnu/libselinux.so.1"
              ls 13596 [000] 91846.054066: probe:do_sys_open: (ffffffffa807b290) filename_string="/lib/x86_64-linux-gnu/libc.so.6”
              ...
# 使用完成后不要忘記刪除探針
$ perf probe --del probe:do_sys_open

實際安裝調試代碼:

[root@luoahong ~]# perf probe -x /bin/bash 'readline%return +0($retval):string'
Added new event:
  probe_bash:readline  (on readline%return in /usr/bin/bash with +0($retval):string)

You can now use it in all perf tools, such as:

	perf record -e probe_bash:readline -aR sleep 1

[root@luoahong ~]# perf record -e probe_bash:readline__return -aR sleep 5
event syntax error: 'probe_bash:readline__return'
                     \___ unknown tracepoint

Error:	File /sys/kernel/debug/tracing/events/probe_bash/readline__return not found.
Hint:	Perhaps this kernel misses some CONFIG_ setting to enable this feature?.

Run 'perf list' for a list of valid events

 Usage: perf record [<options>] [<command>]
    or: perf record [<options>] -- <command> [<options>]

    -e, --event <event>   event selector. use 'perf list' to list available events
[root@luoahong ~]#  perf script
            perf 10318 [001]  3749.316261: probe:do_sys_open: (ffffffff8129f030)
           sleep 10319 [000]  3749.317116: probe:do_sys_open: (ffffffff8129f030)
           sleep 10319 [000]  3749.317130: probe:do_sys_open: (ffffffff8129f030)
           sleep 10319 [000]  3749.317753: probe:do_sys_open: (ffffffff8129f030)
         systemd     1 [001]  3752.144923: probe:do_sys_open: (ffffffff8129f030)
      irqbalance  7772 [001]  3753.567150: probe:do_sys_open: (ffffffff8129f030)
      irqbalance  7772 [001]  3753.567501: probe:do_sys_open: (ffffffff8129f030)
[root@luoahong ~]# perf probe --del probe_bash:readline__return
"probe_bash:readline__return" does not hit any event.
  Error: Failed to delete events.

現在,你就可以看到每次調用 open 時打開的文件了。不過,這個結果是不是看着很熟悉呢?

其實,在我們使用 strace 跟蹤進程的系統調用時,也經常會看到這些動態庫的影子。比如,使用strace 跟蹤 ls 時,你可以得到下面的結果:

strace ls
...
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
...

你估計在想,既然 strace 也能得到類似結果,本身又容易操作,為什么我們還要用 perf 呢?

3、既然 strace 也能得到類似結果,本身又容易操作,為什么我們還要用 perf 呢?

實際上,很多人只看到了 strace 簡單易用的好處,卻忽略了它對進程性能帶來的影響。從原理上來說,strace 基於系統調用 ptrace 實現,這就帶來了兩個問題。

  • 由於 ptrace 是系統調用,就需要在內核態和用戶態切換。當事件數量比較多時,繁忙的切換必然會影響原有服務的性能;
  • ptrace 需要借助 SIGSTOP 信號掛起目標進程。這種信號控制和進程掛起,會影響目標進程的行為。

所以,在性能敏感的應用(比如數據庫)中,我並不推薦你用 strace (或者其他基於 ptrace 的性能工具)去排查和調試。

在 strace 的啟發下,結合內核中的 utrace 機制, perf 也提供了一個 trace 子命令,是取代strace 的首選工具。相對於 ptrace 機制來說,perf trace 基於內核事件,自然要比進程跟蹤的
性能好很多。

perf trace 的使用方法如下所示,跟 strace 其實很像:

perf trace ls
         ? (         ): ls/14234  ... [continued]: execve()) = 0
     0.177 ( 0.013 ms): ls/14234 brk(                                                                  ) = 0x555d96be7000
     0.224 ( 0.014 ms): ls/14234 access(filename: 0xad98082                                            ) = -1 ENOENT No such file or directory
     0.248 ( 0.009 ms): ls/14234 access(filename: 0xad9add0, mode: R                                   ) = -1 ENOENT No such file or directory
     0.267 ( 0.012 ms): ls/14234 openat(dfd: CWD, filename: 0xad98428, flags: CLOEXEC                  ) = 3
     0.288 ( 0.009 ms): ls/14234 fstat(fd: 3</usr/lib/locale/C.UTF-8/LC_NAME>, statbuf: 0x7ffd2015f230 ) = 0
     0.305 ( 0.011 ms): ls/14234 mmap(len: 45560, prot: READ, flags: PRIVATE, fd: 3                    ) = 0x7efe0af92000
     0.324 Dockerfile  test.sh
( 0.008 ms): ls/14234 close(fd: 3</usr/lib/locale/C.UTF-8/LC_NAME>                          ) = 0
     ...

實際測試代碼如下:

[root@luoahong ~]# perf trace ls
         ? (     ?   ): ls/10348  ... [continued]: execve()) = 0
     0.386 ( 0.049 ms): ls/10348 brk(                                                                  ) = 0xae0000
     0.610 ( 0.090 ms): ls/10348 mmap(len: 4096, prot: READ|WRITE, flags: PRIVATE|ANONYMOUS            ) = 0x7fe83213c000
     0.755 ( 0.048 ms): ls/10348 access(filename: 0x31f3abd0, mode: R                                  ) = -1 ENOENT No such file or directory
     0.847 ( 0.052 ms): ls/10348 open(filename: 0x31f394c4, flags: CLOEXEC                             ) = 3
     0.947 ( 0.042 ms): ls/10348 fstat(fd: 3</usr/lib64/libpthread-2.17.so>, statbuf: 0x7fff6a5b9360   ) = 0
     1.036 ( 0.049 ms): ls/10348 mmap(len: 33764, prot: READ, flags: PRIVATE, fd: 3                    ) = 0x7fe832133000
     1.394 ( 0.047 ms): ls/10348 close(fd: 3</usr/lib64/libpthread-2.17.so>                            ) = 0
     1.500 ( 0.053 ms): ls/10348 open(filename: 0x3213c640, flags: CLOEXEC                             ) = 3
     1.599 ( 0.082 ms): ls/10348 read(fd: 3</usr/lib64/libpthread-2.17.so>, buf: 0x7fff6a5b9520, count: 832) = 832
     1.725 ( 0.046 ms): ls/10348 fstat(fd: 3</usr/lib64/libpthread-2.17.so>, statbuf: 0x7fff6a5b93c0   ) = 0
     1.820 ( 0.106 ms): ls/10348 mmap(len: 2255184, prot: EXEC|READ, flags: PRIVATE|DENYWRITE, fd: 3   ) = 0x7fe831cf5000
     2.027 ( 0.350 ms): ls/10348 mprotect(start: 0x7fe831d19000, len: 2093056                          ) = 0
     2.424 ( 0.056 ms): ls/10348 mmap(addr: 0x7fe831f18000, len: 8192, prot: READ|WRITE, flags: PRIVATE|DENYWRITE|FIXED, fd: 3, off: 143360) = 0x7fe831f18000
     2.533 ( 0.053 ms): ls/10348 mmap(addr: 0x7fe831f1a000, len: 6480, prot: READ|WRITE, flags: PRIVATE|ANONYMOUS|FIXED) = 0x7fe831f1a000

不過,perf trace 還可以進行系統級的系統調用跟蹤(即跟蹤所有進程),而 strace 只能跟蹤特定的進程。

第二個 perf 的例子是用戶空間的庫函數。以 bash 調用的庫函數 readline 為例,使用類似的方法,可以跟蹤庫函數的調用(基於 uprobes)。

readline 的作用,是從終端中讀取用戶輸入,並把這些數據返回調用方。所以,跟 open 系統調用不同的是,我們更關注 readline 的調用結果。

我們執行下面的命令,通過 -x 指定 bash 二進制文件的路徑,就可以動態跟蹤庫函數。這其實就是跟蹤了所有用戶在 bash 中執行的命令:

# 為 /bin/bash 添加 readline 探針
$ perf probe -x /bin/bash 'readline%return +0($retval):string’

# 采樣記錄
$ perf record -e probe_bash:readline__return -aR sleep 5

# 查看結果
$ perf script
    bash 13348 [000] 93939.142576: probe_bash:readline__return: (5626ffac1610 <- 5626ffa46739) arg1="ls"

# 跟蹤完成后刪除探針
$ perf probe --del probe_bash:readline__return

當然,如果你不確定探針格式,也可以通過下面的命令,查詢所有支持的函數和函數參數:

跟內核函數類似,如果你想要查看普通應用的函數名稱和參數,那么在應用程序的二進制文件中,同樣需要包含調試信息。

三、eBPF 和 BCC

ftrace 和 perf 的功能已經比較豐富了,不過,它們有一個共同的缺陷,那就是不夠靈活,沒法像 DTrace 那樣通過腳本自由擴展。

而 eBPF 就是 Linux 版的 DTrace,可以通過 C 語言自由擴展(這些擴展通過 LLVM 轉換為 BPF字節碼后,加載到內核中執行)。下面這張圖,就表示了 eBPF 追蹤的工作原理:

從圖中你可以看到,eBPF 的執行需要三步:

  1. 從用戶跟蹤程序生成 BPF 字節碼;
  2. 加載到內核中運行;
  3. 向用戶空間輸出結果。

所以,從使用上來說,eBPF 要比我們前面看到的 ftrace 和 perf ,都更加繁雜。

實際上,在 eBPF 執行過程中,編譯、加載還有 maps 等操作,對所有的跟蹤程序來說都是通用的。把這些過程通過 Python 抽象起來,也就誕生了 BCC(BPF Compiler Collection)。

BCC 把 eBPF 中的各種事件源(比如 kprobe、uprobe、tracepoint 等)和數據操作(稱為Maps),也都轉換成了 Python 接口(也支持 lua)。這樣,使用 BCC 進行動態追蹤時,編寫
簡單的腳本就可以了。

不過要注意,因為需要跟內核中的數據結構交互,真正核心的事件處理邏輯,還是需要我們用 C語言來編寫。

至於 BCC 的安裝方法,在內存模塊的緩存案例中,我就已經介紹過了。如果你還沒有安裝過,可以執行下面的命令來安裝(其他系統的安裝請參考這里):

# Ubuntu
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)

# REHL 7.6
yum install bcc-tools

安裝后,BCC 會把所有示例(包括 Python 和 lua),放到 /usr/share/bcc/examples 目錄中:

ls /usr/share/bcc/examples
hello_world.py  lua  networking  tracing

接下來,還是以 do_sys_open 為例,我們一起來看看,如何用 eBPF 和 BCC 實現同樣的動態跟蹤。

通常,我們可以把 BCC 應用,拆分為下面這四個步驟。

第一,跟所有的 Python 模塊使用方法一樣,在使用之前,先導入要用到的模塊:

from bcc import BPF

第二,需要定義事件以及處理事件的函數。這個函數需要用 C 語言來編寫,作用是初始化剛才導入的 BPF 對象。這些用 C 語言編寫的處理函數,要以字符串的形式送到 BPF 模塊中處理:

# define BPF program (""" is used for multi-line string).
# '#' indicates comments for python, while '//' indicates comments for C.
prog = """
#include <uapi/linux/ptrace.h>
#include <uapi/linux/limits.h>
#include <linux/sched.h>
// define output data structure in C
struct data_t {
    u32 pid;
    u64 ts;
    char comm[TASK_COMM_LEN];
    char fname[NAME_MAX];
};
BPF_PERF_OUTPUT(events);

// define the handler for do_sys_open.
// ctx is required, while other params depends on traced function.
int hello(struct pt_regs *ctx, int dfd, const char __user *filename, int flags){
    struct data_t data = {};
    data.pid = bpf_get_current_pid_tgid();
    data.ts = bpf_ktime_get_ns();
    if (bpf_get_current_comm(&data.comm, sizeof(data.comm)) == 0) {
        bpf_probe_read(&data.fname, sizeof(data.fname), (void *)filename);
    }
    events.perf_submit(ctx, &data, sizeof(data));
    return 0;
}
"""
# load BPF program
b = BPF(text=prog)
# attach the kprobe for do_sys_open, and set handler to hello
b.attach_kprobe(event="do_sys_open", fn_name="hello")

第三步,是定義一個輸出函數,並把輸出函數跟 BPF 事件綁定:

# process event
start = 0
def print_event(cpu, data, size):
    global start
    # event’s type is data_t
    event = b["events"].event(data)
    if start == 0:
            start = event.ts
    time_s = (float(event.ts - start)) / 1000000000
    print("%-18.9f %-16s %-6d %-16s" % (time_s, event.comm, event.pid, event.fname))

# loop with callback to print_event
b["events"].open_perf_buffer(print_event)

最后一步,就是執行事件循環,開始追蹤 do_sys_open 的調用:

# print header
print("%-18s %-16s %-6s %-16s" % ("TIME(s)", "COMM", "PID", "FILE”))
# start the event polling loop
while 1:
    try:
        b.perf_buffer_poll()
    except KeyboardInterrupt:
        exit()

我們把上面幾個步驟的代碼,保存到文件 trace-open.py 中,然后就可以用 Python 來運行了。如果一切正常,你可以看到如下輸出:

python trace-open.py
TIME(s)            COMM             PID    FILE
0.000000000        irqbalance       1073   /proc/interrupts
0.000175401        irqbalance       1073   /proc/stat
0.000258802        irqbalance       1073   /proc/irq/9/smp_affinity
0.000290102        irqbalance       1073   /proc/irq/0/smp_affinity

從輸出中,你可以看到 irqbalance 進程(你的環境中可能還會有其他進程)正在打開很多文件,而 irqbalance 依賴這些文件中讀取的內容,來執行中斷負載均衡。

通過這個簡單的示例,你也可以發現,eBPF 和 BCC 的使用,其實比 ftrace 和 perf 有更高的門檻。想用 BCC 開發自己的動態跟蹤程序,至少要熟悉 C 語言、Python 語言、被跟蹤事件或函數
的特征(比如內核函數的參數和返回格式)以及 eBPF 提供的各種數據操作方法。

不過,因為強大的靈活性,雖然 eBPF 在使用上有一定的門檻,卻也無法阻止它成為目前最熱門、最受關注的動態追蹤技術。

當然,BCC 軟件包也內置了很多已經開發好的實用工具,默認安裝到 /usr/share/bcc/tools/ 目錄中,它們的使用場景如下圖所示:

這些工具,一般都可以直接拿來用。而在編寫其他的動態追蹤腳本時,它們也是最好的參考資料。不過,有一點需要你特別注意,很多 eBPF 的新特性,都需要比較新的內核版本(如下圖所
示)。如果某些工具無法運行,很可能就是因為使用了當前內核不支持的特性。

 

 

 

四、SystemTap 和 sysdig

除了前面提到的 ftrace、perf、eBPF 和 BCC 外,SystemTap 和 sysdig 也是常用的動態追蹤工具。

1、SystemTap 

SystemTap 也是一種可以通過腳本進行自由擴展的動態追蹤技術。在 eBPF 出現之前,

SystemTap 是 Linux 系統中,功能最接近 DTrace 的動態追蹤機制。不過要注意,SystemTap在很長時間以來都游離於內核之外(而 eBPF 自誕生以來,一直根植在內核中)。

所以,從穩定性上來說,SystemTap 只在 RHEL 系統中好用,在其他系統中則容易出現各種異常問題。當然,反過來說,支持 3.x 等舊版本的內核,也是 SystemTap 相對於
 eBPF 的一個巨大優勢。

2、sysdig

sysdig 則是隨着容器技術的普及而誕生的,主要用於容器的動態追蹤。sysdig 匯集了一些列性能工具的優勢,可以說是集百家之所長。我習慣用這個公式來表示 sysdig 的特點:
 sysdig =strace + tcpdump + htop + iftop + lsof + docker inspect。

而在最新的版本中(內核版本 >= 4.14),sysdig 還可以通過 eBPF 來進行擴展,所以,也可以用來追蹤內核中的各種函數和事件。

五、如何選擇追蹤工具

到這里,你可能又覺得頭大了,這么多動態追蹤工具,在實際場景中到底該怎么選擇呢?還是那句話,具體性能工具的選擇,就要從具體的工作原理來入手。

這兩節課,我們已經把常見工具的原理和特點都介紹過了,你可以先自己思考區分一下,不同場景的工具選擇問題。比如:

  1. 在不需要很高靈活性的場景中,使用 perf 對性能事件進行采樣,然后再配合火焰圖輔助分析,就是最常用的一種方法;
  2. 而需要對事件或函數調用進行統計分析(比如觀察不同大小的 I/O 分布)時,就要用SystemTap 或者 eBPF,通過一些自定義的腳本來進行數據處理。

在這里,我也總結了幾個常見的動態追蹤使用場景,並且分別推薦了適合的工具。你可以保存這個表格,方便自己查找並使用。

六、小結

今天,我主要帶你學習了 perf、eBPF 和 BCC 等動態追蹤方法,並總結了不同場景中如何選擇動態追蹤方法

在 Linux 系統中,常見的動態追蹤方法,包括 ftrace、perf、eBPF 以及 SystemTap 等。在大多數性能問題中,使用 perf 配合火焰圖是一個不錯的方法。如果這滿足不了你的要求,那么:

在新版的內核中,eBPF 和 BCC 是最靈活的動態追蹤方法;而在舊版本內核中,特別是在 RHEL 系統中,由於 eBPF 支持受限,SystemTap 往往是更好的選擇。

此外,在使用動態追蹤技術時,為了得到分析目標的詳細信息,一般需要內核以及應用程序的調試符號表。動態追蹤實際上也是在這些符號(包括函數和事件)上進行的,所以易讀易理解的符
號,有助於加快動態追蹤的過程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM