Ftrace是Linux Kernel的官方tracing系統,支援Function trace、靜態tracepoint、動態Tracepoint的跟蹤,還提供各種Tracer,用於統計最大irq延遲、最大函數呼叫棧大小、排程事件等。
Ftrace還提供了強大的過濾、快照snapshot、範例(instance)等功能,可以靈活設定。
核心設定Ftrace後,如果功能不開啟,對效能幾乎沒有影響。開啟事件記錄後,由於是在percpu buffer中記錄log,各CPU無需同步,引入的負載不大,非常適合在效能敏感的場景中使用。
相比kernle的log_buf
和dynamic_debug
機制,Ftrace的buffer大小可以靈活設定,可以生成快照,也有一定的優勢。
整個ftrace框架可以分為幾部分:ftrace核心框架,RingBuffer,debugfs,Tracepoint,各種Tracer。
ftrace框架是整個ftrace功能的紐帶,包括對核心的修改,Tracer的註冊,RingBuffer的控制等等。
RingBuffer是靜態動態ftrace的載體。
debugfs則提供了使用者空間對ftrace設定介面。
Tracepoint是靜態trace,他需要提前編譯進核心;可以客製化列印內容,自由新增;並且核心對主要subsystem提供了Tracepoint。
Tracer有很多種,主要幾大類:
函數類:function, function_graph, stack
延時類:irqsoff, preemptoff, preemptirqsoff, wakeup, wakeup_rt, waktup_dl
其他類:nop, mmiotrace, blk
設定核心支援ftrace需要開啟以下宏定義。
CONFIG_FTRACE=y
CONFIG_STACK_TRACER=y
CONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_IRQSOFF_TRACER=y
CONFIG_SCHED_TRACER=y
CONFIG_FTRACE_SYSCALLS=y
CONFIG_PREEMPTIRQ_EVENTS=y
CONFIG_TRACER_SNAPSHOT=y
Ftrace使用tracefs檔案系統去儲存控制檔案和顯示輸出的檔案。
當tracefs被設定進核心時,目錄/sys/kernel/tracing
將會被建立。為了掛載這個目錄,你可以在/etc/fstab
檔案中新增以下資訊:
tracefs /sys/kernel/tracing tracefs defaults 0 0
或者在執行時掛在:
mount -t tracefs nodev /sys/kernel/tracing
為了快速存取這個目錄可以建立一個軟連結::
ln -s /sys/kernel/tracing /tracing
注意:
在4.1版本之前,所有的ftrace跟蹤控制檔案都在debugfs
檔案系統中,該檔案系統通常位於/sys/kernel/debug/tracing
。為了向後相容,當掛載debugfs檔案系統時,tracefs檔案系統將自動掛載在/sys/kernel/debug/tracing
。位於tracefs檔案系統中的所有檔案也將位於debugfs
檔案系統目錄中。
任何選定的ftrace選項也將建立tracefs
檔案系統。檔案中的操作都在ftrace的目錄中(/sys/kernel/tracing
或者/sys/kernel/debug/tracing
)。
在mount tracefs後,即可存取ftrace的控制和輸出檔案。以下是一些關鍵檔案的列表:
root@firefly:/sys/kernel/debug/tracing# ls
README kprobe_profile set_graph_function
available_events max_graph_depth set_graph_notrace
available_filter_functions options snapshot
available_tracers per_cpu trace
buffer_size_kb printk_formats trace_clock
buffer_total_size_kb saved_cmdlines trace_marker
current_tracer saved_cmdlines_size trace_options
dyn_ftrace_total_info saved_tgids trace_pipe
enabled_functions set_event tracing_cpumask
events set_event_pid tracing_max_latency
free_buffer set_ftrace_filter tracing_on
instances set_ftrace_notrace tracing_thresh
kprobe_events set_ftrace_pid
用於設定或顯示當前使用的跟蹤器;使用 echo 將跟蹤器名字寫入該檔案可以切換到不同的跟蹤器。系統啟動後,其預設值為 nop ,即不做任何跟蹤操作。在執行完一段跟蹤任務後,可以通過向該檔案寫入 nop 來重置跟蹤器。
記錄了當前可以跟蹤的核心函數。對於不在該檔案中列出的函數,無法跟蹤其活動。
記錄了當前編譯進核心的跟蹤器的列表,可以通過 cat 檢視其內容;寫 current_tracer 檔案時用到的跟蹤器名字必須在該檔案列出的跟蹤器名字列表中。
用於設定單個 CPU 所使用的跟蹤快取的大小。跟蹤器會將跟蹤到的資訊寫入快取,每個 CPU 的跟蹤快取是一樣大的。跟蹤快取實現為環形緩衝區的形式,如果跟蹤到的資訊太多,則舊的資訊會被新的跟蹤資訊覆蓋掉。注意,要更改該檔案的值需要先將 current_tracer 設定為 nop 才可以。
顯示所有的跟蹤快取大小,不同之處在於buffer_size_kb
是單個CPU的,buffer_total_size_kb
是所有CPU的和。
輸出和trace一樣的內容,輸出實時tracing紀錄檔,這樣就避免了RingBuffer的溢位。cat trace_pipe > trace.txt &
儲存檔案,但是cat時候會帶來一些效能損耗。
控制Trace列印內容格式或者設定跟蹤器,可以通過trace_options
新增很多附加資訊。
設定和顯示當前正在使用的跟蹤器。使用echo命令可以把跟蹤器的名字寫入current_tracer
檔案,從而切換不同的跟蹤器。
debug使用,顯示available_filter_functins
中跟中函數的數目,兩者一致。
顯示有回撥附著的函數名稱。這個檔案更多的是用於偵錯ftrace,但也可以用於檢視是否有任何函數附加了回撥。不僅ftrace框架使用ftrace函數tracing,其他子系統也可能使用。該檔案顯示所有附加回撥的函數,以及附加回撥的數量。注意,一個回撥也可以呼叫多個函數,這些函數不會在這個計數中列出。
如果回撥被一個帶有"save regs"屬性的函數註冊tracing(這樣開銷更大),一個’R’將顯示在與返回暫存器的函數的同一行上。
如果回撥被一個帶有"ip modify"屬性的函數註冊tracing(這樣regs->ip就可以被修改),'I’將顯示在可以被覆蓋的函數的同一行上。
如果體系架構支援,它還將顯示函數直接呼叫的回撥。如果計數大於1,則很可能是ftrace_ops_list_func()。
如果函數的回撥跳轉到特定於回撥而不是標準的"跳轉點"的跳轉點,它的地址將和跳轉點呼叫的函數一起列印。
系統Trace events目錄,在每個events下面都有enable、filter和fotmat。enable是開關;format是events的格式,然後根據格式設定 filter。
在關閉該檔案時,ring buffer將被調整為其最小大小。如果有一個tracing的程序也開啟了這個檔案,當該程序退出,該檔案的描述符將被關閉,在此過程,ring bufer也將被"freed"。
如果options/disable_on_free選項被設定將會停止tracing。
啟用 dynamic trace opoints
。參考核心檔案Documentation/trace/kprobetrace.rst
。
Dynamic trace points
統計資訊。 參考核心檔案Documentation/trace/kprobetrace.rst
。
被用於function_graph tracer。這是tracing一個函數的最大深度。將其設定為1將只顯示從使用者空間呼叫的第一個核心函數。
目錄檔案,裡面是每個trace options的檔案,和trace_options對應,可以通過echo 0/1使能options。
per_cpu:包含跟蹤 per_cpu 資訊的目錄。
提供給工具讀取原始格式trace的檔案。如果環形緩衝區中的事件參照了一個字串,則只有指向該字串的指標被記錄到緩衝區中,而不是字串本身。這可以防止工具知道該字串是什麼。該檔案顯示字串和字串的地址,允許工具將指標對映到字串的內容。
ftrace會存放pid的comms在一個pid mappings,在顯示event時候同時顯示comm,這裡可以設定pid對應的comm,如果設定,顯示類似<idle>-0
,否則<...>-0
。
saved_cmdlines的數目,預設為128
如果設定了選項「record-tgid」,則在每個排程上下文切換時,任務的任務組 ID 將儲存在將執行緒的 PID 對映到其 TGID 的表中。預設情況下,「record-tgid」選項被禁用。
也可以在系統特定事件觸發的時候開啟跟蹤。為了啟用某個事件,你需要:echo sys_enter_nice >> set_event
(注意你是將事件的名字追加到檔案中去,使用>>
追加定向器,不是>
)。要禁用某個事件,需要在名字前加上一個「!」號:echo '!sys_enter_nice' >> set_event
。以下三種方式都可以啟用事件
echo sched:sched_switch >> /debug/tracing/set_event
echo sched_switch >> /debug/tracing/set_event
echo 1 > /debug/tracing/events/sched/sched_switch/enable
tracer將只追蹤寫入此檔案PID的對應程序的event。"event-fork" option設定後,pid對應程序建立的子程序event也會自動跟蹤。
在編譯核心時設定了動態 ftrace (選中 CONFIG_DYNAMIC_FTRACE 選項)後使用。前者用於顯示指定要跟蹤的函數,後者則作用相反,用於指定不跟蹤的函數。如果一個函數名同時出現在這兩個檔案中,則這個函數的執行狀況不會被跟蹤。這些檔案還支援簡單形式的含有萬用字元的表示式,這樣可以用一個表示式一次指定多個目標函數;注意,要寫入這兩個檔案的函數名必須可以在檔案 available_filter_functions
中看到。預設為可以跟蹤所有核心函數,檔案 set_ftrace_notrace
的值則為空。甚至可以對函數的名字使用萬用字元。例如,要用所有的vmalloc_
函數,通過echo vmalloc_* > set_ftrace_filter
進行設定。
tracer將只追蹤寫入此檔案PID的對應的程序。"function-fork" option設定後,pid對應程序建立的子程序也會自動跟蹤。
設定要清晰顯示呼叫關係的函數,顯示的資訊結構類似於 C 語言程式碼,這樣在分析核心運作流程時會更加直觀一些。在使用 function_graph 跟蹤器時使用;預設為對所有函數都生成呼叫關係序列,可以通過寫該檔案來指定需要特別關注的函數。
echo function_graph > current_tracer
echo __do_fault > set_graph_function //跟蹤__do_fault
是對trace的snapshot。
檔案提供了檢視獲取到的跟蹤資訊的介面。可以通過 cat 等命令檢視該檔案以檢視跟蹤到的核心活動記錄,也可以將其內容儲存為記錄檔案以備後續檢視。
每當一個事件被記錄到環形緩衝區中時,都會新增一個「時間戳」。此標記來自指定的時鐘。預設情況下,ftrace 使用「本地」時鐘。本地時鐘可能與其他 CPU 上的本地時鐘不同步。
用於將使用者空間與核心空間中發生的事件同步。將字串寫入該檔案將被寫入ftrace緩衝區。
在應用程式中,應用程式開始開啟這個檔案並參照檔案描述符::
void trace_write(const char *fmt, ...)
{
va_list ap;
char buf[256];
int n;
if (trace_fd < 0)
return;
va_start(ap, fmt);
n = vsnprintf(buf, 256, fmt, ap);
va_end(ap);
write(trace_fd, buf, n);
}
開始:
trace_fd = open("trace_marker", WR_ONLY);
注意:寫入trace_marker檔案也可以觸發寫入/sys/kernel/tracing/events/ftrace/print/trigger
的觸發器。詳細看核心檔案Documentation/trace/histogram.rst (Section 3.)
。
此檔案允許使用者控制在上述輸出檔案之一中顯示的資料量。還存在用於修改跟蹤器或事件的工作方式(堆疊跟蹤、時間戳等)的選項。
trace_pipe:"trace_pipe"輸出與"trace"檔案相同的內容,但是對跟蹤的影響不同。每次從"trace_pipe"讀取都會被消耗。這意味著後續的讀取將有所不同。跟蹤是動態的:
# echo function > current_tracer
# cat trace_pipe > /tmp/trace.out &
[1] 4153
# echo 1 > tracing_on
# usleep 1
# echo 0 > tracing_on
# cat trace
# tracer: function
#
# entries-in-buffer/entries-written: 0/0 #P:4
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
#
# cat /tmp/trace.out
bash-1994 [000] .... 5281.568961: mutex_unlock <-rb_simple_write
bash-1994 [000] .... 5281.568963: __mutex_unlock_slowpath <-mutex_unlock
bash-1994 [000] .... 5281.568963: __fsnotify_parent <-fsnotify_modify
bash-1994 [000] .... 5281.568964: fsnotify <-fsnotify_modify
bash-1994 [000] .... 5281.568964: __srcu_read_lock <-fsnotify
bash-1994 [000] .... 5281.568964: add_preempt_count <-__srcu_read_lock
bash-1994 [000] ...1 5281.568965: sub_preempt_count <-__srcu_read_lock
bash-1994 [000] .... 5281.568965: __srcu_read_unlock <-fsnotify
bash-1994 [000] .... 5281.568967: sys_dup2 <-system_call_fastpath
注意,讀取"trace_pipe"檔案將會阻塞,直到新增更多輸入。這與"trace"檔案相反。如果任何程序開啟"trace"檔案進行讀取,它實際上將禁用tracing並阻止新增新條目。"trace_pipe"檔案沒有這個限制。
可以通過此檔案設定跟蹤指定CPU,二進位制格式。
記錄某些Tracer的最大延時。比如interrupts的最大延時關閉後,會記錄在這裡。可以echo值到此檔案,然後遇到比設定值更大的延遲才會更新。
用於控制跟蹤的暫停。有時候在觀察到某些事件時想暫時關閉跟蹤,可以將 0 寫入該檔案以停止跟蹤,這樣跟蹤緩衝區中比較新的部分是與所關注的事件相關的;寫入 1 可以繼續跟蹤。
延時記錄Trace的閾值,當延時超過此值時才開始記錄Trace。單位是ms,只有非0才起作用。
blktrace應用程式使用的跟蹤程式。
blk tracer比較特別,需要設定/sys/block/xxx/trace/enable
才工作,可參考https://lwn.net/Articles/315508/
echo 1 > /sys/block/mmcblk0/trace/enable
echo blk > /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace
# tracer: blk
#
jbd2/mmcblk0p9--1100 [001] ...1 679.901410: 179,0 A WS 323710 + 8 <- (179,9) 265048
jbd2/mmcblk0p9--1100 [001] ...1 679.901428: 179,0 Q WS 323710 + 8 [jbd2/mmcblk0p9-]
jbd2/mmcblk0p9--1100 [001] ...1 679.901469: 179,0 G WS 323710 + 8 [jbd2/mmcblk0p9-]
jbd2/mmcblk0p9--1100 [001] ...1 679.901474: 179,0 P N [jbd2/mmcblk0p9-]
jbd2/mmcblk0p9--1100 [001] ...1 679.901491: 179,0 A WS 323718 + 8 <- (179,9) 265056
mmcqd/0-998 [000] ...1 679.901627: 179,0 m N cfq1100SN dispatch_insert
mmcqd/0-998 [000] ...1 679.901635: 179,0 m N cfq1100SN dispatched a request
mmcqd/0-998 [000] ...1 679.901641: 179,0 m N cfq1100SN activate rq, drv=1
mmcqd/0-998 [000] ...2 679.901645: 179,0 D WS 323710 + 16 [mmcqd/0]
mmcqd/0-998 [000] ...1 679.902979: 179,0 C WS 323710 + 16 [0]
追蹤所有的核心函數
檢視可追蹤的核心函數
root@firefly:~# cd /sys/kernel/debug/tracing/
root@firefly:/sys/kernel/debug/tracing# cat available_filter_functions
顯示和設定當前的tracer
cat available_tracers
blk function_graph wakeup_dl wakeup_rt wakeup irqsoff function nop
cat current_tracer
nop
echo function > current_tracer
echo do_sys_open > set_ftrace_filter
echo 1 > tracing_on
echo 0 > tracing_on
cat trace
echo nop > current_tracer
echo > set_ftrace_filter
輸出
跟蹤條目11個
表示當前系統可用的CPU有16個
程序名字-PID
程序執行在那個CPU上
中斷開關狀態
可以設定為以下值
N:表示程序設定了TIF_NEED_RESCHED
和PREEMPT_NEED_RESCHED
標誌位,說明需要被排程。
n:表示程序僅設定了TIF_NEED_RESCHED
標誌
p:表示程序僅設定了PREEMPT_NEED_RESCHED
標誌
.:表示不需要排程
可以設定為以下值
H:表示在一次軟中斷中發生了硬體中斷
h:表示硬體中斷的發生
s:表示軟體中斷的發生
.:表示沒有中斷髮生
表示搶佔關閉的巢狀層級
用特殊符號表示延時時間
$:大於1s
@:大於100ms
*:大於10ms
!:大於100us
+:大於10us
時間戳。如果開啟了latency-format選項,表示相對時間,即從開始跟蹤算起。否則,使用絕對時間。
表示函數名稱
和「function tracer」比較類似,但它除了探測函數的入口還探測函數的出口。它可以畫出一個圖形化的函數呼叫,類似於c原始碼風格。
echo function_graph > current_tracer
echo do_sys_open > set_graph_function
echo 1 > tracing_on
echo 0 > tracing_on
cat trace
echo nop > current_tracer
echo > set_graph_function
function_graph 和function跟蹤器在Linux version 4.4.194的開發板上發現無法生效,給set_graph_function echo 特定函數後,仍會跟蹤所有函數。但是在Linux version 5.4.0-135 ubuntu18.04中是生效的。不知道是不是核心版本差異的原因?
當關閉中斷時,CPU 會延遲對裝置的狀態變化做出反應,有時候這樣做會對系統效能造成比較大的影響。
irqsoff 跟蹤器可以對中斷被關閉的狀況進行跟蹤,有助於發現導致較大延遲的程式碼;
當出現最大延遲時,跟蹤器會記錄導致延遲的跟蹤資訊,檔案 tracing_max_latency
則記錄中斷被關閉的最大延時,遇到比設定值更大的延遲才會更新。
echo irqsoff > current_tracer
echo 0 > tracing_max_latency
echo 1 >tracing_on
echo 0 >tracing_on
cat trace
latency
表示當前最大的中斷延時為372us,跟蹤條目總和為4個。
started at
和 ended at
顯示發生中斷的開始函數和結束函數分別為run_timer_softirq
。
latency
顯示中斷延時為372us,但是在stack trace
顯示為306us,這是因為在記錄最大延遲資訊時需要花費一些時間。
其他引數說明可參考function跟蹤器。
wakeup:顯示程序從woken到wake up的延時,包括所有程序。
wakeup_dl:顯示SCHED_DEADLINE
型別排程延時。
wakeup_rt:顯示實時程序的排程延時。
echo wakeup > current_tracer
echo 0 > tracing_max_latency
echo 1 > tracing_on
echo 0 > tracing_on
cat trace
核心棧大小是有限的,為了跟蹤核心棧的使用情況,可以使用ftrace stack trace。
使能跟蹤一段時間後,可以檢視最大棧佔用情況,stack_max_size
這裡列印的是最長棧的size。而在stack_trace
中列印的是最長棧的每個函數佔用棧大小的情況,注意這裡也只會記錄的最長的棧情況。
echo stack > current_tracer
echo do_sys_open > stack_trace_filter
echo 1 > /proc/sys/kernel/stack_tracer_enabled
echo 0 > /proc/sys/kernel/stack_tracer_enabled
cat stack_max_size
cat stack_trace
488 表示堆疊大小為488位元組,其中el0_svc_naked
使用了最大的棧空間360。
總結下ftrace 跟蹤器的三步法為:1,設定tracer型別;2,設定tracer引數;3,使能tracer
ftrace中的跟蹤機制主要有兩種,分別是函數和跟蹤點。前者屬於簡單操作,後者可以理解為Linux核心的預留位置函數。
tracepoint可以輸出開發者想要的引數、區域性變數等資訊。
跟蹤點的位置比較固定,一般為核心開發者新增,可以理解為C語言中的#if DEBUG部分。如果執行時不開啟DEBUG,不佔用任何系統開銷。
/sys/kernel/debug/tracing/available_events
定義了當前支援的trace event。
root@firefly:/sys/kernel/debug/tracing# cat available_events
raw_syscalls:sys_exit
raw_syscalls:sys_enter
ipi:ipi_exit
ipi:ipi_entry
ipi:ipi_raise
emulation:instruction_emulation
kvm:kvm_halt_poll_ns
kvm:kvm_age_page
kvm:kvm_fpu
kvm:kvm_mmio
kvm:kvm_ack_irq
kvm:kvm_set_irq
kvm:kvm_vcpu_wakeup
kvm:kvm_userspace_exit
kvm:kvm_toggle_cache
.....
啟用特定event
,如sched_wakeup
,echo到 /sys/kernel/debug/tracing/set_event
。例如:
echo sched_wakeup >> /sys/kernel/debug/tracing/set_event
注意:需要使用>>
,否則會首先disable所有的events
。
關閉特定event,在echo event name到set_event
之前設定一個!
字首,比如
echo '!sched_wakeup' >> /sys/kernel/debug/tracing/set_event
使能所有event,echo *:*
or *:
到set_event
中:
echo *:* > set_event
關閉所有event,echo一個空行到set_event
中
echo > set_event
events
通常以subsystems
的形式展現,例如ext4
, irq
, sched
等等。一個完整的event name類似nfs4:nfs4_access:format。
subsystem name
是可選的,但是它會顯示在available_events
檔案中。一個subsystem
中所有的events
可以通過 :*
語法來表示,
例如:enable所有的irq event:
echo 'irq:*' > set_event
所有有效的trace event
同時會在/sys/kernel/debug/tracing/events/
資料夾中列出。
enable event ‘sched_wakeup’:
echo 1 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
disable:
echo 0 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
enable sched subsystem
中所有的events
:
echo 1 > /sys/kernel/debug/tracing/events/sched/enable
enable所有的events:
echo 1 > /sys/kernel/debug/tracing/events/enable
當讀enable檔案時,可能會有以下4種結果:
0 - all events this file affects are disabled
1 - all events this file affects are enabled
X - there is a mixture of events enabled and disabled
? - this file does not affect any event
為了早期啟動時偵錯,可以使用以下boot選項:
trace_event=[event-list]
event-list是逗號分隔的event列表。
每個trace event
都有一個與它相關聯的format
檔案,該檔案包含log event中每個欄位的描述。這個資訊用來解析二進位制的trace流,其中的欄位也可以在event filter
中找到對它的使用。
它還顯示用於在文字模式下列印事件的格式字串,以及用於分析的事件名稱和ID。
每個event都有一系列通用的欄位,全部都以common_
作為字首。其他的欄位都需要在TRACE_EVENT()
中定義。
format中的每個欄位都有如下形式:
field:field-type field-name; offset:N; size:N;
offset是欄位在trace record
中的offset
,size
是資料項的size
,都是byte
單位。
舉例, sched_wakeup
event的format資訊:
cat /sys/kernel/debug/tracing/events/sched/sched_wakeup/format
name: sched_wakeup
ID: 60
format:
field:unsigned short common_type; offset:0; size:2;
field:unsigned char common_flags; offset:2; size:1;
field:unsigned char common_preempt_count; offset:3; size:1;
field:int common_pid; offset:4; size:4;
field:int common_tgid; offset:8; size:4;
field:char comm[TASK_COMM_LEN]; offset:12; size:16;
field:pid_t pid; offset:28; size:4;
field:int prio; offset:32; size:4;
field:int success; offset:36; size:4;
field:int cpu; offset:40; size:4;
print fmt: "task %s:%d [%d] success=%d [%03d]", REC->comm, REC->pid,
REC->prio, REC->success, REC->cpu
這個event包含10個欄位,5個通用欄位5個自定義欄位。除了COMM
是一個字串,此事件的所有欄位都是數位,這對於事件過濾非常重要。
trace event支援 filter expressions
式的過濾。一旦trace event被記錄到trace buffer中,其欄位就針對與該event型別相關聯的filter expressions
進行檢查。
如果event匹配filter將會被記錄,否則將會被丟棄。如果event沒有設定filter,那麼在任何時刻都是匹配的,event預設就是no filter設定。
一個filter expression由多個 predicates
組成,使用邏輯操作符&&
、||
組合在一起。
field-name relational-operator value
數位類的操作符包括:
==, !=, <, <=, >, >=, &
字元類的操作符包括:
==, !=, ~
約等於操作符(~)接受萬用字元形式 (*,?)和字元類 ([)。舉例:
prev_comm ~ "*sh"
prev_comm ~ "sh*"
prev_comm ~ "*sh*"
prev_comm ~ "ba*sh"
通過將filter expressions
寫入給定event
的filter
檔案來設定單個event
的filter
。
例如
echo 'pid > 1000' > /sys/kernel/debug/tracing/events/sched/sched_wakeup/filter # pid大於100的事件
echo 1 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
cat /sys/kernel/debug/tracing/trace
過濾程序名為rcu_sched的事件
echo 'comm == "rcu_sched"' > /sys/kernel/debug/tracing/events/sched/sched_wakeup/filter
echo 1 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
cat /sys/kernel/debug/tracing/trace
如果表示式中存在錯誤,則在設定時會得到一個Invalid argument
錯誤,錯誤的字串連同錯誤訊息可以通過檢視過濾器來檢視,例如:
cd /sys/kernel/debug/tracing/events/signal/signal_generate
echo '((sig >= 10 && sig < 15) || dsig == 17) && comm != "bash"' > filter
-bash: echo: write error: Invalid argument
cat filter
((sig >= 10 && sig < 15) || dsig == 17) && comm != bash
^
parse_error: Field not found
清除某個event的filter,echo 0 到對應event的filter檔案。
清除某個subsystem中所有events的filter,echo 0 到對應subsystem的filter檔案。
echo 0 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/filter
echo 0 > /sys/kernel/debug/tracing/events/sched/filter
為了方便起見,可以將子系統中的每個事件的過濾器作為一個組來設定或清除,將一個過濾器表示式寫入子系統根目錄下的過濾器檔案中。
如果子系統內的任何事件的過濾器缺少子系統過濾器中指定的欄位,或者如果過濾器不能應用於任何其他原因,則該事件的過濾器將保留其以前的設定。只有參照公共欄位的過濾器才能保證成功地傳播到所有事件。
舉例:
清除sched subsystem
中所有events
的filter
:
echo 0 > /sys/kernel/debug/tracing/events/sched/filter
cat /sys/kernel/debug/tracing/events/sched_switch/filter
none
cat /sys/kernel/debug/tracing/events/sched_wakeup/filter
none
使用sched subsystem
中所有events
都有的通用欄位來設定filter
(所有event將以同樣的filter結束):
echo 'common_pid == 0' > /sys/kernel/debug/tracing/events/sched/filter
cat /sys/kernel/debug/tracing/events/sched/sched_switch/filter
common_pid == 0
cat /sys/kernel/debug/tracing/events/sched/sched_wakeup/filter
common_pid == 0
嘗試使用sched subsystem
中非所有events
通用欄位來設定filter
(所有沒有prev_pid
欄位的event
將保留原有的filter
):
echo prev_pid == 0 > /sys/kernel/debug/tracing/events/sched/filter
cat /sys/kernel/debug/tracing/events/sched/sched_switch/filter
prev_pid == 0
cat /sys/kernel/debug/tracing/events/sched/sched_wakeup/filter
common_pid == 0
頂級資料夾下的set_event_pid
檔案,可以給所有event設定PID過濾:
echo $$ > /sys/kernel/debug/tracing/set_event_pid
echo 1 > /sys/kernel/debug/tracing/events/enable
以上設定將會只追蹤當前程序。
追加PID使用>>
:
echo 123 244 1 >> set_event_pid
跟蹤事件可以有條件地呼叫trigger commands
,每當呼叫具有附加觸發器的trace event時,就會呼叫與該event相關聯的 trigger commands
。
任何給定的觸發器還可以具有與它相關聯的事件過濾中描述的相同形式的事件過濾器。如果呼叫的事件通過關聯的篩選器,則該命令將被呼叫。
給定的event可以有任意數量的trigger與它相關聯,個別命令可能在這方面有所限制。
Event triggers是在「soft」模式上實現的,這意味如果一個event有一個或者多個trigger與之相關聯,即使該event是disable狀態,但實質上已經被actived,然後在「soft」模式中被disable。
也就是說,tracepoint 將被呼叫,但將不會被跟蹤,除非它被正式的enable。該方案允許即使disable的event也可以呼叫trigger,並且還允許當前event filter實現用於有條件地呼叫trigger。
設定event triggers的語法類似於設定set_ftrace_filter
ftrace filter commands
的語法(可以參考‘Filter commands’ section of Documentation/trace/ftrace.txt),但存在很大的差異。
使用echo command 到‘trigger’檔案的形式來增加Trigger:
echo 'command[:count] [if filter]' > trigger
移除Trigger使用同樣的命令,但是加上了 ‘!’ 字首:
echo '!command[:count] [if filter]' > trigger
filter部分的語法和上一節 ‘Event 過濾’ 中描述的相同。
為了方便使用,當前filter只支援使用>
增加或刪除單條trigger,必須使用!
命令逐條移除。
當triggering event被命中時,這些命令可以enable or disable其他的trace event。當這些命令被註冊,trace event變為active。
但是在「soft」 mode下disable。這時,tracepoint會被呼叫但是不會被trace。這些event tracepoint一直保持在這種模式中,直到trigger被觸發。
舉例,當一個read系統呼叫進入,以下的trigger導致kmalloc events被trace,:1
表明該行為只發生一次:
echo 'enable_event:kmem:kmalloc:1' > \
/sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger
當一個read系統呼叫退出,以下的trigger導致kmalloc events被disable trace,每次退出都會呼叫:
echo 'disable_event:kmem:kmalloc' > /sys/kernel/debug/tracing/events/syscalls/sys_exit_read/trigger
命令格式如下:
enable_event:<system>:<event>[:count]
disable_event:<system>:<event>[:count]
移除命令:
echo '!enable_event:kmem:kmalloc:1' > /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger
echo '!disable_event:kmem:kmalloc' > /sys/kernel/debug/tracing/events/syscalls/sys_exit_read/trigger
注意:每個 triggering event可以有任意多個觸發動作,但是每種觸發動作只能有一個。
例如,sys_enter_read
可以觸發enable kmem:kmalloc
和sched:sched_switch
,但是kmem:kmalloc
不能有兩個版本kmem:kmalloc
and kmem:kmalloc:1
或者是kmem:kmalloc if bytes_req == 256
and kmem:kmalloc if bytes_alloc == 256
。
在triggering event發生時,這個命令在trace buffer中dump出堆疊呼叫。
舉例,在每次kmalloc tracepoint被命中,以下的trigger dump出堆疊呼叫,
echo 'stacktrace' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
以下的trigger dump出堆疊呼叫,在kmalloc請求bytes_req >= 800的前2次
echo 'stacktrace:2 if bytes_req >= 800' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
命令格式如下:
stacktrace[:count]
移除命令:
echo '!stacktrace' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
echo '!stacktrace:2 if bytes_req >= 800' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
後者也可以通過下面的(沒有過濾器)更簡單地去除:
echo '!stacktrace:2' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
注意:每個trace event只能有一個stacktrace觸發器。
當triggering event發生時,這個命令會觸發snapshot。
只有程序名為snapd才會建立一個snapshot。
如果你想trace一系列的events or functions,在 trigger event發生時,snapshot trace buffer將會抓住這些events:
echo 'snapshot if comm == "snapd"' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger #設定trigger,只有程序名為snapd才會snapshot
echo 'enable_event:kmem:kmalloc:1' > /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger #觸發kmalloc
cat /sys/kernel/debug/tracing/snapshot #檢視快照
只snapshot一次:
echo 'snapshot:1 if comm == "snapd"' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
echo 'enable_event:kmem:kmalloc:1' > /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger #觸發kmalloc
cat /sys/kernel/debug/tracing/snapshot #檢視快照
移除命令:
echo '!snapshot if comm == "snapd"' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
echo '!snapshot:1 if comm == "snapd"' > /sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
注意:每個trace event只能有一個snapshot觸發器。
這個命令將會把整個trace tracing on/off當event被命中。parameter 決定了系統 turned on/off 多少次。沒有描述就是無限制。
以下命令將 turns tracing off 在block request queue第一次unplugged並且depth > 1,如果您當時正在跟蹤一組事件或函數,則可以檢查跟蹤緩衝區,以檢視導致觸發事件的事件序列:
echo 'traceoff:1 if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
一直disable tracing 當nr_rq > 1:
echo 'traceoff if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
移除命令:
echo '!traceoff:1 if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
echo '!traceoff if nr_rq > 1' > /sys/kernel/debug/tracing/events/block/block_unplug/trigger
注意:每個trace event只能有一個traceon or traceoff觸發器。
組合觸發。這個命令聚合多個trace event的欄位到一個hash表中。
echo 'hist:key=id.syscall,common_pid.execname:val=hitcount:sort=id,hitcount if id == 16' > /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger
cat /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/hist
詳細 可以參考Documentation/trace/histogram.txt。
https://www.kernel.org/doc/html/latest/trace/events.html
https://www.cnblogs.com/hellokitty2/p/17055175.html
https://www.cnblogs.com/fellow1988/p/6417379.html
https://blog.csdn.net/u012489236/article/details/119519361
https://lwn.net/Articles/365835/
https://lwn.net/Articles/366796/
https://www.cnblogs.com/wsg1100/p/17020703.html
https://www.cnblogs.com/arnoldlu/p/7211249.html
https://www.cnblogs.com/hpyu/p/14348151.html
https://mjmwired.net/kernel/Documentation/trace/ftrace.txt
https://mjmwired.net/kernel/Documentation/trace/events.txt
《奔跑吧Linux核心》