zoukankan      html  css  js  c++  java
  • Linux trace使用入门

    概念

    trace 顾名思义追踪信息,可通俗理解为一种高级打印机制,用于debug,实现追踪kernel中函数事件的框架。源代码位于:kernel race race.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:kernelDocumentation race 文件夹下有非常多文档可看


    加入trace event

    上面说了是为了追踪执行信息,以我为readahead加入的trace event为例,抓取readahead所需的event log用于分析.
    kernel中event定义的源代码路径:kernelinclude raceevents
    路径下加入一个我为了这个功能新增的头文件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应用中介绍~

  • 相关阅读:
    学习使用apt(三)
    2005 男人感悟100(转自MOP)
    学习使用apt
    学习使用apt(四)
    编译glib1.2.20r5出错./libtool: line 297
    poj1004的java实现
    猜算式
    基于爬山算法求解TSP问题(JAVA)
    mysql数据库的简单语句的介绍(1)
    NYOJ42 一笔画问题
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/7238419.html
Copyright © 2011-2022 走看看