Linuxtrace使⽤⼊门
概念
trace 顾名思义追踪信息,可通俗理解为⼀种⾼级打印机制,⽤于debug,实现追踪kernel中函数事件的框架,源码位于:
\kernel\trace\trace.c,有兴趣可以研究
终端使⽤
需要⽂件系统挂载完成之后,kernel的debugfs 挂载到 /sys/kernel/debug ,也可⽤命令挂载,⼀般都是在.rc中:mount debugfs none /sys/kernel/debug
列出⽬录下⽂件:
root@:/sys/kernel/debug/tracing#ll
-r--r--r--root root01970-01-0108:00README
-r--r--r--root root01970-01-0108:00available_events
-r--r--r--root root01970-01-0108:00available_tracers
-rw-rw-r--root shell01970-01-0108:00buffer_size_kb
-r--r--r--root root01970-01-0108:00buffer_total_size_kb
-rw-r--r--root root01970-01-0108:00current_tracer
drwxr-xr-x root root1970-01-0108:00events
-rw-r--r--root root01970-01-0108:00free_buffer
drwxr-xr-x root root1970-01-0108:00instances
drwxr-xr-x root root1970-01-0108:00options
drwxr-xr-x root root1970-01-0108:00per_cpu
-r--r--r--root root01970-01-0108:00printk_formats
-r--r--r--root root01970-01-0108:00saved_cmdlines
-
r--r--r--root root01970-01-0108:00saved_tgids
-rw-r--r--root root01970-01-0108:00set_event
-rw-rw----root shell01970-01-0108:00trace
-rw-rw-r--root shell01970-01-0108:00trace_clock
--w--w--w-root root01970-01-0108:00trace_marker
-rw-r--r--root root01970-01-0108:00trace_options
-r--r--r--root root01970-01-0108:00trace_pipe
-rw-r--r--root root01970-01-0108:00tracing_cpumask
-rw-rw-r--root shell01970-01-0108:00tracing_on
-rw-r--r--root root01970-01-0108:00tracing_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: 当前的追踪器,有哪⼏种可以查ailable_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),
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            01970-01-01 08:00 enable
-rw-r--r-- root    root            01970-01-01 08:00 filter
每个对应的event⽬录下结构如下:
root@:/sys/kernel/debug/tracing/events/readahead# ll do_file_map/
-rw-r--r-- root    root            01970-01-01 08:00 enable
-rw-r--r-- root    root            01970-01-01 08:00 filter
-r--r--r-- root    root            01970-01-01 08:00 format
-r--r--r-- root    root            01970-01-01 08:00 id
这⾥⽂件节点所代表的意义,以及如果初始配置 在上⾯说到的kernel对应doc的中有详细的解析,不多阐述。
可以看到上⾯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
--- 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*/
+
+
linux重定向ret = rw_verify_area(READ, file, pos, count);
if (ret >= 0) {
count = ret;
diff --git a/mm/filemap.c b/mm/filemap.c
04ed31 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中,看下结果:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。