赞
踩
总体而言三者各有千秋,gdb可动态调试,ftrace主打系统函数追踪,而systemtap功能很强大,个人感觉基本覆盖了ftrace,且能动态捕获系统函数或应用函数的执行时间,项目工作中很实用。
gdb太普遍了,讲的人很多,直接给前人的链接了:
https://blog.csdn.net/weixin_37921201/article/details/120117096
https://zhuanlan.zhihu.com/p/100403438
GDB条件断点(condition命令)详解
这里只补充下启动gdb的几种方式,本次以用户程序qemu为例说明:
- //直接加程序名调试
- gdb qemu-system-x86_64
-
- //带参数调试(qemu-system-ppc64后面的都是qemu自己的参数)
- gdb --args /home/jcf/qemu-6.2.0/build/qemu-system-ppc64 -m 1G -smp 1 -boot cd -hda /home/jcf/pseries.img
-
- //图形化界面调试
- gdb --tui --args /home/jcf/qemu-6.2.0/build/qemu-system-ppc64 -m 1G -smp 1 -boot cd -hda /home/jcf/pseries.img
-
- //程序已启动,附加上去调试(pid需要用 ps -ef 提前获取)
- gdb --tui attach $pid
- gdb --tui attach --pid=xxx
- gdb --tui /home/jcf/qemu-6.2.0/build/qemu-system-ppc64 $pid
一、总体介绍
*trace系列基本用于跟踪,细分的话有跟踪系统调用的strace(简单易用),跟踪系统函数执行的ftrace,跟踪进程执行的ptrace等,本文目前暂介绍实际工程项目中用到的ftrace。
ftrace官方文档在kernel/Documentation/trace/ftrace.txt文件中。
首先要确定内核打开了ftrace的编译选项: CONFIG_FTRACE (一般默认打开)
使用ftrace接口之前,先检查debugfs系统是否挂载(一般默认打开)
# mount | grep debugfs
如果系统没有自动挂载debugfs文件系统,则要先手动挂载:
# mount -t debugfs nodev /sys/kernel/debug
ftracer的目录为/sys/kernel/debug/tracing,下面介绍这个目录下的常用文件:
tracing_on,启用/禁用向追踪缓冲区写入功能。1为启用,0为禁用。
available_tracers,当前内核中可用的插件追踪器。
current_tracer,指定当前要使用的插件追踪器。
tracing_cpumask,以十六进制的位掩码指定要作为追踪对象的处理器,例如,指定0xb时仅在处理器0、1、3上进行追踪。
set_ftrace_pid,指定作为追踪对象的进程的PID号。
trace,以文本格式输出内核中追踪缓冲区的内容。
trace_pipe,与trace相同,但是运行时像管道一样,可以在每次事件发生时读出追踪信息,但是读出的内容不能再次读出。
buffer_size_kb,以KB为单位指定各个CPU追踪缓冲区的大小。系统追踪缓冲区的总大小就是这个值乘以CPU的数量。设置buffer_size_kb时,必须设置current_tracer为nop追踪器。
set_ftrace_filter,指定要追踪的函数名称,函数名称仅可以包含一个通配符。
set_ftrace_notrace,指定不要追踪的函数名称。
ftrace可以使用的插件追踪器主要有:
function,函数调用追踪器,可以看出哪个函数何时调用。
function_graph,函数调用图表追踪器,可以看出哪个函数被哪个函数调用,何时返回。
mmiotrace,MMIO( Memory MappedI/O)追踪器,用于Nouveau驱动程序等逆向工程。
blk,block I/O追踪器。
wakeup,进程调度延迟追踪器。
wakeup_rt,与wakeup相同,但以实时进程为对象。
irqsoff,当中断被禁止时,系统无法响应外部事件,造成系统响应延迟,irqsoff跟踪并记录内核中哪些函数禁止了中断,对于其中禁止中断时间最长的,irqsoff将在log文件的第一行标示出来,从而可以迅速定位造成系统响应延迟的原因。
preemptoff,追踪并记录禁止内核抢占的函数,并清晰显示出禁止内核抢占时间最长的函数。
preemptirqsoff,追踪并记录禁止内核抢占和中断时间最长的函数。
sched_switch,进行上下文切换的追踪,可以得知从哪个进程切换到了哪个进程。
nop,不执行任何操作。不使用插件追踪器时指定。
二、使用案例步骤
cd /sys/kernel/debug/tracing
echo 0 > tracing_on //关闭trace
echo function_graph > current_tracer //设置当前的跟踪器是function_graph(调用关系)
echo 5 > max_graph_depth //设置调用关系深度为5层
或
echo function > current_tracer //设置当前的跟踪器是function(列表)
echo funcgraph-proc > trace_options
echo funcgraph-abstime > trace_options //在输出结果里增加每个函数的时间戳
ps -aux | grep xxx //查看要追踪的进程pid号
echo xxxpid> set_ftrace_pid //把你要跟踪的进程PID配置进ftrace
或
echo your_func > set_ftrace_filter //把你要跟踪的函数配置进ftrace
grep -i your_func available_filter_functions //可以查看上个步骤的函数有没有设置好
echo 0 > trace //把之前跟踪buffer里的数据清空
echo 1 > tracing_on //开始trace
启动你要跟踪的程序执行
echo 0 > tracing_on //关闭trace
cat trace > your_trace_result //输出得到的跟踪信息,可以将信息重定向到文件
三、参考
2. https://www.csdn.net/tags/MtTaEgzsMTA4MzEzLWJsb2cO0O0O.html
一、总体介绍
使用systemtap需要安装kernel-devel和待测软件如qemu-devel
二、环境测试
stap -e 'probe begin { printf("Hello World!\n") exit() }'
hw.tap脚本测试环境,其中begin为开始执行tap脚本打印的函数,end为结束(如手动ctrl+D)时打印的函数;
[root@test111 stapscripts]# cat hw.stap #! /bin/stap probe begin { print("===Hello World===\n") } probe end { print("===GunLe===\n") } [root@test111 stapscripts]# |
测试结果:
三、使用案例
stap -L 'process("/usr/libexec/qemu-kvm").function("qemu_vfree")'
查找kernel函数定义
stap -l 'kernel.function("sys_recv")'
[root@D01-303-D2-8 /home/jianchunfu]$ cat netif_receive_skb.stap probe kernel.function("netif_receive_skb").call { printf("--------------------------------------------------------\n"); print_backtrace(); printf("--------------------------------------------------------\n"); } [root@D01-303-D2-8 /home/jianchunfu]$ |
用户态探测点堆栈:print_ubacktrace()、sprint_ubacktrace()
内核态探测点堆栈:print_backtrace()、sprint_backtrace()
不带s和带s的区别是前者直接输出,后者是返回堆栈字符串。
[root@D01-303-D2-8 /home/jianchunfu]$ cat qemu-stack.stap #! /bin/stap probe process("/usr/libexec/qemu-kvm").function("qemu_vfree") { printf("--------------------------------------------------------\n"); print_ubacktrace(); printf("--------------------------------------------------------\n"); } [root@D01-303-D2-8 /home/jianchunfu]$ |
[root@D01-303-D2-8 /home/jianchunfu]$ cat qemu-cpr.stap #! /bin/stap probe process("/usr/libexec/qemu-kvm").function("qmp_cpr_save") { printf("--------------------------------------------------------\n"); print_ubacktrace(); printf("--------------------------------------------------------\n"); } [root@D01-303-D2-8 /home/jianchunfu]$ |
thread_indent(n): 补充空格
ppfunc(): 当前探测点所在的函数
在call探测点调用thread_indent(4)补充4个空格,在return探测点调用thread_indent(-4)回退4个空格,效果如下
[root@D01-303-D2-8 /home/jianchunfu]$ cat qemu-trace.tap #! /bin/stap probe process("/usr/libexec/qemu-kvm").function("qemu_memalign").call { printf("%s -> %s\n", thread_indent(4), ppfunc()); } probe process("/usr/libexec/qemu-kvm").function("qemu_memalign").return { printf("%s <- %s\n", thread_indent(-4), ppfunc()); } [root@D01-303-D2-8 /home/jianchunfu]$ |
[root@D01-303-D2-8 /home/jianchunfu]$ cat trace.tap probe process("/usr/libexec/qemu-kvm").function("*cpr*").call { printf("%s -> %s\n", thread_indent(4), ppfunc()); } probe process("/usr/libexec/qemu-kvm").function("*cpr*").return { printf("%s <- %s\n", thread_indent(-4), ppfunc()); } [root@D01-303-D2-8 /home/jianchunfu]$ |
Windows1:
Windows2:
global times probe process("/usr/libexec/qemu-kvm").function("hmp_cpr_save").return, process("/usr/libexec/qemu-kvm").function("hmp_cpr_exec").return, process("/usr/libexec/qemu-kvm").function("hmp_cpr_load").return { #耗时及耗时信息放在times 数组之中 times[pid(), ppfunc()] += gettimeofday_us() - @entry(gettimeofday_us()) } probe timer.s(10) { #每隔10秒打印一次 println("========%s", execname()) foreach([pid, pp] in times - limit 10) { printf("pid:%5d %50s %10ld(us)\n", pid, pp, times[pid, pp]) } delete times } |
Windows1:
Windows2:
对于进程较多脚本输出刷屏情况,可以 -x PID指定只追踪某一进程,也可以 -o file将输出重定向到某一文件,具体help指令可参见后续官方参考。
四、参考:
1. SystemTap使用指南_HanBlogs的博客-CSDN博客_systemtap tapset
2. 关于 Rocksdb 性能分析 需要知道的一些“小技巧“ -- perf_context的“内功” ,systemtap、perf、 ftrace的颜值_z_stand的博客-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。