使用 ftrace 調試 Linux 內核,第 3 部分

ftrace 提供的工具函數 html

王 生輝, 軟件工程師, EMC
李 驊宸, 實習生, EMC

簡介: ftrace 是 Linux 內核中提供的一種調試工具。使用 ftrace 能夠對內核中發生的事情進行跟蹤,這在調試 bug 或者分析內核時很是有用。本系列文章對 ftrace 進行了介紹,分爲三部分。本文是第三部分,經過示例代碼介紹如何在代碼中使用 ftrace 提供的工具函數,以與 ftrace 交互。經過本文的講解,讀者能夠在實際代碼中使用 ftrace,方便了調試和分析。 linux

發佈日期: 2010 年 6 月 10 日 
級別: 初級 
訪問狀況 : 4274 次瀏覽 
評論: 0 (查看 | 添加評論 - 登陸) 框架

平均分 5 星 共 15 個評分 平均分 (15個評分)
爲本文評分


內容

內核頭文件 include/linux/kernel.h 中描述了 ftrace 提供的工具函數的原型,這些函數包括 trace_printk、tracing_on/tracing_off 等。本文經過示例模塊程序向讀者展現如何在代碼中使用這些工具函數。 less

使用 trace_printk 打印跟蹤信息 jsp

ftrace 提供了一個用於向 ftrace 跟蹤緩衝區輸出跟蹤信息的工具函數,叫作 trace_printk(),它的使用方式與 printk() 相似。能夠經過 trace 文件讀取該函數的輸出。從頭文件 include/linux/kernel.h 中能夠看到,在激活配置 CONFIG_TRACING 後,trace_printk() 定義爲宏: 函數

#define trace_printk(fmt, args...)   		 \ 
        ...

下面經過一個示例模塊 ftrace_demo 來演示如何使用 trace_printk() 向跟蹤緩衝區輸出信息,以及如何查看這些信息。這裏的示例模塊程序中僅提供了初始化和退出函數,這樣讀者不會由於須要爲模塊建立必要的訪問接口好比設備文件而分散注意力。注意,編譯模塊時要加入 -pg 選項。 工具


清單 1. 示例模塊 ftrace_demo
/*                                                     
 * ftrace_demo.c 
 */                                                    
 #include <linux/init.h> 
 #include <linux/module.h> 
 #include <linux/kernel.h> 

 MODULE_LICENSE("GPL"); 

 static int ftrace_demo_init(void) 
 { 
	 trace_printk("Can not see this in trace unless loaded for the second time\n"); 
	 return 0; 
 } 

 static void ftrace_demo_exit(void) 
 { 
	 trace_printk("Module unloading\n"); 
 } 

 module_init(ftrace_demo_init); 
 module_exit(ftrace_demo_exit);

示例模塊很是簡單,僅僅是在模塊初始化函數和退出函數中輸出信息。接下來要對模塊的運行進行跟蹤,如清單 2 所示。 學習


清單 2. 對模塊 ftrace_demo 進行跟蹤
[root@linux tracing]# pwd 
 /sys/kernel/debug/tracing 
 [root@linux tracing]# echo 0 > tracing_enabled 
 [root@linux tracing]# echo 1 > /proc/sys/kernel/ftrace_enabled 
 [root@linux tracing]# echo function_graph > current_tracer 

 # 事先加載模塊 ftrace_demo 

 [root@linux tracing]# echo ':mod:ftrace_demo' > set_ftrace_filter 
 [root@linux tracing]# cat set_ftrace_filter 
 ftrace_demo_init 
 ftrace_demo_exit 

 # 將模塊 ftrace_demo 卸載

 [root@linux tracing]# echo 1 > tracing_enabled 

 # 從新進行模塊 ftrace_demo 的加載與卸載操做

 [root@linux tracing]# cat trace 
 # tracer: function_graph 
 # 
 # CPU  DURATION                  FUNCTION CALLS 
 # |     |   |                     |   |   |   | 
 1)               |  /* Can not see this in trace unless loaded for the second time */ 
 0)               |  /* Module unloading */

在這個例子中,使用 mod 指令顯式指定跟蹤模塊 ftrace_demo 中的函數,這須要提早加載該模塊,不然在寫文件 set_ftrace_filter 時會由於找不到該模塊報錯。這樣在第一次加載模塊時,其初始化函數 ftrace_demo_init 中調用 trace_printk 打印的語句就跟蹤不到了。所以這裏會將其卸載,而後激活跟蹤,再從新進行模塊 ftrace_demo 的加載與卸載操做。最終能夠從文件 trace 中看到模塊在初始化和退出時調用 trace_printk() 輸出的信息。 測試

這裏僅僅是爲了以簡單的模塊進行演示,故只定義了模塊的 init/exit 函數,重複加載模塊也只是爲了獲取初始化函數輸出的跟蹤信息。實踐中,能夠在模塊的功能函數中加入對 trace_printk 的調用,這樣能夠記錄模塊的運做狀況,而後對其特定功能進行調試優化。還能夠將對 trace_printk() 的調用經過宏來控制編譯,這樣能夠在調試時將其開啓,在最終發佈時將其關閉。 優化

回頁首

使用 tracing_on/tracing_off 控制跟蹤信息的記錄

在跟蹤過程當中,有時候在檢測到某些事件發生時,想要中止跟蹤信息的記錄,這樣,跟蹤緩衝區中較新的數據是與該事件有關的。在用戶態,能夠經過向文件 tracing_on 寫入 0 來中止記錄跟蹤信息,寫入 1 會繼續記錄跟蹤信息。而在內核代碼中,能夠經過函數 tracing_on() 和 tracing_off() 來作到這一點,它們的行爲相似於對 /sys/kernel/debug/tracing 下的文件 tracing_on 分別執行寫 1 和 寫 0 的操做。使用這兩個函數,會對跟蹤信息的記錄控制地更準確一些,這是由於在用戶態寫文件 tracing_on 到實際暫停跟蹤,中間因爲上下文切換、系統調度控制等可能已經通過較長的時間,這樣會積累大量的跟蹤信息,而感興趣的那部分可能會被覆蓋掉了。

如今對清單 1 中的代碼進行修改,使用 tracing_off() 來控制跟蹤信息記錄的暫停。


清單 3. 使用 tracing_off 的模塊 ftrace_demo
/*                                                     
 * ftrace_demo.c 
 *     modified to demostrate the usage of tracing_off 
 */                                                    
 #include <linux/init.h> 
 #include <linux/module.h> 
 #include <linux/kernel.h> 

 MODULE_LICENSE("GPL"); 

 static int ftrace_demo_init(void) 
 { 		
	 trace_printk("ftrace_demo_init called\n"); 
	 tracing_off(); 
	 return 0; 
 } 

 static void ftrace_demo_exit(void) 
 { 
	 trace_printk("ftrace_demo_exit called\n"); 
	 tracing_off(); 
 } 

 module_init(ftrace_demo_init); 
 module_exit(ftrace_demo_exit);

下面對其進行跟蹤,如清單 4 所示。


清單 4. 跟蹤
[root@linux tracing]# pwd 
 /sys/kernel/debug/tracing 
 [root@linux tracing]# echo 0 > tracing_enabled 
 [root@linux tracing]# echo 1 > /proc/sys/kernel/ftrace_enabled 
 [root@linux tracing]# echo 1 > tracing_on 
 [root@linux tracing]# echo function > current_tracer 
 [root@linux tracing]# echo 1 > tracing_enabled 

 # 加載模塊 ftrace_demo,模塊初始化函數 ftrace_demo_init 被調用

 [root@linux tracing]# cat tracing_on 
 0 
 [root@linux tracing]# cat trace | wc -l 
 120210 
 [root@linux tracing]# cat trace | grep -n ftrace_demo_init 
 120187:      insmod-2897  [000]  2610.504611: ftrace_demo_init <-do_one_initcall 
 120193:      insmod-2897  [000]  2610.504667: ftrace_demo_init: ftrace_demo_init called 

 [root@linux tracing]# echo 1 > tracing_on   # 繼續跟蹤信息的記錄

 # 卸載模塊 ftrace_demo,模塊函數 ftrace_demo_exit 被調用

 [root@linux tracing]# cat tracing_on 
 0 
 [root@linux tracing]# wc -l trace 
 120106 trace 
 [root@linux tracing]# grep -n ftrace_demo_exit trace 
 120106:           rmmod-2992  [001]  3016.884449: : ftrace_demo_exit called

在這個例子中,跟蹤開始以前須要確保 tracing_on 的值爲 1。跟蹤開始後,加載模塊 ftrace_demo,其初始化方法 ftrace_demo_init 被調用,該方法會調用 tracing_off() 函數來暫停跟蹤信息的記錄,這時文件 tracing_on 的值被代碼設置爲 0。查看文件 trace,能夠看到 ftrace_demo_init 相關的記錄位於跟蹤信息的末端,這是由於從調用 trace_off() 到其生效須要一段時間,這段時間中的內核活動會被記錄下來;相比從用戶態讀寫 tracing_on 文件,這段時間開銷要小了許多。卸載模塊時的狀況與此相似。從這裏能夠看到,在代碼中使用 tracing_off() 能夠控制將感興趣的信息保存在跟蹤緩衝區的末端位置,不會很快被新的信息所覆蓋,便於及時查看。

實際代碼中,能夠經過特定條件(好比檢測到某種異常情況,等等)來控制跟蹤信息的記錄,函數的使用方式相似以下的形式:

if (condition) 
	 tracing_on() or tracing_off()

跟蹤模塊運行情況時,使用 ftrace 命令操做序列在用戶態進行必要的設置,而在代碼中則能夠經過 traceing_on() 控制在進入特定代碼區域時開啓跟蹤信息,並在遇到某些條件時經過 tracing_off() 暫停;讀者能夠在查看完感興趣的信息後,將 1 寫入 tracing_on 文件以繼續記錄跟蹤信息。實踐中,能夠經過宏來控制是否將對這些函數的調用編譯進內核模塊,這樣能夠在調試時將其開啓,在最終發佈時將其關閉。

用戶態的應用程序能夠經過直接讀寫文件 tracing_on 來控制記錄跟蹤信息的暫停狀態,以便了解應用程序運行期間內核中發生的活動。

回頁首

小結

本系列文章對 ftrace 的配置和使用進行了介紹。本文是其中的第三部分,經過示例代碼介紹了 ftrace 所提供的部分工具函數的使用,包括 trace_printk、tracing_on/tracing_off 。至此,本系列文章的全部內容都已經介紹完畢。經過本系列文章,讀者能夠了解如何使用 ftrace 來對內核進行調試和分析。ftrace 使用起來很是靈活,而且支持多種跟蹤器,並且它的框架結構使得在添加新的跟蹤器的時候會比較方便。讀者能夠在之後的工做和學習中探索 ftrace 的各類用法。


參考資料

做者簡介

王生輝,軟件工程師。目前在 IBM 系統技術實驗室從事 Linux for Power 方面的測試工做。

李驊宸,實習生。目前在 IBM 系統技術實驗室從事 Linux for Power 方面的測試工做。

相關文章
相關標籤/搜索