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

来源:互联网 发布:网络电玩 编辑:程序博客网 时间:2024/04/30 02:36

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>, 给了一个完整的例子, 如何在开发中使用这个接口
    [plain] view plaincopy
    1. int trace_fd = -1;  
    2.     int marker_fd = -1;  
    3.   
    4.     int main(int argc, char *argv)  
    5.     {  
    6.         char *debugfs;  
    7.         char path[256];  
    8.         [...]  
    9.   
    10.         debugfs = find_debugfs();  
    11.         if (debugfs) {  
    12.             strcpy(path, debugfs);  
    13.             strcat(path,"/tracing/tracing_on");  
    14.             trace_fd = open(path, O_WRONLY);  
    15.             if (trace_fd >= 0)  
    16.                 write(trace_fd, "1", 1);  
    17.   
    18.             strcpy(path, debugfs);  
    19.             strcat(path,"/tracing/trace_marker");  
    20.             marker_fd = open(path, O_WRONLY);  
    在一些critical section
    [plain] view plaincopy
    1. if (marker_fd >= 0)  
    2.         write(marker_fd, "In critical area\n", 17);  
    3.   
    4.     if (critical_function() < 0) {  
    5.         /* we failed! */  
    6.         if (trace_fd >= 0)  
    7.             write(trace_fd, "0", 1);  
    8.     }  
    其中find_debugfs()的代码是
    [plain] view plaincopy
    1. #define MAX_PATH 256  
    2.     #define _STR(x) #x  
    3.     #define STR(x) _STR(x)  
    4.     static const char *find_debugfs(void)  
    5.     {  
    6.         static char debugfs[MAX_PATH+1];  
    7.         static int debugfs_found;  
    8.         char type[100];  
    9.         FILE *fp;  
    10.   
    11.         if (debugfs_found)  
    12.             return debugfs;  
    13.   
    14.         if ((fp = fopen("/proc/mounts","r")) == NULL)  
    15.             return NULL;  
    16.   
    17.         while (fscanf(fp, "%*s %"  
    18.               STR(MAX_PATH)  
    19.               "s %99s %*s %*d %*d\n",  
    20.               debugfs, type) == 2) {  
    21.             if (strcmp(type, "debugfs") == 0)  
    22.                 break;  
    23.         }  
    24.         fclose(fp);  
    25.   
    26.         if (strcmp(type, "debugfs") != 0)  
    27.             return NULL;  
    28.   
    29.         debugfs_found = 1;  
    30.   
    31.         return debugfs;  
    32.     }  

    以上是在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
原创粉丝点击