簡介
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框架可以分為幾部分: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
Trace文件系統
配置內核支持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/tracingtracefsdefaults00
或者在運行時掛在:
mount-ttracefsnodev/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 READMEkprobe_profileset_graph_function available_eventsmax_graph_depthset_graph_notrace available_filter_functionsoptionssnapshot available_tracersper_cputrace buffer_size_kbprintk_formatstrace_clock buffer_total_size_kbsaved_cmdlinestrace_marker current_tracersaved_cmdlines_sizetrace_options dyn_ftrace_total_infosaved_tgidstrace_pipe enabled_functionsset_eventtracing_cpumask eventsset_event_pidtracing_max_latency free_bufferset_ftrace_filtertracing_on instancesset_ftrace_notracetracing_thresh kprobe_eventsset_ftrace_pid
available_events
用于設置或顯示當前使用的跟蹤器;使用 echo 將跟蹤器名字寫入該文件可以切換到不同的跟蹤器。系統啟動后,其缺省值為 nop ,即不做任何跟蹤操作。在執行完一段跟蹤任務后,可以通過向該文件寫入 nop 來重置跟蹤器。
available_filter_functions
記錄了當前可以跟蹤的內核函數。對于不在該文件中列出的函數,無法跟蹤其活動。
available_tracers
記錄了當前編譯進內核的跟蹤器的列表,可以通過 cat 查看其內容;寫 current_tracer 文件時用到的跟蹤器名字必須在該文件列出的跟蹤器名字列表中。
buffer_size_kb
用于設置單個 CPU 所使用的跟蹤緩存的大小。跟蹤器會將跟蹤到的信息寫入緩存,每個 CPU 的跟蹤緩存是一樣大的。跟蹤緩存實現為環形緩沖區的形式,如果跟蹤到的信息太多,則舊的信息會被新的跟蹤信息覆蓋掉。注意,要更改該文件的值需要先將 current_tracer 設置為 nop 才可以。
buffer_total_size_kb
顯示所有的跟蹤緩存大小,不同之處在于buffer_size_kb是單個CPU的,buffer_total_size_kb是所有CPU的和。
trace_pipe
輸出和trace一樣的內容,輸出實時tracing日志,這樣就避免了RingBuffer的溢出。cat trace_pipe > trace.txt &保存文件,但是cat時候會帶來一些性能損耗。
trace_options
控制Trace打印內容格式或者設置跟蹤器,可以通過trace_options添加很多附加信息。
current_tracer
設置和顯示當前正在使用的跟蹤器。使用echo命令可以把跟蹤器的名字寫入current_tracer文件,從而切換不同的跟蹤器。
dyn_ftrace_total_info
debug使用,顯示available_filter_functins中跟中函數的數目,兩者一致。
enabled_functions
顯示有回調附著的函數名稱。這個文件更多的是用于調試ftrace,但也可以用于查看是否有任何函數附加了回調。不僅ftrace框架使用ftrace函數tracing,其他子系統也可能使用。該文件顯示所有附加回調的函數,以及附加回調的數量。注意,一個回調也可以調用多個函數,這些函數不會在這個計數中列出。
如果回調被一個帶有"save regs"屬性的函數注冊tracing(這樣開銷更大),一個’R’將顯示在與返回寄存器的函數的同一行上。
如果回調被一個帶有"ip modify"屬性的函數注冊tracing(這樣regs->ip就可以被修改),'I’將顯示在可以被覆蓋的函數的同一行上。
如果體系架構支持,它還將顯示函數直接調用的回調。如果計數大于1,則很可能是ftrace_ops_list_func()。
如果函數的回調跳轉到特定于回調而不是標準的"跳轉點"的跳轉點,它的地址將和跳轉點調用的函數一起打印。
events
系統Trace events目錄,在每個events下面都有enable、filter和fotmat。enable是開關;format是events的格式,然后根據格式設置 filter。
free_buffer
在關閉該文件時,ring buffer將被調整為其最小大小。如果有一個tracing的進程也打開了這個文件,當該進程退出,該文件的描述符將被關閉,在此過程,ring bufer也將被"freed"。
如果options/disable_on_free選項被設置將會停止tracing。
kprobe_events
激活 dynamic trace opoints。參考內核文檔Documentation/trace/kprobetrace.rst。
kprobe_profile
Dynamic trace points 統計信息。 參考內核文檔Documentation/trace/kprobetrace.rst。
max_graph_depth
被用于function_graph tracer。這是tracing一個函數的最大深度。將其設置為1將只顯示從用戶空間調用的第一個內核函數。
options
目錄文件,里面是每個trace options的文件,和trace_options對應,可以通過echo 0/1使能options。
per_cpu:包含跟蹤 per_cpu 信息的目錄。
per_cpu/cpu0/buffer_size_kb:配置per_cpu的buffer空間
per_cpu/cpu0/trace:當前CPU的trace文件。
per_cpu/cpu0/trace_pipe:當前CPU的trace_pipe文件。
per_cpu/cpu0/trace_pipe_raw:當前CPU的trace_pipe_raw
per_cpu/cpu0/snapshot:當前CPU的snapshot
per_cpu/cpu0/snapshot_raw:當前CPU的snapshot_raw
per_cpu/cpu0/stats:當前CPU的trace統計信息
printk_formats
提供給工具讀取原始格式trace的文件。如果環形緩沖區中的事件引用了一個字符串,則只有指向該字符串的指針被記錄到緩沖區中,而不是字符串本身。這可以防止工具知道該字符串是什么。該文件顯示字符串和字符串的地址,允許工具將指針映射到字符串的內容。
saved_cmdlines
ftrace會存放pid的comms在一個pid mappings,在顯示event時候同時顯示comm,這里可以配置pid對應的comm,如果配置,顯示類似
saved_cmdlines_size
saved_cmdlines的數目,默認為128
saved_tgids
如果設置了選項“record-tgid”,則在每個調度上下文切換時,任務的任務組 ID 將保存在將線程的 PID 映射到其 TGID 的表中。默認情況下,“record-tgid”選項被禁用。
set_event
也可以在系統特定事件觸發的時候打開跟蹤。為了啟用某個事件,你需要:echo sys_enter_nice >> set_event(注意你是將事件的名字追加到文件中去,使用>>追加定向器,不是>)。要禁用某個事件,需要在名字前加上一個“!”號:echo '!sys_enter_nice' >> set_event。以下三種方式都可以啟用事件
echosched:sched_switch>>/debug/tracing/set_event echosched_switch>>/debug/tracing/set_event echo1>/debug/tracing/events/sched/sched_switch/enable
set_event_pid
tracer將只追蹤寫入此文件PID的對應進程的event。"event-fork" option設置后,pid對應進程創建的子進程event也會自動跟蹤。
set_ftrace_filter 和 set_ftrace_notrace
在編譯內核時配置了動態 ftrace (選中 CONFIG_DYNAMIC_FTRACE 選項)后使用。前者用于顯示指定要跟蹤的函數,后者則作用相反,用于指定不跟蹤的函數。
如果一個函數名同時出現在這兩個文件中,則這個函數的執行狀況不會被跟蹤。這些文件還支持簡單形式的含有通配符的表達式,這樣可以用一個表達式一次指定多個目標函數;注意,要寫入這兩個文件的函數名必須可以在文件 available_filter_functions 中看到。
缺省為可以跟蹤所有內核函數,文件 set_ftrace_notrace 的值則為空。甚至可以對函數的名字使用通配符。例如,要用所有的vmalloc_函數,通過echo vmalloc_* > set_ftrace_filter進行設置。
set_ftrace_pid
tracer將只追蹤寫入此文件PID的對應的進程。"function-fork" option設置后,pid對應進程創建的子進程也會自動跟蹤。
set_graph_function
設置要清晰顯示調用關系的函數,顯示的信息結構類似于 C 語言代碼,這樣在分析內核運作流程時會更加直觀一些。在使用 function_graph 跟蹤器時使用;缺省為對所有函數都生成調用關系序列,可以通過寫該文件來指定需要特別關注的函數。
echofunction_graph>current_tracer echo__do_fault>set_graph_function//跟蹤__do_fault
snapshot
是對trace的snapshot。
echo 0清空緩存,并釋放對應內存。
echo 1進行對當前trace進行snapshot,如沒有內存則分配。
echo 2清空緩存,不釋放也不分配內存。
trace
文件提供了查看獲取到的跟蹤信息的接口。可以通過 cat 等命令查看該文件以查看跟蹤到的內核活動記錄,也可以將其內容保存為記錄文件以備后續查看。
trace_clock
每當一個事件被記錄到環形緩沖區中時,都會添加一個“時間戳”。此標記來自指定的時鐘。默認情況下,ftrace 使用“本地”時鐘。本地時鐘可能與其他 CPU 上的本地時鐘不同步。
local:默認時鐘,在每CPU中快速且精準,但是可能不會在各個CPU之間同步;
global:各CPU間同步,但是比local慢;
counter:并不是時鐘,而是一個原子計數器。數值一直+1,但是所有cpu是同步的。主要用處是分析不同cpu發生的events
uptime:time stamp和jiffies counter根據boot time;
perf:clock跟perf使用一致。
x86-tsc:非系統自己時鐘。比如x86有TSC cycle clock;
ppc-tb:使用powerpc的基礎時鐘寄存器值;
mono:使用fast monotonic clock (CLOCK_MONOTONIC)
mono_raw:使用raw monotonic clock (CLOCK_MONOTONIC_RAW)
boot:使用boot clock (CLOCK_BOOTTIME)。
trace_marker
用于將用戶空間與內核空間中發生的事件同步。將字符串寫入該文件將被寫入ftrace緩沖區。
在應用程序中,應用程序開始打開這個文件并引用文件描述符::
voidtrace_write(constchar*fmt,...) { va_listap; charbuf[256]; intn; if(trace_fd0) ??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_options
此文件允許用戶控制在上述輸出文件之一中顯示的數據量。還存在用于修改跟蹤器或事件的工作方式(堆棧跟蹤、時間戳等)的選項。
trace_pipe:"trace_pipe"輸出與"trace"文件相同的內容,但是對跟蹤的影響不同。每次從"trace_pipe"讀取都會被消耗。這意味著后續的讀取將有所不同。跟蹤是動態的:
#echofunction>current_tracer #cattrace_pipe>/tmp/trace.out& [1]4153 #echo1>tracing_on #usleep1 #echo0>tracing_on #cattrace #tracer:function # #entries-in-buffer/entries-written:0/0#P:4 # #_-----=>irqs-off #/_----=>need-resched #|/_---=>hardirq/softirq #||/_--=>preempt-depth #|||/delay #TASK-PIDCPU#||||TIMESTAMPFUNCTION #||||||||| # #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"文件沒有這個限制。
tracing_cpumask
可以通過此文件設置跟蹤指定CPU,二進制格式。
tracing_max_latency
記錄某些Tracer的最大延時。比如interrupts的最大延時關閉后,會記錄在這里。可以echo值到此文件,然后遇到比設置值更大的延遲才會更新。
tracing_on
用于控制跟蹤的暫停。有時候在觀察到某些事件時想暫時關閉跟蹤,可以將 0 寫入該文件以停止跟蹤,這樣跟蹤緩沖區中比較新的部分是與所關注的事件相關的;寫入 1 可以繼續跟蹤。
tracing_thresh
延時記錄Trace的閾值,當延時超過此值時才開始記錄Trace。單位是ms,只有非0才起作用。
跟蹤器使用方法
blk跟蹤器
blktrace應用程序使用的跟蹤程序。
blk tracer比較特別,需要設置/sys/block/xxx/trace/enable 才工作,可參考https://lwn.net/Articles/315508/
echo1>/sys/block/mmcblk0/trace/enable echoblk>/sys/kernel/debug/tracing/current_tracer echo1>/sys/kernel/debug/tracing/tracing_on cat/sys/kernel/debug/tracing/trace #tracer:blk # jbd2/mmcblk0p9--1100[001]...1679.901410:179,0AWS323710+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]
function跟蹤器
追蹤所有的內核函數
查看可追蹤的內核函數
root@firefly:~#cd/sys/kernel/debug/tracing/ root@firefly:/sys/kernel/debug/tracing#catavailable_filter_functions
顯示和配置當前的tracer
catavailable_tracers blkfunction_graphwakeup_dlwakeup_rtwakeupirqsofffunctionnop catcurrent_tracer nop echofunction>current_tracer echodo_sys_open>set_ftrace_filter echo1>tracing_on echo0>tracing_on cattrace echonop>current_tracer echo>set_ftrace_filter
輸出
11/11
跟蹤條目11個
#P16
表示當前系統可用的CPU有16個
TASK-PID
進程名字-PID
CPU#
進程運行在那個CPU上
irqs-off
中斷開關狀態
need-resched
可以設置為以下值
N:表示進程設置了TIF_NEED_RESCHED和PREEMPT_NEED_RESCHED標志位,說明需要被調度。
n:表示進程僅設置了TIF_NEED_RESCHED標志
p:表示進程僅設置了PREEMPT_NEED_RESCHED標志
.:表示不需要調度
hardirq/softirq
可以設置為以下值
H:表示在一次軟中斷中發生了硬件中斷
h:表示硬件中斷的發生
s:表示軟件中斷的發生
.:表示沒有中斷發生
preempt-depth
表示搶占關閉的嵌套層級
delay
用特殊符號表示延時時間
$:大于1s
@:大于100ms
*:大于10ms
#:大于1000us
!:大于100us
+:大于10us
TIMESTATION
時間戳。如果打開了latency-format選項,表示相對時間,即從開始跟蹤算起。否則,使用絕對時間。
FUNCTION
表示函數名稱
function_graph跟蹤器
和“function tracer”比較類似,但它除了探測函數的入口還探測函數的出口。它可以畫出一個圖形化的函數調用,類似于c源代碼風格。
echofunction_graph>current_tracer echodo_sys_open>set_graph_function echo1>tracing_on echo0>tracing_on cattrace echonop>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中是生效的。不知道是不是內核版本差異的原因?
irqsoff跟蹤器
當關閉中斷時,CPU 會延遲對設備的狀態變化做出反應,有時候這樣做會對系統性能造成比較大的影響。
irqsoff 跟蹤器可以對中斷被關閉的狀況進行跟蹤,有助于發現導致較大延遲的代碼;
當出現最大延遲時,跟蹤器會記錄導致延遲的跟蹤信息,文件 tracing_max_latency 則記錄中斷被關閉的最大延時,遇到比設置值更大的延遲才會更新。
echoirqsoff>current_tracer echo0>tracing_max_latency echo1>tracing_on echo0>tracing_on cattrace

latency表示當前最大的中斷延時為372us,跟蹤條目總和為4個。
started at 和 ended at 顯示發生中斷的開始函數和結束函數分別為run_timer_softirq。
latency顯示中斷延時為372us,但是在stack trace 顯示為306us,這是因為在記錄最大延遲信息時需要花費一些時間。
其他參數說明可參考function跟蹤器。
wakeup/wakeup_rt/wakeup_dl跟蹤器
wakeup:顯示進程從woken到wake up的延時,包括所有進程。
wakeup_dl:顯示SCHED_DEADLINE類型調度延時。
wakeup_rt:顯示實時進程的調度延時。
echowakeup>current_tracer echo0>tracing_max_latency echo1>tracing_on echo0>tracing_on cattrace

stack跟蹤器
內核棧大小是有限的,為了跟蹤內核棧的使用情況,可以使用ftrace stack trace。
使能跟蹤一段時間后,可以查看最大棧占用情況,stack_max_size這里打印的是最長棧的size。而在stack_trace 中打印的是最長棧的每個函數占用棧大小的情況,注意這里也只會記錄的最長的棧情況。
echostack>current_tracer echodo_sys_open>stack_trace_filter echo1>/proc/sys/kernel/stack_tracer_enabled echo0>/proc/sys/kernel/stack_tracer_enabled catstack_max_size catstack_trace

488 表示堆棧大小為488字節,其中el0_svc_naked使用了最大的棧空間360。
小結
總結下ftrace 跟蹤器的三步法為:1,設置tracer類型;2,設置tracer參數;3,使能tracer
trace event 用法
ftrace中的跟蹤機制主要有兩種,分別是函數和跟蹤點。前者屬于簡單操作,后者可以理解為Linux內核的占位符函數。
tracepoint可以輸出開發者想要的參數、局部變量等信息。
跟蹤點的位置比較固定,一般為內核開發者添加,可以理解為C語言中的#if DEBUG部分。如果運行時不開啟DEBUG,不占用任何系統開銷。
trace event使用方法
set_event接口
/sys/kernel/debug/tracing/available_events定義了當前支持的trace event。
root@firefly:/sys/kernel/debug/tracing#catavailable_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。例如:
echosched_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類似nfs4format。
subsystem name是可選的,但是它會顯示在available_events文件中。一個subsystem中所有的events可以通過 :*語法來表示,
例如:enable所有的irq event:
echo'irq:*'>set_event
enable接口
所有有效的trace event同時會在/sys/kernel/debug/tracing/events/文件夾中列出。
enable event ‘sched_wakeup’:
echo1>/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
disable:
echo0>/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
enable sched subsystem中所有的events:
echo1>/sys/kernel/debug/tracing/events/sched/enable
enable所有的events:
echo1>/sys/kernel/debug/tracing/events/enable
當讀enable文件時,可能會有以下4種結果:
0-alleventsthisfileaffectsaredisabled 1-alleventsthisfileaffectsareenabled X-thereisamixtureofeventsenabledanddisabled ?-thisfiledoesnotaffectanyevent
為了早期啟動時調試,可以使用以下boot選項:
trace_event=[event-list]
event-list是逗號分隔的event列表。
event格式
每個trace event都有一個與它相關聯的format文件,該文件包含log event中每個字段的描述。這個信息用來解析二進制的trace流,其中的字段也可以在event filter中找到對它的使用。
它還顯示用于在文本模式下打印事件的格式字符串,以及用于分析的事件名稱和ID。
每個event都有一系列通用的字段,全部都以common_作為前綴。其他的字段都需要在TRACE_EVENT()中定義。
format中的每個字段都有如下形式:
field:field-typefield-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:unsignedshortcommon_type;offset:0;size:2; field:unsignedcharcommon_flags;offset:2;size:1; field:unsignedcharcommon_preempt_count;offset:3;size:1; field:intcommon_pid;offset:4;size:4; field:intcommon_tgid;offset:8;size:4; field:charcomm[TASK_COMM_LEN];offset:12;size:16; field:pid_tpid;offset:28;size:4; field:intprio;offset:32;size:4; field:intsuccess;offset:36;size:4; field:intcpu;offset:40;size:4; printfmt:"task%s:%d[%d]success=%d[%03d]",REC->comm,REC->pid, REC->prio,REC->success,REC->cpu
這個event包含10個字段,5個通用字段5個自定義字段。除了COMM是一個字符串,此事件的所有字段都是數字,這對于事件過濾非常重要。
event 過濾
trace event支持 filter expressions式的過濾。一旦trace event被記錄到trace buffer中,其字段就針對與該event類型相關聯的filter expressions進行檢查。
如果event匹配filter將會被記錄,否則將會被丟棄。如果event沒有配置filter,那么在任何時刻都是匹配的,event默認就是no filter配置。
語法
一個filter expression由多個 predicates組成,使用邏輯操作符&&、||組合在一起。
field-namerelational-operatorvalue
數字類的操作符包括:
==,!=,<,?<=,?>,>=,&
字符類的操作符包括:
==,!=,~
約等于操作符(~)接受通配符形式 (*,?)和字符類 ([)。舉例:
prev_comm~"*sh" prev_comm~"sh*" prev_comm~"*sh*" prev_comm~"ba*sh"
配置filters
通過將filter expressions寫入給定event的filter文件來設置單個event的filter。
例如
echo'pid>1000'>/sys/kernel/debug/tracing/events/sched/sched_wakeup/filter#pid大于100的事件 echo1>/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 echo1>/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&&sig15)?||?dsig?==?17)?&&?comm?!=?"bash"'??>filter -bash:echo:writeerror:Invalidargument catfilter ((sig>=10&&sig15)?||?dsig?==?17)?&&?comm?!=?bash ^ parse_error:?Field?not?found
清除filters
清除某個event的filter,echo 0 到對應event的filter文件。
清除某個subsystem中所有events的filter,echo 0 到對應subsystem的filter文件。
echo0>/sys/kernel/debug/tracing/events/sched/sched_wakeup/filter echo0>/sys/kernel/debug/tracing/events/sched/filter
子系統filters
為了方便起見,可以將子系統中的每個事件的過濾器作為一個組來設置或清除,將一個過濾器表達式寫入子系統根目錄下的過濾器文件中。
如果子系統內的任何事件的過濾器缺少子系統過濾器中指定的字段,或者如果過濾器不能應用于任何其他原因,則該事件的過濾器將保留其以前的設置。只有引用公共字段的過濾器才能保證成功地傳播到所有事件。
舉例:
清除sched subsystem中所有events的filter:
echo0>/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):
echoprev_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
PID filters
頂級文件夾下的set_event_pid 文件,可以給所有event配置PID過濾:
echo$$>/sys/kernel/debug/tracing/set_event_pid echo1>/sys/kernel/debug/tracing/events/enable

以上配置將會只追蹤當前進程。
追加PID使用>>:
echo1232441>>set_event_pid
Event triggers
跟蹤事件可以有條件地調用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][iffilter]'>trigger
移除Trigger使用同樣的命令,但是加上了 ‘!’ 前綴:
echo'!command[:count][iffilter]'>trigger
filter部分的語法和上一節 ‘Event 過濾’ 中描述的相同。
為了方便使用,當前filter只支持使用>增加或刪除單條trigger,必須使用!命令逐條移除。
支持的命令
enable_event/disable_event
當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_eventkmalloc:1'> /sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger

當一個read系統調用退出,以下的trigger導致kmalloc events被disable trace,每次退出都會調用:
echo'disable_eventkmalloc'>/sys/kernel/debug/tracing/events/syscalls/sys_exit_read/trigger

命令格式如下:
enable_event:: [:count] disable_event: : [:count]
移除命令:
echo'!enable_eventkmalloc:1'>/sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger echo'!disable_eventkmalloc'>/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 kmem1或者是kmem:kmalloc if bytes_req == 256 and kmem:kmalloc if bytes_alloc == 256。
stacktrace
在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:2ifbytes_req>=800'>/sys/kernel/debug/tracing/events/kmem/kmalloc/trigger

命令格式如下:
stacktrace[:count]
移除命令:
echo'!stacktrace'>/sys/kernel/debug/tracing/events/kmem/kmalloc/trigger echo'!stacktrace:2ifbytes_req>=800'>/sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
后者也可以通過下面的(沒有過濾器)更簡單地去除:
echo'!stacktrace:2'>/sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
注意:每個trace event只能有一個stacktrace觸發器。
snapshot
當triggering event發生時,這個命令會觸發snapshot。
只有進程名為snapd才會創建一個snapshot。
如果你想trace一系列的events or functions,在 trigger event發生時,snapshot trace buffer將會抓住這些events:
echo'snapshotifcomm=="snapd"'>/sys/kernel/debug/tracing/events/kmem/kmalloc/trigger#配置trigger,只有進程名為snapd才會snapshot echo'enable_eventkmalloc:1'>/sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger#觸發kmalloc cat/sys/kernel/debug/tracing/snapshot#查看快照

只snapshot一次:
echo'snapshot:1ifcomm=="snapd"'>/sys/kernel/debug/tracing/events/kmem/kmalloc/trigger echo'enable_eventkmalloc:1'>/sys/kernel/debug/tracing/events/syscalls/sys_enter_read/trigger#觸發kmalloc cat/sys/kernel/debug/tracing/snapshot#查看快照
移除命令:
echo'!snapshotifcomm=="snapd"'>/sys/kernel/debug/tracing/events/kmem/kmalloc/trigger echo'!snapshot:1ifcomm=="snapd"'>/sys/kernel/debug/tracing/events/kmem/kmalloc/trigger
注意:每個trace event只能有一個snapshot觸發器。
traceon/traceoff
這個命令將會把整個trace tracing on/off當event被命中。parameter 決定了系統 turned on/off 多少次。沒有描述就是無限制。
以下命令將 turns tracing off 在block request queue第一次unplugged并且depth > 1,如果您當時正在跟蹤一組事件或函數,則可以檢查跟蹤緩沖區,以查看導致觸發事件的事件序列:
echo'traceoff:1ifnr_rq>1'>/sys/kernel/debug/tracing/events/block/block_unplug/trigger
一直disable tracing 當nr_rq > 1:
echo'traceoffifnr_rq>1'>/sys/kernel/debug/tracing/events/block/block_unplug/trigger
移除命令:
echo'!traceoff:1ifnr_rq>1'>/sys/kernel/debug/tracing/events/block/block_unplug/trigger echo'!traceoffifnr_rq>1'>/sys/kernel/debug/tracing/events/block/block_unplug/trigger
注意:每個trace event只能有一個traceon or traceoff觸發器。
hist
組合觸發。這個命令聚合多個trace event的字段到一個hash表中。
echo'hist:key=id.syscall,common_pid.execname:val=hitcount:sort=id,hitcountifid==16'>/sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger cat/sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/hist

審核編輯:劉清
-
ECHO
+關注
關注
1文章
73瀏覽量
27550 -
PID控制
+關注
關注
10文章
461瀏覽量
40960 -
跟蹤器
+關注
關注
0文章
132瀏覽量
20353 -
nop
+關注
關注
0文章
9瀏覽量
2055
原文標題:【調試】ftrace(一)基本使用方法
文章出處:【微信號:嵌入式與Linux那些事,微信公眾號:嵌入式與Linux那些事】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
談談什么是文件系統 文件系統的功能與特點

Linux文件系統課程
基于μC/OS-II的文件系統設計
NTFS文件系統,NTFS文件系統是什么意思
XfS文件系統,XfS文件系統是什么意思
文件系統是什么?淺談EXT文件系統歷史

可以了解的Linux 文件系統結構

linux文件系統中的虛擬文件系統設計詳解

評論