❶ 使用 ftrace 來跟蹤系統問題 - ftrace 介紹
雖然之前一直聽說過 ftrace,但從來沒將它用在實戰中,在一次客戶排查問題中,遇到了比較奇怪的現象,一位精通內核的朋友建議使用 ftrace 來定位一下。雖然那一次並沒有使用 ftrace,但也讓我覺得,後面我們勢必要提供 ftrace 相關的工具幫助我們在線上定位問題,所以自己也決定重新學習使用下 ftrace,當然也決定寫一系列的相關出來,這里就先簡單介紹下 ftrace。
首先我們需要知道,什麼是 ftrace?根據 linux Doc 的介紹,ftrace 是一個 Linux 內部的 trace 工具,能夠幫助開發者和系統設計者知道內核當前正在幹啥,從而更好的去分析性能問題。
Ftrace 能幫我們分析內核特定的事件,譬如調度,中斷等,也能幫我們去追蹤動態的內核函數,以及這些函數的調用棧還有棧的使用這些。它也能幫我們去追蹤延遲,譬如中斷被屏蔽,搶占被禁止的時間,以及喚醒一個進程之後多久開始執行的時間。
可以看到,使用 ftrace 真的能做到對系統內核非常系統的剖析,甚至都能通過 ftrace 來學習 Linux 內核,不過在更進一步之前,我們需要學會的是 - 如何使用 ftrace。
要使用 ftrace,首先就是需要將系統的 debugfs 或者 tracefs 給掛載到某個地方,幸運的是,幾乎所有的 Linux 發行版,都開啟了 debugfs/tracefs 的支持,所以我們也沒必要去重新編譯內核了。
在比較老的內核版本,譬如 CentOS 7 的上面,debugfs 通常被掛載到 /sys/kernel/debug 上面(debug 目錄下面有一個 tracing 目錄),而比較新的內核,則是將 tracefs 掛載到 /sys/kernel/tracing ,無論是什麼,我都喜歡將 tracing 目錄直接 link 到 /tracing 。後面都會假設直接進入了 /tracing 目錄,後面,我會使用 Ubuntu 16.04 來舉例子,內核版本是 4.13 來舉例子。
我們使用 ls 來看看目錄下面到底有什麼:
可以看到,裡面有非常多的文件和目錄,具體的含義,大家可以去詳細的看官方文檔的解釋,後面只會重點介紹一些文件。
我們可以通過 available_tracers 這個文件知道當前 ftrace 支持哪些插件。
通常用的最多的就是 function 和 function_graph ,當然,如果我們不想 trace 了,可以使用 nop 。我們首先打開 function :
上面我們將 function 寫入到了 current_tracer 來開啟 function 的 trace,我通常會在 cat 下 current_tracer 這個文件,主要是防止自己寫錯了。
然後 ftrace 就開始工作了,會將相關的 trace 信息放到 trace 文件裡面,我們直接讀取這個文件就能獲取相關的信息。
我們可以設置只跟蹤特定的 function
當然,如果我們不想 trace schele 這個函數,也可以這樣做:
或者也可以這樣做:
Function filter 的設置也支持 *match , match* , *match* 這樣的正則表達式,譬如我們可以 echo '*lock*' < set_ftrace_notrace 來禁止跟蹤帶 lock 的函數, set_ftrace_notrace 文件裡面這時候就會顯示:
相比於 function , function_graph 能讓我們更加詳細的去知道內核函數的上下文,我們打開 function_graph :
我們也可以只跟蹤某一個函數的堆棧
上面提到了 function 的 trace,在 ftrace 裡面,另外用的多的就是 event 的 trace,我們可以在 events 目錄下面看支持那些事件:
上面列出來的都是分組的,我們可以繼續深入下去,譬如下面是查看 sched 相關的事件:
對於某一個具體的事件,我們也可以查看:
不知道大家注意到了沒有,上述目錄裡面,都有一個 enable 的文件,我們只需要往裡面寫入 1,就可以開始 trace 這個事件。譬如下面就開始 trace sched_wakeup 這個事件:
我們也可以 trace sched 裡面的所有事件:
當然也可以 trace 所有的事件:
從上面的例子可以看到,其實使用 ftrace 並不是那麼方便,我們需要手動的去控制多個文件,但幸運的是,我們有 trace-cmd ,作為 ftrace 的前端, trace-cmd 能夠非常方便的讓我們進行 ftrace 的操作,譬如我們可以使用 record 命令來 trace sched 事件:
然後使用 report 命令來查看 trace 的數據:
當然,在 report 的時候也可以加入自己的 filter 來過濾數據,譬如下面,我們就過濾出 sched_wakeup 事件並且是 success 為 1 的。
大家可以注意下 success == 1 ,這其實是一個對事件裡面 field 進行的表達式運算了,對於不同的事件,我們可以通過查看起 format 來知道它的實際 fields 是怎樣的,譬如:
上面只是簡單的列出了 ftrace 相關的使用,後續我會在寫一些我們或者業界是如何用 ftrace 來解決問題的。另外,我們正在用 ftrace 開發非常多的性能診斷工具,如果你對這一塊感興趣,歡迎聯系我 [email protected] 。
❷ 如何linux內核報告問題
Linux Kernel BUG:soft lockup CPU#1 stuck分析
1.線上內核bug日誌
kernel: Deltaway too big! 18428729675200069867 ts=18446743954022816244 write stamp =18014278822746377
kernel:------------[ cut here ]------------
kernel:WARNING: at kernel/trace/ring_buffer.c:1988 rb_reserve_next_event+0x2ce/0x370()(Not tainted)
kernel:Hardware name: ProLiant DL360 G7
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel: Pid:5483, comm: master Not tainted 2.6.32-220.el6.x86_64 #1
kernel: CallTrace:
kernel:[<ffffffff81069b77>] ? warn_slowpath_common+0x87/0xc0
kernel:[<ffffffff81069bca>] ? warn_slowpath_null+0x1a/0x20
kernel:[<ffffffff810ea8ae>] ? rb_reserve_next_event+0x2ce/0x370
kernel:[<ffffffff810eab02>] ? ring_buffer_lock_reserve+0xa2/0x160
kernel:[<ffffffff810ec97c>] ? trace_buffer_lock_reserve+0x2c/0x70
kernel:[<ffffffff810ecb16>] ? trace_current_buffer_lock_reserve+0x16/0x20
kernel:[<ffffffff8107ae1e>] ? ftrace_raw_event_hrtimer_cancel+0x4e/0xb0
kernel:[<ffffffff81095e7a>] ? hrtimer_try_to_cancel+0xba/0xd0
kernel:[<ffffffff8106f634>] ? do_setitimer+0xd4/0x220
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
kernel: ---[end trace 4d0a1ef2e62cb1a2 ]---
abrt-mp-oops: Reported 1 kernel oopses to Abrt
kernel: BUG: softlockup - CPU#11 stuck for 4278190091s! [qmgr:5492]
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel: CPU 11
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel:
kernel: Pid:5492, comm: qmgr Tainted: G W ---------------- 2.6.32-220.el6.x86_64 #1 HPProLiant DL360 G7
kernel: RIP:0010:[<ffffffff8106f730>] [<ffffffff8106f730>]do_setitimer+0x1d0/0x220
kernel: RSP:0018:ffff88080a661ef8 EFLAGS: 00000286
kernel: RAX:ffff88080b175a08 RBX: ffff88080a661f18 RCX: 0000000000000000
kernel: RDX:0000000000000000 RSI: 0000000000000082 RDI: ffff88080c8c4c40
kernel: RBP:ffffffff8100bc0e R08: 0000000000000000 R09: 0099d7270e01c3f1
kernel: R10:0000000000000000 R11: 0000000000000246 R12: ffffffff810ef9a3
kernel: R13:ffff88080a661e88 R14: 0000000000000000 R15: ffff88080a65a544
kernel: FS:00007f10b245f7c0(0000) GS:ffff88083c4a0000(0000) knlGS:0000000000000000
kernel: CS:0010 DS: 0000 ES: 0000 CR0: 000000008005003b
kernel: CR2:00007ff955977380 CR3: 000000100a80b000 CR4: 00000000000006e0
kernel: DR0:0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
kernel: DR3:0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
kernel:Process qmgr (pid: 5492, threadinfo ffff88080a660000, task ffff880809577500)
kernel: Stack:
kernel:00007f10b323def0 00007f10b248ead0 00007f10b26d0f78 00007f10b248ede0
kernel:<0> ffff88080a661f68 ffffffff8106f88a 0000000000000000 0000000000000000
kernel:<0> 000000000000014c 00000000000f423d 0000000000000000 0000000000000000
kernel: CallTrace:
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
kernel: Code:89 ef e8 74 66 02 00 83 3d 15 69 b5 00 00 75 37 49 8b 84 24 70 07 00 00 48 0508 08 00 00 66 ff 00 66 66 90 fb 66 0f 1f 44 00 00 <31> c0 e9 64 fe ff ff49 8b 84 24 68 07 00 00 48 c7 80 d0 00 00
kernel: CallTrace:
kernel:[<ffffffff8106f769>] ? do_setitimer+0x209/0x220
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
abrt-mp-oops: Reported 1 kernel oopses to Abrt
2.內核軟死鎖(soft lockup)bug原因分析
Soft lockup名稱解釋:所謂,soft lockup就是說,這個bug沒有讓系統徹底死機,但是若干個進程(或者kernel thread)被鎖死在了某個狀態(一般在內核區域),很多情況下這個是由於內核鎖的使用的問題。
Linux內核對於每一個cpu都有一個監控進程,在技術界這個叫做watchdog(看門狗)。通過ps –ef | grep watchdog能夠看見,進程名稱大概是watchdog/X(數字:cpu邏輯編號1/2/3/4之類的)。這個進程或者線程每一秒鍾運行一次,否則會睡眠和待機。這個進程運行會收集每一個cpu運行時使用數據的時間並且存放到屬於每個cpu自己的內核數據結構。在內核中有很多特定的中斷函數。這些中斷函數會調用soft lockup計數,他會使用當前的時間戳與特定(對應的)cpu的內核數據結構中保存的時間對比,如果發現當前的時間戳比對應cpu保存的時間大於設定的閥值,他就假設監測進程或看門狗線程在一個相當可觀的時間還沒有執。Cpu軟鎖為什麼會產生,是怎麼產生的?如果linux內核是經過精心設計安排的CPU調度訪問,那麼怎麼會產生cpu軟死鎖?那麼只能說由於用戶開發的或者第三方軟體引入,看我們伺服器內核panic的原因就是qmgr進程引起。因為每一個無限的循環都會一直有一個cpu的執行流程(qmgr進程示一個後台郵件的消息隊列服務進程),並且擁有一定的優先順序。Cpu調度器調度一個驅動程序來運行,如果這個驅動程序有問題並且沒有被檢測到,那麼這個驅動程序將會暫用cpu的很長時間。根據前面的描述,看門狗進程會抓住(catch)這一點並且拋出一個軟死鎖(soft lockup)錯誤。軟死鎖會掛起cpu使你的系統不可用。
如果是用戶空間的進程或線程引起的問題backtrace是不會有內容的,如果內核線程那麼在soft lockup消息中會顯示出backtrace信息。
3.根據linux內核源碼分析錯誤
根據我們第一部分內核拋出的錯誤信息和call trace(linux內核的跟蹤子系統)來分析產生的具體原因。
首先根據我們的centos版本安裝相應的linux內核源碼,具體步驟如下:
(1)下載源碼的rpm包kernel-2.6.32-220.17.1.el6.src.rpm
(2)安裝相應的依賴庫,命令:yuminstall rpm-build redhat-rpm-config asciidoc newt-devel
(3)安裝源碼包:rpm -ikernel-2.6.32-220.17.1.el6.src.rpm
(4)進入建立源碼的目錄:cd~/rpmbuild/SPECS
(5)建立生成源碼目錄:rpmbuild-bp --target=`uname -m` kernel.spec
下面開始真正的根據內核bug日誌分析源碼:
(1)第一階段內核錯誤日誌分析(時間在Dec 4 14:03:34這個階段的日誌輸出代碼分析,其實這部分代碼不會導致cpu軟死鎖,主要是第二階段錯誤日誌顯示導致cpu軟死鎖)
我們首先通過日誌定位到相關源代碼:看下面日誌:Dec 4 14:03:34 BP-YZH-1-xxxx kernel: WARNING: atkernel/trace/ring_buffer.c:1988 rb_reserve_next_event+0x2ce/0x370() (Not tainted)
根據日誌內容我們可以很容易的定位到kernel/trace/ring_buffer.c這個文件的1988行代碼如下:WARN_ON(1)。
先簡單解釋一下WARN_ON的作用:WARN_ON只是列印出當前棧信息,不會panic。所以會看到後面有一大堆的棧信息。這個宏定義如下:
#ifndef WARN_ON
#defineWARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
__WARN(); \
unlikely(__ret_warn_on); \
})
#endif
這個宏很簡單保證傳遞進來的條件值為0或者1(兩次邏輯非操作的結果),然後使用分支預測技術(保證執行概率大的分支緊鄰上面的指令)判斷是否需要調用__WARN()宏定義。如果滿足條件執行了__WARN()宏定義也接著執行一條空指令;。上面調用WARN_ON宏是傳遞的1,所以會執行__WARN()。下面繼續看一下__WARN()宏定義如下:
#define __WARN() warn_slowpath_null(__FILE__,__LINE__)
從接下來的call trace信息中我們也確實發現調用了warn_slowpath_null這個函數。通過在linux內核源代碼中搜索這個函數的實現,發現在panic.c(內核恐慌時的相關功能實現)中實現如下:
voidwarn_slowpath_null(const char *file, int line)
{
warn_slowpath_common(file, line,__builtin_return_address(0),
TAINT_WARN, NULL);
}
EXPORT_SYMBOL(warn_slowpath_null);//都出這個符號,讓其他模塊可以使用這個函數
同樣的我們看到了warn_slowpath_common這個函數,而在call trace當中這個函數在warn_slowpath_null函數之前列印出來,再次印證了這個流程是正確的。同樣在panic.c這個文件中我發現了warn_slowpath_common這個函數的實現如下:
static voidwarn_slowpath_common(const char *file, int line, void *caller,
unsigned taint, struct slowpath_args *args)
{
const char *board;
printk(KERN_WARNING "------------[ cut here]------------\n");
printk(KERN_WARNING "WARNING: at %s:%d %pS()(%s)\n",
file, line, caller, print_tainted());
board = dmi_get_system_info(DMI_PRODUCT_NAME);//得到dmi系統信息
if (board)
printk(KERN_WARNING "Hardware name:%s\n", board);//通過我們的日誌信息可以發現我們硬體名稱是ProLiant DL360 G7
if (args)
vprintk(args->fmt, args->args);
print_moles();//列印系統模塊信息
mp_stack();//mp信息輸出(call trace開始)
print_oops_end_marker();//列印oops結束
add_taint(taint);
}
分析這個函數的實現不難發現我們的很多日誌信息從這里開始輸出,包括列印一些系統信息,就不繼續深入分析了(請看代碼注釋,裡面調用相關函數列印對應信息,通過我分析這些函數的實現和我們的日誌信息完全能夠對應,其中mp_stack是與cpu體系結構相關的,我們的伺服器應該是屬於x86體系)。這里在繼續分析一下mp_stack函數的實現,因為這個是與cpu體系結構相關的,而且這個函數直接反應出導致內核panic的相關進程。這個函數實現如下:
/*
* The architecture-independent mp_stackgenerator
*/
void mp_stack(void)
{
unsigned long stack;
printk("Pid: %d, comm: %.20s %s %s %.*s\n",
current->pid, current->comm,print_tainted(),
init_utsname()->release,
(int
❸ Android-trace分析工具
1.TraceView
官方說明文檔:
https://developer.android.google.cn/studio/profile/cpu-profiler
android CPU profiler
CPU profiler可以實時檢查應用的CPU使用率和線程activity,並記錄函數跟蹤,以便於您可以優化和調試您的應用程序.
Flame Chart如果出現問題 顏色也會加深
2.systrace
簡介:
systrace是Android4.1版本之後推出的,對系統Performance分析的工具。systrace的功能包括跟蹤系統I/O操作,內核工作隊列,CPU負載以及Android各個子系統的運行狀況等。
主要由三部分構成:
1.內核部分
systrace採用了linux Kernel的ftrace功能,所以如果要使用systrace的話,必須開啟Kernel和ftrace相關的模塊.
2.數據採集部分
Android中定義了一個trace類,應用程序可以使用該類把統計信息輸出給trace,同時,android有一個atrace程序,它可以從ftrace中讀取統計信息然後交給數據分析工具來處理.
3.數據分析工具
Android提供一個systrace.py用來配置數據採集的方法(如採集數據的標簽,輸出文件名等)和收集ftrace統計數據並生成一個結果網頁文件供用戶查看。
簡單的說,當機器以60幀/秒顯示,用戶會感知機器流暢。如果出現顯示時丟幀的情況,就需要知道系統在做什麼?Systrace是用來收集系統和應用的數據信息和一些中間生成數據的細節,在Android4.1和4.2系統之後出現。Systrace在分析一些顯示問題上特別有用,如應用畫圖慢,顯示動作或者動畫時變形。
抓取systrace
進入本地Android/Sdk/platform-tools/systrace目錄下,執行python systrace.py view --time = 10
python腳本的option
❹ Linux性能工具(一)ftrace使用
Ftrace設計作為一個內部的tracer提供給系統的開發者和設計者,幫助他們弄清kernel正在發生的行為,它能夠調式分析延遲和性能問題。對於前一章節,我們學習了Ftrace發展到現在已經不僅僅是作為一個function tracer了,它實際上成為了一個通用的trace工具的框架。
一方面已經從function tracer擴展到irqsoff tracer、preemptoff tracer;另一方面靜態的trace event也成為trace的一個重要組成部分;通過前面兩節的學習,我們知道了什麼是ftrace,能夠解決什麼問題,從這章開始我們主要是學習,怎麼去使用ftreace解決問題。
ftrace 通過 debugfs 向用戶態提供訪問介面。配置內核時激活 debugfs 後會創建目錄 /sys/kernel/debug ,debugfs 文件系統就是掛載到該目錄。要掛載該目錄,需要將如下內容添加到 /etc/fstab 文件:
或者可以在運行時掛載:
激活內核對 ftrace 的支持後會在 debugfs 下創建一個 tracing 目錄 /sys/kernel/debug/tracing 。該目錄下包含了 ftrace的控制和輸出文件
其中重點關注以下文件:
查看當前的跟蹤器current_tracer ,可以echo選擇:
trace使能
tracing_on :是否往循環buffer寫跟蹤記錄,可以echo設置
trace過濾器選擇(可選)
trace數據讀取
更多linux內核視頻教程文檔資料免費領取後台私信【 內核 】自行獲取。
所以對於ftrace的三步法為:
1.2 function trace實例
function,函數調用追蹤器, 跟蹤函數調用,默認跟蹤所有函數,如果設置set_ftrace_filter, 則跟蹤過濾的函數,可以看出哪個函數何時調用。
Disable tracer:
設置 tracer 類型為 function:
set_ftrace_filter 表示要跟蹤的函數,這里我們只跟蹤 dev_attr_show 函數:
Enable tracer:
提取trace結果:
從上圖可以看到 function trace 一個函數的方法基本就是三板斧:
function 跟蹤器可以跟蹤內核函數的調用情況,可用於調試或者分析 bug ,還可用於了解和觀察 Linux 內核的執行過程。同時ftrace允許你對一個特定的進程進行跟蹤,在/sys/kernel/debug/tracing目錄下,文件set_ftrace_pid的值要更新為你想跟蹤的進程的PID。
1.3 function_graph Trace 實例
function_graph 跟蹤器則可以提供類似 C 代碼的函數調用關系信息。通過寫文件 set_graph_function 可以顯示指定要生成調用關系的函數,預設會對所有可跟蹤的內核函數生成函數調用關系圖。
函數圖跟蹤器對函數的進入與退出進行跟蹤,這對於跟蹤它的執行時間很有用。函數執行時間超過10微秒的標記一個「+」號,超過1000微秒的標記為一個「!」號。通過echo function_graph > current_tracer可以啟用函數圖跟蹤器。
與 function tracer 類似,設置 function_graph 的方式如下:
設置 tracer 類型為 function_graph:
set_graph_function 表示要跟蹤的函數:
捕捉到的 trace 內容:
我們跟蹤的是 __do_fault 函數,但是 function_graph tracer 會跟蹤函數內的調用關系和函數執行時間,可以協助我們確定代碼執行流程。比如一個函數內部執行了很多函數指針,不能確定到底執行的是什麼函數,可以用 function_graph tracer 跟蹤一下。
需要注意:
對於不調用其它函數的函數,其對應行以「;」結尾,而且對應的 DURATION 欄位給出其運行時長;
對於調用其它函數的函數,則在其「}」對應行給出了運行時長,該時間是一個累加值,包括了其內部調用的函數的執行時長。DURATION 欄位給出的時長並不是精確的,它還包含了執行 ftrace 自身的代碼所耗費的時間,所以示例中將內部函數時長累加得到的結果會與對應的外圍調用函數的執行時長並不一致;不過通過該欄位還是可以大致了解函數在時間上的運行開銷的。
1.4 wakeup
wakeup tracer追蹤普通進程從被喚醒到真正得到執行之間的延遲。
non-RT進程通常看平均延遲。RT進程的最大延遲非常有意義,反應了調度器的性能
trace event 就是利用 ftrace 框架,實現低性能損耗,對執行流無影響的一種信息輸出機制。相比 printk,trace event:
2.2 使用實例
上面提到了 function 的 trace,在 ftrace 裡面,另外用的多的就是 event 的 trace,我們可以在 events 目錄下面看支持那些事件:
上面列出來的都是分組的,我們可以繼續深入下去,譬如下面是查看 sched 相關的事件
對於某一個具體的事件,我們也可以查看:
上述目錄裡面,都有一個 enable 的文件,我們只需要往裡面寫入 1,就可以開始 trace 這個事件。譬如下面就開始 trace sched_wakeup 這個事件
我們也可以 trace sched 裡面的所有事件
查看函數調用棧
查看函數調用棧是內核調試最最基本得需求,常用方法:
trace 函數的時候,設置 echo 1 > options/func_stack_trace 即可在 trace 結果中獲取追蹤函數的調用棧。
以 dev_attr_show 函數為例,看看 ftrace 如何幫我們獲取調用棧:
如何跟蹤一個命令,但是這個命令執行時間很短
我們可以設置ftrace過濾器控制相關文件:
如果這時候問:如何跟蹤某個進程內核態的某個函數?
答案是肯定的,將被跟蹤進程的 pid 設置到 set_event_pid/set_ftrace_pid 文件即可。
但是如果問題變成了,我要調試 kill 的內核執行流程,如何辦呢?
因為 kill 運行時間很短,我們不能知道它的 pid,所以就沒法過濾了。
調試這種問題的小技巧,即 腳本化,這個技巧在很多地方用到:
如何跟蹤過濾多個進程?多個函數?
用法為: echo xxx >> set_ftrace_filter ,例如,先設置 dev_attr_* :
再將 ip_rcv 追加到跟蹤函數中:
基於模塊過濾
格式為: : : ,例如,過濾 ext3 mole 的 write* 函數:
從過濾列表中刪除某個函數,使用「感嘆號」
感嘆號用來移除某個函數,把上面追加的 ip_rcv 去掉:
我們可以手工操作/sys/kernel/debug/tracing路徑下的大量的配置文件介面,來使用ftrace的強大功能。但是這些介面對普通用戶來說太多太復雜了,我們可以使用對ftrace功能進行二次封裝的一些命令來操作。
trace-cmd就是ftrace封裝命令其中的一種。該軟體包由兩部分組成
下載編譯ARM64 trace-cmd方法:
先通過 record 子命令將結果記錄到 trace.dat,再通過 report 命令進行結果提取。命令解釋:
在很有情況下不能使用函數追蹤,需要依賴 事件追蹤 的支持,例如:
4.2 kernelshark圖形化分析數據
trace-cmd report主要是使用統計的方式來找出熱點。如果要看vfs_read()一個具體的調用過程,除了使用上一節的trace-cmd report命令,還可以使用kernelshark圖形化的形式來查看,可以在板子上使用trace-cmd record 記錄事件,把得到的trace.data放到linux 桌面系統,用kernelshark打開,看到圖形化的信息
❺ red hat 內核2.6.32的kernel/fork.c在哪裡
裝了源碼的話,find -name fork.c 找下就知道了
❻ systrace實現原理
systrace是通過atrace和ftrace一起實現。
抓取systrace的adb命令如下:
adb shell atrace -t 8 -z gfx view wm am sched freq input > atrace
python命令:
python systrace.py -b 10240 -t 10 wm am input ss power view freq workq sched idle sync gfx view hal dalvik disk -a com.tencent.mm -o PD1982_weixin.html
systrace抓取實質是通過atrace實現,下面以ATRACE_CALL()為例說明systrace實現
system/core/libutils/include/utils/Trace.h
system/core/libcutils/include/cutils/trace.h
system/core/libcutils/trace-dev.cpp
system/core/libcutils/trace-dev.inc
到這可以看出:
ATRACE_CALL其實就是往atrace_marker_fd寫入函數名和進程pid等信息,其中atrace_marker_fd對應「/sys/kernel/debug/tracing/trace_marker」文件
systrace在內核層實質是通過ftrace來實現,systrace的內容是寫入內核分配的ringbuffer裡面的,開關的實質是disable/enable ringbuffer,ftrace的總開關/sys/kernel/debug/tracing/tracing_on
開關ftrace命令如下:
adb shell echo 1 > /sys/kernel/debug/tracing/tracing_on
adb shell echo 0 > /sys/kernel/debug/tracing/tracing_on
通過tracing_mark_write函數把內容寫入ringbuffer
msm-4.19/kernel/trace/trace.c
大致原理參考下圖:
ftrace就是function trace的縮寫,每個函數的追蹤都有一個對應的tracepoint結構來表示,這個結構存放在特殊的section內存中。
msm-4.19/include/linux/tracepoint-defs.h
3.1 tracepoint的probe函數注冊
以高通gpu驅動ftrace為例,通過以下命令可以觸發tracepoint的probe函數注冊
adb shell echo 1 > /sys/kernel/debug/tracing/events/kgsl/enable
msm-4.19/kernel/tracepoint.c
tracepoint的probe函數實質是在下面這個宏裡面定義,通過這個函數ftrace往對應的ringbuffer裡面寫入函數追蹤數據
msm-4.19/include/trace/trace_events.h
3.2 probe函數的調用
以高通gpu驅動入列一條繪制命令_queue_drawobj函數為例
msm-4.19/drivers/gpu/msm/adreno_dispatch.c
通過trace_adreno_cmdbatch_queued來追蹤_queue_drawobj函數,調用tracepoint的probe函數
接下來看下trace_adreno_cmdbatch_queued的實現
msm-4.19/drivers/gpu/msm/adreno_trace.h
trace_adreno_cmdbatch_queued真正定義在下面這個宏裡面
msm-4.19/include/linux/tracepoint.h
最終調用到tracepoint注冊的probe函數
msm-4.19/include/linux/tracepoint.h
總結下:Native層調用內核的tracing_mark_write來往ftrace的ringbuffer裡面寫入數據,而內核函數調用其對應probe函數往ftrace ringbuffer寫入數據。