Linux trace使用入门
2015-06-13 13:35
579 查看
概念
trace 顾名思义追踪信息,可通俗理解为一种高级打印机制,用于debug,实现追踪kernel中函数事件的框架,源码位于:\kernel\trace\trace.c,有兴趣可以研究撰写不易,转载需注明出处:/article/1531673.html本文来自 【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应用中介绍~
相关文章推荐
- VMware虚拟机克隆Linux系统后找不到eth0网卡的问题
- mysql5.6 linux下安装笔记
- mysql5.6 linux下安装笔记
- hadoop常用linux命令与操作
- Linux ld命令
- I.MX6 Linux Qt 启动流程跟踪
- linux下一些问题
- Linux系统软件
- CentOS6.4 NFS配置
- Linux LCD驱动(四)--驱动的实现
- Go语言linux安装设置
- 正则表达式与文件格式处理-Linux(笔记)
- Linux readelf命令
- linux ar命令
- Linux 系统管理程序
- Linux下GTK实现系统监视器
- Linux LCD驱动(三)--图形显示
- linux LCD驱动(二)--FrameBuffer
- linux LCD驱动(一)--硬件分析
- Linux 性能优化程序