利用ftrace跟蹤內核static tracepoint


摘要:和很多linux內核子系統一樣,static tracepoint有很多層次,其中某個層次都展示給不同層次的開發者來滿足他們的不同需求。關於linux tracepoint的詳細信息,我們可以在linux內核文檔Documentation/trace/tracepoints.txt和 samples/tracepoints這兩個地方找到。大致來說,對tracepoints本身的定義是第一個層次,一般只有內核開發者才會定義這些tracepoints;trace event是第二個層次,用於debug;第三個層次就是perf這些內核測試工具,他們調用底層的trace events來監控系統內核的某些特性。

一個tracepoint可以理解為一個linux內核中的占位符函數,內核子系統的開發者常常用它們來debug。static表明這些tracepoint的位置是固定的,你可以把它理解位傳統C程序中的 #if DEBUG部分。如果在運行時沒有開啟,它們是不占用任何系統開銷的。本文主要為你講解如何用ftrace來使用這些tracepoint,當然,你也可以使用perf來使用這些tracepoints。

本文來源:
1.什么是linux static tracepoint

 

 

       所有這些靈活性也有一定的缺點。一個可執行的kprobe有一個顯著的負載——因為它利用了breakpoints和exception hadlers。另一個方面是probe的放置地點:kprobes可以很方便的放置在函數入口或者出口,但是如果你需要把probe放置在函數內部或者需要probe局部變量,那么你就需要systemtap和配置了 CONFIG_DEBUG_INFO的自己編譯的內核。 從這個角度上看,靜態tracepoints可以被放置在函數的任意地方,而且可以越過任意重要的局部變量。linux 2.6.32的主線以后已經實現了比較多的靜態tracepoint。

        增加一個靜態tracepoint是非常簡單的,你可以參考這個例子。在這個例子中,我給已經存在的trace組(irq)增加tracepoint,所以我僅僅需要定義tracepoint和這些tracepoints。你可以在內核的文檔linux/samples/trace_events/trace-events-sample.h中找到一個tracepoint定義的五個部分的解釋。針對更加復雜的例子,可以參考linux/samples/trace_events/。

 

2.使用linux static tracepoint

 

2.1掛載debug文件系統

mount -t debugfs nodev /debug

 

2.2查看可供使用的tracepoints # cat /sys/kernel/debug/tracing/available_events skb:skb_copy_datagram_iovec skb:kfree_skb block:block_rq_remap block:block_remap block:block_split block:block_unplug_io block:block_unplug_timer

Since we added our tracepoints to the irq group, we can find them in tracing/events/irq:

# ls /sys/kernel/debug/tracing/events/irq/ enable irq_handler_entry softirq_entry tasklet_entry filter irq_handler_exit softirq_exit tasklet_exit

Enable the tasklet tracepoints:

# echo 1 > /sys/kernel/debug/tracing/events/irq/tasklet_entry/enable # echo 1 > /sys/kernel/debug/tracing/events/irq/tasklet_exit/enable

And the output is available in the trace buffer:

# cat /sys/kernel/debug/tracing/trace # tracer: nop # # TASK-PID CPU# TIMESTAMP FUNCTION # | | | | | -0 [000] 327.349213: tasklet_entry: func=.rpavscsi_task -0 [000] 327.349217: tasklet_exit: func=.rpavscsi_task

When finished, we can disable the tracepoints. There are enable files at all levels of the hierarchy, so we can disable all tracepoints in one go:

# echo 0 > /sys/kernel/debug/tracing/events/enable

 

3.在內核模塊中使用靜態tracepoints

 

Kernel modules can also make use of static tracepoints. A simple module that hooks the tasklet_entry tracepoint and printks the function name of the tasklet might look like (I’ve called it tracepoint-example.c):

 


#include <linux/interrupt.h>
#include <linux/module.h>
#include <trace/events/irq.h>
static void probe_tasklet_entry(struct tasklet_struct *t)
{
printk("tasklet_entry %pf\n", t->func);
}
static int __init trace_init(void)
{
WARN_ON(register_trace_tasklet_entry(probe_tasklet_entry));
return 0;
}

static void __exit trace_exit(void)
{
unregister_trace_tasklet_entry(probe_tasklet_entry);
}
module_init(trace_init)
module_exit(trace_exit)
MODULE_LICENSE("GPL");

 

4 利用ftrace跟蹤static tracepoints

 

以下所有操作均在/debug/tracing目錄下進行

大致的步驟為:設定要監控的event,實際上也就是要監控的一系列的tracepoints;設定tracer成nop;開啟tracing_on;查看結果。

 

4.1 使用event有兩種方式

 

i) 通過set_event文件

events被組織成一個個子系統,如ext4,irq,sched等待,一個完整的event name是這樣的:<subsystem>:<event>,其中subsystem是可選的,一個子系統中所有的events可以通過<subsystem>:*指定。

 

 

  • #echo *:* > set_event
  • #echo 'irq:*' > set_event

 

 

ii) 通過'enable' toggle

 

 

 

實例:我們需要監控writeback子系統,那么需要進行如下設定

$:echo writeback > set_event

 

 

 

 

4.2開啟監控

$:echo nop > current_tracer

$:echo 1 > tracing_on

(wait for a moment......)

 

 

4.3結果查看:event trace的意義

 

$:cat trace | head -20 

輸出結果如下:

 

利用ftrace跟蹤內核static tracepoint

 

 

 

關於輸出結果的意義,可以到對應events下面,利用cat fromat查看輸出格式和意義

利用ftrace跟蹤內核static tracepoint

 

這里,不以common_開頭的filed是每個event特有的。每一個event對應的有一個TRACE_EVENT定義一個record,這里offset為field在record中的偏移,size為其大小。下載一個內核,在samples/trace_events目錄下有一個例子,可以查看TRACE_EVENT的定義方法。

 

4.4event filter

語法:

 

  • field-name relation-operatior value                           //一個predicate

 

可以通過'&&', '||',以及圓括號將幾個predicate組合起來。對於數字域,可以使用操作符==, !=, < , > , <=, >=,對於字符串域,可以使用==, !=。目前字符串只支持完全匹配,且最多可以組合16個predicate。

例子:

 

 

  • #cd /sys/kernel/debug/tracing/events/signal/signal_generate
  • #echo "((sig >= 10 && sig < 15) || sig == 17) && comm != bash" > filter

 

 

每個子系統都有獨立的filter文件支持,如:

 

 

 

可以看到,雖然將sched子系統的filter設為prev_pid == 0,但由於只有sched_switch事件存在prev_pid域,所以對sched的filter文件的設置只影響了sched_switch。

 

 

4.5定義一個event-enabled tracepoint

定義tracepoint不在本文討論范圍之內

 


參考文檔:

 

【1】Linux Static Tracepoints    【2】 

【3】ftrace 學習筆記:

【4】tracing on linux  


免責聲明!

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



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