trace-cmd是一个易于使用、功能丰富的命令,用于跟踪内核函数。在上一篇文章中,我介绍了如何使用ftrace来跟踪内核函数。通过写入和读取文件来使用ftrace会变得乏味,所以我围绕它做了一个包装器来运行带有选项的命令来启用和禁用跟踪、设置过滤器、查看输出、清除输出等。trace-cmd命令是一个工具,可以帮助你做到这一点。在本文中,我使用trace-cmd执行与ftrace文章中相同的任务。由于那篇文章会经常被引用,所以建议在阅读这篇文章之前阅读它。安装trace-cmd本文所有命令均在root用户下运行。因为内核内置了ftrace机制,可以使用如下命令来验证是否启用:#mount|greptracefsnoneon/sys/kernel/tracingtypetracefs(rw,relatime,seclabel)但是,你需要手动尝试安装trace-cmd命令:#dnfinstalltr??ace-cmd-yListavailabletracers在使用ftrace时,你必须查看文件的内容以查看哪些跟踪器可用。但是使用trace-cmd,您可以通过以下方式获取此信息:#trace-cmdlist-thwlatblkmmiotracefunction_graphwakeup_dlwakeup_rtwakeupfunctionnop启用函数跟踪器在我之前的文章中,我使用了两个跟踪器,在这里我将做同样的事情。使用函数启用您的第一个跟踪器:$trace-cmdstart-pfunctionplugin'function'查看跟踪输出启用跟踪器后,您可以使用show参数查看输出。这只显示前20行以保持示例简短(有关输出的解释,请参阅我之前的帖子):#trace-cmdshow|head-20##tracer:function##entries-in-buffer/entries-written:410142/3380032#P:8##_------=>irqs-off#/_----=>需要-重新安排#|/_---=>硬中断/软中断#||/_--=>抢占深度#|||/delay#TASK-PIDCPU#||||时间戳函数#|||||||gdbus-2606[004]..s.10520.538760:load_balance<-rebalance_domainsgdbus-2606[004]..s.10520.538761:idle_cpu<-load_balancegdbus-2606[004]..s.2606[004]..s.10520.538762:find_busiest_group<-load_balancegdbus-2606[004]..s.10520.538763:update_group_capacity<-update_sd_lb_stats.constprop.0gdbus-2606[004]..s.10520.538763:__msecs_to_jiffies<-update_group_capacitygdbus-2606[004]..s.10520.538765:idle_cpu<-update_sd_lb_stats.constprop.0gdbus-2606[004]..s.10520.538766:__msecs_to_jiffies<-rebalance_domains停止跟踪并清除缓冲区跟踪将继续在后台运行,您可以继续使用show查看输出要停止跟踪,请运行带停止参数的跟踪命令:#trace-cmdstop要清除缓冲区,请使用clear参数运行它:#trace-cmdclear启用函数调用图跟踪器运行第二个跟踪器,使用function_graph参数启用它。#trace-cmdstart-pfunction_graphPlugin'function_graph'再次使用show参数查看输出。正如预期的那样,输出与第一个跟踪输出略有不同。这一次,它包括一系列函数调用:#trace-cmdshow|head-20##tracer:function_graph##CPUDURATIONFUNCTIONCALLS#|||||||4)0.079|}/*rcu_all_qs*/4)0.327我们|}/*__cond_resched*/4)0.081我们|rcu_read_unlock_strict();4)|__cond_resched(){4)0.078我们|rcu_all_qs();4)0.243我们|4)|__cond_resched(){4)0.078我们|rcu_all_qs();4)0.241我们|}4)0.080我们|rcu_read_unlock_strict();4)|__cond_resched(){4)0.079我们|rcu_all_qs();4)0.235我们|}4)0.095我们|rcu_read_unlock_strict();4)|__cond_resched(){使用停止和清除命令停止跟踪并清除缓冲区:#trace-cmdstop#trace-cmdclear如果你想调整跟踪以增加深度要查看函数调用的更多深度,你可以调整跟踪器:#trace-cmd开始-pfunction_graph--max-graph-depth5plugin'function_graph'现在,当您将此输出与之前看到的进行比较时,您应该会看到更多的嵌套函数调用:#trace-cmdshow|head-20##tracer:function_graph##CPUDURATIONFUNCTIONCALLS#|||||||6)|__fget_light(){6)0.804我们|__fget_files();6)2.708|}6)3.650我们|}/*__fdget*/6)0.547我们|eventfd_poll();6)0.535|输出();6)|__fdget(){6)|__fget_light(){6)0.946我们|__fget_files();6)1.895|}6)2.849我们|}6)|sock_poll(){6)0.651我们|unix_poll();6)1.905我们|}6)0.475我们|输出();6)|__fdget(){如果你想了解可跟踪的函数要只跟踪一些函数而忽略其他函数,你需要知道确切的函数名称,你可以使用list-f参数获取它们。例如搜索常见的内核函数kmalloc,它被用来在内核中分配内存:#trace-cmdlist-f|grepkmallocbpf_map_kmalloc_nodemempool_kmalloc__traceiter_kmalloc__traceiter_kmalloc_nodekmalloc_slabkmalloc_orderkmalloc_order_tracekmalloc_large_node__kmalloc__kmalloc_track_caller__kmalloc_node__kmalloc_node_track_caller[...]下面是我的测试系统中可被追踪的函数总数:#trace-cmdlist-f|wc-l63165TracefunctionsrelatedtokernelmodulesYoucanalsotracefunctionsrelatedtospecifickernelmodules.Supposeyouwanttotrackthefunctionsrelatedtothekvmkernelmodule,youcandoitinthefollowingway.Makesurethemoduleisloaded:#lsmod|grepkvm_intelkvm_intel3358720kvm9871361kvm_intelRuntrace-cmdagainwiththelistparameter,andfromtheoutput,grepforlinesendingwith].Thiswillfilteroutkernelmodules.Thengrepthekernelmodulekvm_intelandyoushouldseeallfunctionsrelatedtothatkernelmodule.#trace-cmdlist-f|grep]$|grepkvm_intelvmx_can_emulate_instruction[kvm_intel]vmx_update_emulated_instruction[kvm_intel]vmx_setup_uret_msr[kvm_intel]vmx_set_identity_map_addr[kvm_intel]handle_machine_check[kvm_intel]handle_triple_fault[kvm_intel]vmx_patch_hypercall[kvm_intel][...]vmx_dump_dtsel[kvm_intel]vmx_dump_sel[kvm_intel]TracingspecificfunctionsNowthatyouknowhowtofindfunctionsofinterest,putthistotimewithanexample.就像上一篇文章一样,尝试跟踪文件系统相关的函数。我的测试系统上的文件系统是ext4。过程略有不同;您可以在记录参数之后使用要跟踪的函数的“模式”来运行命令,而不是启动参数。您还需要指定您想要的示踪剂;在这种情况下,function_graph。此命令将一直记录跟踪,直到您使用Ctrl+C停止它。所以几秒钟后,按Ctrl+C停止跟踪:#trace-cmdlist-f|grep^ext4_#trace-cmdrecord-lext4_*-pfunction_graphplugin'function_graph'HitCtrl^Ctostoprecording^CCPU0datarecordedatoffset=0x8560008192bytesinsize[...]查看跟踪记录查看你之前的记录跟踪记录,运行带有报告参数的命令。从输出中可以明显看出过滤器有效,您只能看到与ext4相关的函数跟踪:#trace-cmdreport|head-20[...]cpus=8trace-cmd-12697[000]11303.928103:funcgraph_entry:|ext4_show_options(){trace-cmd-12697[000]11303.928104:funcgraph_entry:0.187us|ext4_get_dummy_policy();trace-cmd-12697[000]11303.928105:funcgraph_exit:1.583us|}trace-cmd-12697[000]11303.928122:funcgraph_entry:|ext4_create(){trace-cmd-12697[000]11303.928122:funcgraph_entry:|}ext4_alloc_inode(){trace-cmd-12697[000]11303.928123:funcgraph_entry:0.101us|ext4_es_init_tree();trace-cmd-12697[000]11303.928123:funcgraph_entry:0.083us|ext4_init_pending_tree();trace-cmd-12697[000]11303.928123:funcgraph_entry:0.141us|ext4_fc_init_inode();trace-cmd-12697[000]11303.928123:funcgraph_exit:0.931u秒|}trace-cmd-12697[000]11303.928124:funcgraph_entry:0.081us|ext4_get_dummy_policy();trace-cmd-12697[000]11303.928124:funcgraph_entry:0.133us|ext4_get_group_desc();trace-cmd-12697[000]11303.928124:funcgraph_entry:0.115us|ext4_free_inodes_count();trace-cmd-12697[000]11303.928124:funcgraph_entry:0.114us|ext4_get_group_desc();跟踪特定的PID假设您要跟踪与打开另一个终端的一个进程(PID)关联的函数,记下正在运行的shell的PID:#echo$$10885再次运行记录命令,将PID与-P选项一起传递。这一次,让终端运行(也就是说,还不要按Ctrl+C):#trace-cmdrecord-P10885-pfunction_graphPlugin'function_graph'HitCtrl^Ctostoprecording在shell上运行一些命令Move到另一个A终端,您有一个运行特定PID的shell,然后运行任何命令,例如,ls命令以列出文件:#lsTemp-9b61f280-fdc1-4512-9211-5c60f764d702tracker-extract-3-files。1000v8-compile-cache-1000[…]移至启用跟踪的终端,按Ctrl+C停止跟踪:#trace-cmdrecord-P10885-pfunction_graphplugin'function_graph'按Ctrl^C停止记录^CCPU1数据记录在offset=0x856000618496bytesinsize[...]在跟踪的输出中,您可以在左侧看到PID和Bashshell,在右侧看到与其相关的函数调用。这对于缩小跟踪范围非常方便:#trace-cmdreport|head-20cpus=8
