Linux trace使用入門


概念

trace 顧名思義追蹤信息,可通俗理解為一種高級打印機制,用於debug,實現追蹤kernel中函數事件的框架。源代碼位於:\kernel\trace\trace.c,有興趣能夠研究

撰寫不易,轉載需注明出處:http://blog.csdn.net/jscese/article/details/46415531本文來自 【jscese】的博客。

終端使用

須要文件系統掛載完畢之后,kernel的debugfs 掛載到 /sys/kernel/debug ,也可用命令掛載,一般都是在.rc中:

mount debugfs none /sys/kernel/debug

列出文件夾下文件:

root@:/sys/kernel/debug/tracing # ll
-r--r--r-- root     root            0 1970-01-01 08:00 README
-r--r--r-- root     root            0 1970-01-01 08:00 available_events
-r--r--r-- root     root            0 1970-01-01 08:00 available_tracers
-rw-rw-r-- root     shell           0 1970-01-01 08:00 buffer_size_kb
-r--r--r-- root     root            0 1970-01-01 08:00 buffer_total_size_kb
-rw-r--r-- root     root            0 1970-01-01 08:00 current_tracer
drwxr-xr-x root     root              1970-01-01 08:00 events
-rw-r--r-- root     root            0 1970-01-01 08:00 free_buffer
drwxr-xr-x root     root              1970-01-01 08:00 instances
drwxr-xr-x root     root              1970-01-01 08:00 options
drwxr-xr-x root     root              1970-01-01 08:00 per_cpu
-r--r--r-- root     root            0 1970-01-01 08:00 printk_formats
-r--r--r-- root     root            0 1970-01-01 08:00 saved_cmdlines
-r--r--r-- root     root            0 1970-01-01 08:00 saved_tgids
-rw-r--r-- root     root            0 1970-01-01 08:00 set_event
-rw-rw---- root     shell           0 1970-01-01 08:00 trace
-rw-rw-r-- root     shell           0 1970-01-01 08:00 trace_clock
--w--w--w- root     root            0 1970-01-01 08:00 trace_marker
-rw-r--r-- root     root            0 1970-01-01 08:00 trace_options
-r--r--r-- root     root            0 1970-01-01 08:00 trace_pipe
-rw-r--r-- root     root            0 1970-01-01 08:00 tracing_cpumask
-rw-rw-r-- root     shell           0 1970-01-01 08:00 tracing_on
-rw-r--r-- root     root            0 1970-01-01 08:00 tracing_thresh

版本號不同,可能會有出入,我這邊(3.10.37)。列出幾個經常使用的:
README能夠去看看,介紹了一些屬性。
available_* : 代表支持有效的 事件 和追蹤器 ,都能夠使用cat 查看。


buffer_size_kb:這個屬性比較重要,也是使用中須要注意的,這是設置啟動的CPU的緩存大小。取決於追蹤log的大小,超出會反復利用覆蓋,可是一次性分配又須要考慮內存。
buffer_total_size_kb:這個就是總和buffer size 了,啟用了多少個cpu去trace就乘以buffer_size_kb.
current_tracer: 當前的追蹤器。有哪幾種能夠查看available_tracers ,用echo * > 重定向 設置改變,詳細tracer的不同需另行參考 ,默覺得nop
events:文件夾下就是加入在kernel源代碼中已經存在的各個event集合。
free_buffer:顧名思義,可是這個使用方法比較特殊,有僅僅要open之后。等處理完buffer之后 close這個文件就可以釋放buffer,有興趣能夠去trace.c里面看看這個節點的file_operation,不手動去close這個節點的話,上面設置的buffer是不會free的。
trace:用於追蹤操作的文件節點,就是讀取該節點獲取trace log
tracing_cpumask:用到的cpu標記。以數值bit位表示多少個cpu,這個尤為注意。比方四核 cat顯示就是 “f” 也就是“1111”。
tracing_on:開關


我這里僅僅是簡單的列出我用到過的幾項。須要尤為注意的就是buffer free cpubit 假設沒弄好就大量內存泄露了~前車之鑒

對於節點定義以及使用方法,不妨耐心閱讀kernel自帶的doc:\kernel\Documentation\trace 文件夾下有非常多文檔可看


加入trace event

上面說了是為了追蹤執行信息,以我為readahead加入的trace event為例,抓取readahead所需的event log用於分析.
kernel中event定義的源代碼路徑:\kernel\include\trace\events
路徑下加入一個我為了這個功能新增的頭文件readahead.h 內容例如以下:

#undef TRACE_SYSTEM
#define TRACE_SYSTEM readahead

#if !defined(_TRACE_READAHEAD_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_READAHEAD_H

#include <linux/tracepoint.h>

TRACE_EVENT(do_open_exec,

    TP_PROTO(struct inode *inode),

    TP_ARGS(inode),

    TP_STRUCT__entry(
            __field(    dev_t,  dev         )
            __field(    ino_t,  ino         )
    ),

    TP_fast_assign(
            __entry->dev    = inode->i_sb->s_dev;
            __entry->ino    = inode->i_ino;
    ),




    TP_printk("%d %d %lu",
          MAJOR(__entry->dev), MINOR(__entry->dev),
          (unsigned long) __entry->ino)
);


TRACE_EVENT(do_fs_read,

    TP_PROTO(struct inode *inode,unsigned long pos,size_t count),

    TP_ARGS(inode,pos,count),

    TP_STRUCT__entry(
            __field(    dev_t,  dev         )
            __field(    ino_t,  ino         )
            __field(    unsigned long,  pos         )
            __field(    size_t, count           )
    ),

    TP_fast_assign(
            __entry->dev    = inode->i_sb->s_dev;
            __entry->ino    = inode->i_ino;
            __entry->pos    =pos;
            __entry->count  =count;
    ),




    TP_printk("%d %d %lu %lu %d",
          MAJOR(__entry->dev), MINOR(__entry->dev),
         __entry->ino,__entry->pos,__entry->count)
);


TRACE_EVENT(do_file_map,

    TP_PROTO(struct inode *inode,unsigned long pageshift, unsigned long pagesize),

    TP_ARGS(inode,pageshift,pagesize),

    TP_STRUCT__entry(
            __field(    dev_t,  dev         )
            __field(    ino_t,  ino         )
            __field(    unsigned long , pageshift           )
            __field(    unsigned long,  pagesize            )
    ),

    TP_fast_assign(
            __entry->dev    = inode->i_sb->s_dev;
            __entry->ino    = inode->i_ino;
            __entry->pageshift  =pageshift;
            __entry->pagesize   =pagesize;
    ),




    TP_printk("%d %d %lu %lu %d",
          MAJOR(__entry->dev), MINOR(__entry->dev),
          (unsigned long) __entry->ino,__entry->pageshift,__entry->pagesize)
);


#endif
#include <trace/define_trace.h>

編譯進系統,可到終端去查看event文件夾下是否生成了定義的這3個文件文件夾:

root@:/sys/kernel/debug/tracing/events # ll readahead/ 
drwxr-xr-x root     root              1970-01-01 08:00 do_file_map
drwxr-xr-x root     root              1970-01-01 08:00 do_fs_read
drwxr-xr-x root     root              1970-01-01 08:00 do_open_exec
-rw-r--r-- root     root            0 1970-01-01 08:00 enable
-rw-r--r-- root     root            0 1970-01-01 08:00 filter

每一個相應的event文件夾下結構例如以下:

root@:/sys/kernel/debug/tracing/events/readahead # ll do_file_map/ 
-rw-r--r-- root     root            0 1970-01-01 08:00 enable
-rw-r--r-- root     root            0 1970-01-01 08:00 filter
-r--r--r-- root     root            0 1970-01-01 08:00 format
-r--r--r-- root     root            0 1970-01-01 08:00 id

這里文件節點所代表的意義,以及假設初始配置 在上面說到的kernel相應doc的trace/events.txt中有詳細的解析,不多闡述。


能夠看到上面3個event,每一個傳入的參數是不一樣的,定義之后就是使用了,加入3處trace event位置例如以下:
直接貼kernel 文件夾下的git patch:

diff --git a/fs/exec.c b/fs/exec.c
index a0d09ca..0954060 100755
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -66,6 +66,8 @@

 #include <trace/events/sched.h>

+#include <trace/events/readahead.h>

 int suid_dumpable = 0;

 static LIST_HEAD(formats);
@@ -748,6 +750,17 @@ EXPORT_SYMBOL(setup_arg_pages);

 #endif /* CONFIG_MMU */


 struct file *open_exec(const char *name)
 {
    struct file *file;
@@ -793,6 +806,21 @@ struct file *open_exec(const char *name)
    }
 #endif

+/*===================*/
+ /*(add trace for readahead)*/
+ struct inode *inode = file->f_path.dentry->d_inode;
+ if (inode && inode->i_ino && MAJOR(inode->i_sb->s_dev)) {
+
+ trace_do_open_exec(inode);
+ }
+
+
+/*end*/
+
+
 out:
    return file;

diff --git a/fs/read_write.c b/fs/read_write.c
index c6a3a68..156ebff 100755
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -22,6 +22,8 @@
 #include <asm/uaccess.h>
 #include <asm/unistd.h>

+#include <trace/events/readahead.h>
+
 typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
 typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
        unsigned long, loff_t);
@@ -376,6 +378,26 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
    }
 #endif

+
+ /*(add trace for readahead)*/
+
+ if (S_ISREG(file->f_dentry->d_inode->i_mode)
+ && MAJOR(file->f_dentry->d_inode->i_sb->s_dev)) {
+
+ unsigned long ulpos=(unsigned long) *pos;
+
+ trace_do_fs_read(file->f_dentry->d_inode,ulpos,count);
+
+ }

+
+ /*end*/
+

+
    ret = rw_verify_area(READ, file, pos, count);
    if (ret >= 0) {
        count = ret;

diff --git a/mm/filemap.c b/mm/filemap.c
index 84a6422..e04ed31 100755
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -38,6 +38,8 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/filemap.h>

+
+#include <trace/events/readahead.h>
 /*
  * FIXME: remove all knowledge of the buffer layer from the core VM
  */
@@ -1623,6 +1625,13 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        offset << PAGE_SHIFT, PAGE_SIZE);
 #endif

+ /*(add trace for readahead)*/
+
+ trace_do_file_map(inode,offset << PAGE_SHIFT,PAGE_SIZE);
+
+ /*end*/
+
+
    size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
    if (offset >= size)
        return VM_FAULT_SIGBUS;

當須要trace log的時候,就須要使能event,也就是打開上面每一個event相應文件夾下的節點enable,(trace版本號不同開關會不同,要視詳細情況而定了)trace機制就會運作抓取事件到buffer中。看下結果:

root@:/sys/kernel/debug/tracing # cat trace 
# tracer: nop
#
# entries-in-buffer/entries-written: 0/0 #P:1
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
root@:/sys/kernel/debug/tracing # echo 1 > events/readahead/do_file_map/enable
root@:/sys/kernel/debug/tracing # cat trace 
# tracer: nop
#
# entries-in-buffer/entries-written: 1100/1100 #P:1
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
     InputReader-517   [000] ...1  6270.548499: do_file_map: 93 32 58 41598976 4096
     InputReader-517   [000] ...1  6270.548540: do_file_map: 93 32 58 41594880 4096
     InputReader-517   [000] ...1  6270.548641: do_file_map: 93 32 58 48373760 4096
     InputReader-517   [000] ...1  6270.577857: do_file_map: 93 16 1290 188416 4096
     InputReader-517   [000] ...1  6270.578380: do_file_map: 93 16 1290 184320 4096
...

這打印出來的數據格式前面的都有凝視,后面的一串數據,就是之前readahead.h中定義的TP_printk

僅僅做簡單的介紹,實際代碼應用在興許readahead應用中介紹~


免責聲明!

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



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