大家好!今天我们要讨论一个调试工具:ftrace,之前在我的博客上没有讨论过。有什么比新的调试工具更令人兴奋的呢?很棒的ftrace并不是一个新工具!自2008年左右Linux的2.6内核版本发布以来,它就一直存在。这是我在Google上找到的最早的文档。所以,如果您是调试系统的“老手”,您可能已经用过它了!我知道ftrace已经有大约2.5年的历史了(LCTT译注:这篇文章最初写的时候),但还没有真正学习它。假设我明天有一个研讨会,那么关于ftrace应该讨论什么?所以今天是时候谈谈它了!什么是跟踪?ftrace是一项Linux内核功能,可让您跟踪Linux内核中的函数调用。你为什么这样做?好吧,假设您正在调试一个奇怪的问题,并且您已经在您的内核版本的源代码中找到了问题开始的地方,并且您想知道这里发生了什么?每次调试的时候,我不常看内核源码,但在极少数情况下我会看!例如,本周在工作中我有一个程序卡在了内核中。查看正在调用的函数有助于我更好地了解内核中正在发生的事情以及涉及哪些系统!(在我的例子中是虚拟内存系统)。我觉得ftrace是一个非常有用的工具(肯定没有strace应用广泛,也比较难用),但是值得学习。让我们开始吧!使用ftrace的第一步与strace和perf不同,ftrace并不是一个真正的程序——您不能只运行ftracemy_cool_function。这太容易了!如果您阅读使用ftrace调试内核,它会告诉您从cd/sys/kernel/debug/tracing开始,然后执行大量文件系统操作。这种方法对我来说太麻烦了-使用ftrace的一个简单示例如下所示:cd/sys/kernel/debug/tracingechofunction>current_tracerechodo_page_fault>set_ftrace_filtercattrace这个文件系统是跟踪系统的接口(“给这些神奇的文件赋值,然后应该发生的事情发生了”)似乎在理论上可行,但这对我来说不是最好的方法。幸运的是,ftrace团队也考虑到了这种不友好的用户界面,所以它有一个更容易使用的界面,它就是trace-cmd!!!trace-cmd是一个带有命令行参数的普通程序。我们稍后会用到它!我在LWN上找到了trace-cmd的介绍:trace-cmd:afront-endforFtrace。开始使用trace-cmd:让我们只跟踪一个函数首先,我需要使用sudoapt-getinstalltr??ace-cmd安装trace-cmd,这很简单。对于我的第一个ftrace演示,我决定看看我的内核如何处理页面错误。当Linux分配内存时,它通常是懒惰的(“你真的不打算使用内存,是吗?”)。这意味着当一个应用程序试图写入分配给它的内存时,会发生页面错误,而此时,内核实际上会为该应用程序分配物理内存。让我们从trace-cmd开始,让它跟踪do_page_fault函数!$sudotrace-cmdrecord-pfunction-ldo_page_faultplugin'function'按Ctrl^C停止记录我运行它几秒钟然后按Ctrl+C。令我惊讶的是,它生成了一个名为trace.dat的2.5MB跟踪文件。我们来看看这个文件的内容吧!$sudotrace-cmdreportchrome-15144[000]11446.466121:function:do_page_faultchrome-15144[000]11446.467910:function:do_page_faultchrome-15144[000]11446.469174:function:do_page_faultchrome-15144[000]11446.474225:function:do_page_faultchrome-15144[000]11446.474386:function:do_page_faultchrome-15144[000]11446.478768:function:do_page_faultCompositorTileW-15154[001]11446.480172:function:do_page_faultchrome-1830[003]11446.486696:function:do_page_faultCompositorTileW-15154[001]11446.488983:function:do_page_faultCompositorTileW-15154[001]11446.489034:function:do_page_faultCompositorTileW-15154[001]11446.489045:function:do_page_faultCompositorTileW-15154[001]11446.489045(CPUname1processID,chome15)looksneat(itshowsCPU)000),以及它跟踪的函数。查看整个文件(sudotrace-cmdreport|grepchrome),我们可以看到我们跟踪了大约1.5秒,在这1.5秒期间,Chrome有大约500个页面错误。这太酷了!这是我们做的第一个ftrace!下一个ftrace技巧:让我们跟踪一个进程!好吧,只看一个功能有点无聊!假设我想知道程序中发生了什么。我使用一个名为Hugo的静态站点生成器。看看内核为Hugo做了什么?我电脑上Hugo的PID现在是25314,所以我用下面的命令来记录所有的内核函数:sudotrace-cmdrecord--help#我看了帮助!sudotrace-cmdrecord-pfunction-P25314#record对于PID25314sudotrace-cmd报告输出18,000行。如果您对此感兴趣,可以在此处查看全部18,000行输出。18000行太多了,这里只摘录了其中的几行。当系统调用clock_gettime运行的时候,都发生了什么:compat_SyS_clock_gettimeSyS_clock_gettimeclockid_to_kclockposix_clock_realtime_getgetnstimeofday64__getnstimeofday64arch_counter_read__compat_put_timespec这是与进程调试相关的一些东西:cpufreq_sched_irq_workwake_up_processtry_to_wake_up_raw_spin_lock_irqsavedo_raw_spin_lock_raw_spin_lockdo_raw_spin_lockwalt_ktime_clockktime_getarch_counter_readwalt_update_task_ravgexiting_task虽然你可能还不理解它们does,butit'salsocooltobeabletoseeallthesefunctioncalls."functiongraph"traceThereisanothermodecalledfunction_graph.Itfunctionsthesameasafunctiontracer,exceptthatitcanbothenterandexitafunction.这是该跟踪器的输出sudotrace-cmdrecord-pfunction_graph-P25314同样,这只是一个片段(这次来自futex代码):|futex_wake(){|get_futex_key(){|get_user_pages_fast(){1.458us|__get_user_pages_fast();4.375|}|__might_sleep(){0.292我们|___might_sleep();2.333我们|}0.584我们|get_futex_key_refs();5.250我们|}0.583我们|put_page();+24.208我们|我们看到在这个例子中get_futex_key在futex_wake之后被调用。这是源代码中实际发生的事情吗?我们可以检查一下!!这里是Linux4.4(我的内核版本是4.4)中futex_wake的定义。为了节省时间,我直接贴出来了。其内容如下:staticintfutex_wake(u32__user*uaddr,unsignedintflags,intnr_wake,u32bitset){structfutex_hash_bucket*hb;结构futex_q*this,*next;unionfutex_keykey=FUTEX_KEY_INIT;诠释;WAKE_Q(wake_q);如果(!bitset)返回-EINVAL;ret=get_futex_key(uaddr,flags&FLAGS_SHARED,&key,VERIFY_READ);可以看到,futex_wake中的第一个函数调用真的是get_futex_key!奇妙!阅读函数跟踪绝对是比阅读内核代码更容易发现的方法,而且很高兴看到所有函数需要多长时间。如何知道可以跟踪哪些函数如果您运行sudotrace-cmdlist-f,您将获得可以跟踪的函数列表。这很简单但很重要。***一件事:事件!既然我们知道了如何在内核中跟踪函数,那就太棒了!我们可以跟踪的又一类事物!有些事件与我们的函数调用不匹配。例如,您可能想知道当一个程序被调入或调出CPU时会发生什么!您可能想通过“盯着”函数调用来弄明白,但是,让我告诉您,这是行不通的!由于该功能还为您提供了几个事件,您可以在重要事件发生时查看发生了什么。您可以使用sudocat/sys/kernel/debug/tracing/available_events查看这些事件的列表。我检查了所有schedswitch事件。我不完全知道schedswitch是什么,但是,我猜它与调度有关。sudocat/sys/kernel/debug/tracing/available_eventssudotrace-cmdrecord-esched:sched_switchsudotrace-cmd报告输出如下:16169.624862:Chrome_ChildIOT:24817[112]S==>chrome:15144[120]16169.624992:15144[120]S==>swapper/3:0[120]16169.625202:swapper/3:0[120]R==>Chrome_ChildIOT:24817[112]16169.625251:Chrome_ChildIOT:24817[112]R==>chrome:1561[112]16169.625437:chrome:1561[112]S==>chrome:15144[120]现在,可以清楚地看到这些开关,从PID24817->15144->kernel->24817->1561->15114。(所有这些事件都发生在同一个CPU上)。ftrace是如何工作的?ftrace是一个动态跟踪系统。当我们启动ftrace内核函数时,函数的代码会发生变化。让我们假设跟踪do_page_fault函数。内核会在该函数的汇编代码中插入一些额外的指令,以在每次调用该函数时提示跟踪系统。内核能够添加额外指令的原因是Linux将额外的一对NOP指令编译到每个函数中,因此有地方可以在需要时添加跟踪代码。这是一个非常复杂的问题,因为当我不需要使用ftrace来跟踪我的内核时,它根本不会影响性能。而当我需要跟踪的时候,我跟踪的函数越多,开销就越大。(也许有些地方不对,但是,我认为这就是ftrace的工作方式)更容易使用ftrace:brendangregg的工具和kernelshark正如我们在文档中讨论的那样,您需要考虑很多关于单个内核函数/事件的问题,这些都是直接使用ftrace完成的。能够做到这一点真是太酷了!但这也是很多工作!BrendanGregg(我们的Linux调试工具“god”)有一个工具存储库,它使用ftrace提供有关I/O延迟等各种信息。这是它在GitHub上的完整性能工具存储库。这里有一个权衡,那就是工具易于使用,但您只能使用BrendanGregg批准的工具和在工具中执行的操作。涵盖了很多方面!:)另一个工具是可视化ftrace的输出,它比kernelshark好。我还没有使用它,但它似乎工作。您可以使用sudoapt-getinstallkernelshark安装它。一个新的超级大国我很高兴能花一些时间学习ftrace!与任何内核工具一样,不同的内核版本有不同的效果,我希望有一天你会发现它有用!ftrace系列文章的索引,这里是我找到的一些关于ftrace的文章。其中大部分都在LWN(Linux每周新闻)上,这是Linux的绝佳资源(您可以购买订阅!)使用Ftrace调试内核-第1部分(2009年12月,StevenRostedt)使用Ftrace调试内核-第2部分(2009年12月,StevenRostedt)Linux函数跟踪器的秘密(2010年1月,StevenRostedt)trace-cmd:Ftrace的前端(2010年10月,StevenRostedt)使用KernelShark分析即时调试器(2011年,StevenRostedt)Ftrace:MysteriousSwitches(2014,BrendanGregg)内核文档:(非常有用)Documentation/ftrace.txtDocumentationofeventsyoucantraceDocumentation/events.txt一些关于linux内核开发的ftrace设计文档(没用,但很有趣!)Documentation/ftrace-设计.txt
