[置顶] kernel学习之ftrace环境搭设及使用(包括buildroot的使用)

Updated(2012/04/23):

刚看了elc2012的一篇关于使用ftrace调试性能问题的文章,也很不错
https://events.linuxfoundation.org/images/stories/pdf/lf_elc12_kobayashi.pdf

同时, 推荐下面这篇关于在ARM体系结构下使用Ftrace的文章
http://elinux.org/Ftrace_Function_Graph_ARM


以上支持ARM 的Ftrace的patch在commit:376cfa8730c08c0394d0aa1d4a80fd8c9971f323 中引入了kernel的mainline.


-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Ftrace是用来帮助调试kernel,了解kernel中的运行机制及performance相关问题而设计的基于debugfs的kernel内部的trace机制.


Ftrace的一些前提知识:

  1. mcount, 当gcc的-gp参数启用时,根据不同的系统及其compiler相关,会使得每次函数调用之前,先执行这个叫做mcount的操作.它由对应的profiling library提供.
    参见:http://sourceware.org/binutils/docs/gprof/Implementation.html

搭建Ftrace调试环境

  1. 使用build root编译内核及相应的rootfs
    这里需要注意, build root只支持ext2(目前还不支持ext3,ext4), 所以编译好的output/images/下的rootfs是ext2的.
    如果用比较新的内核,编出的bzImage中不支持ext2的rootfs引导, 所以会出错.
    这里就需要把rootfs.ext2的rootfs image转换成ext3的, 如下:
        sudo dd if=/dev/zero of=disk.image bs=1024k count=4096
        mkfs.ext3 -F -b 1024 disk.image 4096
        sudo mount -o loop disk.image /mnt/disk_ext3/
        sudo mount -o loop rootfs.ext2 /mnt/disk_ext2/
        sudo cp -r /mnt/disk_ext2/* /mnt/disk_ext3/
        sudo umount /mnt/disk_ext3

  2. 运行qemu
    qemu -kernel ~/opensource/qemu/test_ftrace/bzImage \
    -hda ~/opensource/qemu/test_ftrace/disk.ext3 \
    -boot c \
    -m 256 \
    -append "root=/dev/sda rw" \
    -localtime \
    -no-reboot \
    -name ftrace_linux \
    -net nic -net user hostfwd=tcp:5555:23
     
  3. qemu启动完毕后,在target的shell中mount debugfsmount -t debugfs nodev /sys/kernel/debug则就能在/sys/kernel/debug/tracing找到各种调试接口了

下面是如何使用ftrace

  1. 查看当前内核支持什么样的ftrace,这依赖于你在编译内核时,打开了哪些ftrace支持.cat available_tracers
    function_graph function nop ...

  2. 打开你想要的trace功能,并查看trace结果
    [tracing]# echo [function] > current_tracer  -> 这里[]中键入目前支持的ftrace方式
    [tracing]# cat current_tracer

  3. ftrace了一个很有用的ftrace_printk机制, 方便内核开发者使用它,来提供更快速轻量的log机制, 它会把log记在ftrace自己的ring buffer中, 并能够支持interrupt等场合下使用.
    如,
    把trace_printk("read foo %d out of bar %p\n", bar->foo, bar);加入一个模块
    然后就可以通过读取cat /sys/kernel/debug/ftrace/trace 来查看相关log
    

  4. 如何打开/关闭trace
    通过对/sys/kernel/debug/ftrace/tracing_on写入1/0来打开/关闭,这样可以提高性能, 隔绝不需要的干扰信息.
    请注意,这里只是停止网trace ring buffer中写入log, 而不是关闭trace的整个机制, 它仍然不能降低ftrace带来的overhead.
    [tracing]# echo 0 > tracing_on
    [tracing]# echo function_graph > current_tracer
    [tracing]# echo 1 > tracing_on; run_test; echo 0 > tracing_on

  5. 提供接口给user space来利用ftrace提供的ring buffer, 从使得通过读取trace信息,能够知道user space和kernel space的交互及时间
    [tracing]# echo nop > current_tracer
    [tracing]# echo test > trace_marker[tracing]# cat trace# tracer: nop## TASK-PID CPU# TIMESTAMP FUNCTION# | | | | |    sh-848  [000] 1986.459489: tracing_mark_write:test
    参照<Debug the kernel using Ftrace - part2>, 给了一个完整的例子, 如何在开发中使用这个接口
    int trace_fd = -1;
        int marker_fd = -1;
    
        int main(int argc, char *argv)
        {
    	    char *debugfs;
    	    char path[256];
    	    [...]
    
    	    debugfs = find_debugfs();
    	    if (debugfs) {
    		    strcpy(path, debugfs);
    		    strcat(path,"/tracing/tracing_on");
    		    trace_fd = open(path, O_WRONLY);
    		    if (trace_fd >= 0)
    			    write(trace_fd, "1", 1);
    
    		    strcpy(path, debugfs);
    		    strcat(path,"/tracing/trace_marker");
    		    marker_fd = open(path, O_WRONLY);
    在一些critical section
    if (marker_fd >= 0)
    	    write(marker_fd, "In critical area\n", 17);
    
        if (critical_function() < 0) {
    	    /* we failed! */
    	    if (trace_fd >= 0)
    		    write(trace_fd, "0", 1);
        }
    其中find_debugfs()的代码是
    #define MAX_PATH 256
        #define _STR(x) #x
        #define STR(x) _STR(x)
        static const char *find_debugfs(void)
        {
    	    static char debugfs[MAX_PATH+1];
    	    static int debugfs_found;
    	    char type[100];
    	    FILE *fp;
    
    	    if (debugfs_found)
    		    return debugfs;
    
    	    if ((fp = fopen("/proc/mounts","r")) == NULL)
    		    return NULL;
    
    	    while (fscanf(fp, "%*s %"
    			  STR(MAX_PATH)
    			  "s %99s %*s %*d %*d\n",
    			  debugfs, type) == 2) {
    		    if (strcmp(type, "debugfs") == 0)
    			    break;
    	    }
    	    fclose(fp);
    
    	    if (strcmp(type, "debugfs") != 0)
    		    return NULL;
    
    	    debugfs_found = 1;
    
    	    return debugfs;
        }

    以上是在user space测使用tracing_on接口,kernel端的开发也提供了tracing_on()和tracing_off()的接口达到同样的目地.

  6. ftrace提供了接口更方便的调试kernel crash的问题
    ftrace_dump_on_oops, 既可以在kernel boot parameters打开,也可以在通过ehco 1 > /proc/sys/kernel/ftrace_dump_on_oops
    同时,可以控制dump信息的大小
    [tracing]# echo xx > buffer_size_kb
    

  7. ftrace提供了调试kernel stack使用情况的接口
    需要在编译内核的时候打开CONFIG_STACK_TRACER.
    它基于ftrace的function trace结构, 但是没有使用ring buffer. 所以没有引入额外的负担.
    echo 1 > /proc/sys/kernel/stack_tracer_enabled
    cat stack_max_size

关于使用Ftrace的例子及一些ftrace结果的format,参见ftrace.txt



参考资料:

    http://bec-systems.com/site/865/linux-tracing-tutorial

    http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=tree;f=Documentation/trace

    http://lwn.net/Articles/322666/

    http://lwn.net/Articles/365835/

    http://lwn.net/Articles/366796/

    http://lwn.net/Articles/370423/

    http://elinux.org/Kernel_Trace_Systems


你可能感兴趣的:(function,ext,Graph,buffer,Path,profiling)