内核头文件 include/linux/kernel.h 中描述了 ftrace 提供的工具函数的原型,这些函数包括 trace_printk、tracing_on/tracing_off 等。本文通过示例模块程序向读者展示如何在代码中使用这些工具函数。

  使用 trace_printk 打印跟踪信息

  ftrace 提供了一个用于向 ftrace 跟踪缓冲区输出跟踪信息的工具函数,叫做 trace_printk(),它的使用方式与 printk() 类似。可以通过 trace 文件读取该函数的输出。从头文件 include/linux/kernel.h 中可以看到,在激活配置 CONFIG_TRACING 后,trace_printk() 定义为宏:

   #define trace_printk(fmt, args...)    
    ... 

  下面通过一个示例模块 ftrace_demo 来演示如何使用 trace_printk() 向跟踪缓冲区输出信息,以及如何查看这些信息。这里的示例模块程序中仅提供了初始化和退出函数,这样读者不会因为需要为模块创建必要的访问接口比如设备文件而分散注意力。注意,编译模块时要加入 -pg 选项。

清单 1. 示例模块 ftrace_demo

 /*                           
 * ftrace_demo.c 
 */                           
 #include <linux/init.h> 
 #include <linux/module.h> 
 #include <linux/kernel.h> 
 
 MODULE_LICENSE("GPL"); 
 
 static int ftrace_demo_init(void) 
 { 
 trace_printk("Can not see this in trace unless loaded for the second timen"); 
 return 0; 
 } 
 
 static void ftrace_demo_exit(void) 
 { 
 trace_printk("Module unloadingn"); 
 } 
 
 module_init(ftrace_demo_init); 
 module_exit(ftrace_demo_exit); 

  示例模块非常简单,仅仅是在模块初始化函数和退出函数中输出信息。接下来要对模块的运行进行跟踪,如清单 2 所示。

清单 2. 对模块 ftrace_demo 进行跟踪

 [root@linux tracing]# pwd 
 /sys/kernel/debug/tracing 
 [root@linux tracing]# echo 0 > tracing_enabled 
 [root@linux tracing]# echo 1 > /proc/sys/kernel/ftrace_enabled 
 [root@linux tracing]# echo function_graph > current_tracer 
 
 # 事先加载模块 ftrace_demo 
 
 [root@linux tracing]# echo ':mod:ftrace_demo' > set_ftrace_filter 
 [root@linux tracing]# cat set_ftrace_filter 
 ftrace_demo_init 
 ftrace_demo_exit 
 
 # 将模块 ftrace_demo 卸载 
 
 [root@linux tracing]# echo 1 > tracing_enabled 
 
 # 重新进行模块 ftrace_demo 的加载与卸载操作 
 
 [root@linux tracing]# cat trace 
 # tracer: function_graph 
 # 
 # CPU DURATION         FUNCTION CALLS 
 # |   |  |           |  |  |  | 
 1)        | /* Can not see this in trace unless loaded for the second time */ 
 0)        | /* Module unloading */ 

  在这个例子中,使用 mod 指令显式指定跟踪模块 ftrace_demo 中的函数,这需要提前加载该模块,否则在写文件 set_ftrace_filter 时会因为找不到该模块报错。这样在第一次加载模块时,其初始化函数 ftrace_demo_init 中调用 trace_printk 打印的语句就跟踪不到了。因此这里会将其卸载,然后激活跟踪,再重新进行模块 ftrace_demo 的加载与卸载操作。最终可以从文件 trace 中看到模块在初始化和退出时调用 trace_printk() 输出的信息。

  这里仅仅是为了以简单的模块进行演示,故只定义了模块的 init/exit 函数,重复加载模块也只是为了获取初始化函数输出的跟踪信息。实践中,可以在模块的功能函数中加入对 trace_printk 的调用,这样可以记录模块的运作情况,然后对其特定功能进行调试优化。还可以将对 trace_printk() 的调用通过宏来控制编译,这样可以在调试时将其开启,在最终发布时将其关闭。

  使用 tracing_on/tracing_off 控制跟踪信息的记录

  在跟踪过程中,有时候在检测到某些事件发生时,想要停止跟踪信息的记录,这样,跟踪缓冲区中较新的数据是与该事件有关的。在用户态,可以通过向文件 tracing_on 写入 0 来停止记录跟踪信息,写入 1 会继续记录跟踪信息。而在内核代码中,可以通过函数 tracing_on() 和 tracing_off() 来做到这一点,它们的行为类似于对 /sys/kernel/debug/tracing 下的文件 tracing_on 分别执行写 1 和 写 0 的操作。使用这两个函数,会对跟踪信息的记录控制地更准确一些,这是因为在用户态写文件 tracing_on 到实际暂停跟踪,中间由于上下文切换、系统调度控制等可能已经经过较长的时间,这样会积累大量的跟踪信息,而感兴趣的那部分可能会被覆盖掉了。

  现在对清单 1 中的代码进行修改,使用 tracing_off() 来控制跟踪信息记录的暂停。

清单 3. 使用 tracing_off 的模块 ftrace_demo

 /*                           
 * ftrace_demo.c 
 *   modified to demostrate the usage of tracing_off 
 */                           
 #include <linux/init.h> 
 #include <linux/module.h> 
 #include <linux/kernel.h> 
 
 MODULE_LICENSE("GPL"); 
 
 static int ftrace_demo_init(void) 
 {  
 trace_printk("ftrace_demo_init calledn"); 
 tracing_off(); 
 return 0; 
 } 
 
 static void ftrace_demo_exit(void) 
 { 
 trace_printk("ftrace_demo_exit calledn"); 
 tracing_off(); 
 } 
 
 module_init(ftrace_demo_init); 
 module_exit(ftrace_demo_exit); 

  下面对其进行跟踪,如清单 4 所示。

清单 4. 跟踪

 [root@linux tracing]# pwd 
 /sys/kernel/debug/tracing 
 [root@linux tracing]# echo 0 > tracing_enabled 
 [root@linux tracing]# echo 1 > /proc/sys/kernel/ftrace_enabled 
 [root@linux tracing]# echo 1 > tracing_on 
 [root@linux tracing]# echo function > current_tracer 
 [root@linux tracing]# echo 1 > tracing_enabled 
 
 # 加载模块 ftrace_demo,模块初始化函数 ftrace_demo_init 被调用 
 
 [root@linux tracing]# cat tracing_on 
 0 
 [root@linux tracing]# cat trace | wc -l 
 120210 
 [root@linux tracing]# cat trace | grep -n ftrace_demo_init 
 120187:   insmod-2897 [000] 2610.504611: ftrace_demo_init <-do_one_initcall 
 120193:   insmod-2897 [000] 2610.504667: ftrace_demo_init: ftrace_demo_init called 
 
 [root@linux tracing]# echo 1 > tracing_on  # 继续跟踪信息的记录 
 
 # 卸载模块 ftrace_demo,模块函数 ftrace_demo_exit 被调用 
 
 [root@linux tracing]# cat tracing_on 
 0 
 [root@linux tracing]# wc -l trace 
 120106 trace 
 [root@linux tracing]# grep -n ftrace_demo_exit trace 
 120106:      rmmod-2992 [001] 3016.884449: : ftrace_demo_exit called 

  在这个例子中,跟踪开始之前需要确保 tracing_on 的值为 1。跟踪开始后,加载模块 ftrace_demo,其初始化方法 ftrace_demo_init 被调用,该方法会调用 tracing_off() 函数来暂停跟踪信息的记录,这时文件 tracing_on 的值被代码设置为 0。查看文件 trace,可以看到 ftrace_demo_init 相关的记录位于跟踪信息的末端,这是因为从调用 trace_off() 到其生效需要一段时间,这段时间中的内核活动会被记录下来;相比从用户态读写 tracing_on 文件,这段时间开销要小了许多。卸载模块时的情况与此类似。从这里可以看到,在代码中使用 tracing_off() 可以控制将感兴趣的信息保存在跟踪缓冲区的末端位置,不会很快被新的信息所覆盖,便于及时查看。

  实际代码中,可以通过特定条件(比如检测到某种异常状况,等等)来控制跟踪信息的记录,函数的使用方式类似如下的形式:

 if (condition) 
 tracing_on() or tracing_off() 

  跟踪模块运行状况时,使用 ftrace 命令操作序列在用户态进行必要的设置,而在代码中则可以通过 traceing_on() 控制在进入特定代码区域时开启跟踪信息,并在遇到某些条件时通过 tracing_off() 暂停;读者可以在查看完感兴趣的信息后,将 1 写入 tracing_on 文件以继续记录跟踪信息。实践中,可以通过宏来控制是否将对这些函数的调用编译进内核模块,这样可以在调试时将其开启,在最终发布时将其关闭。

  用户态的应用程序可以通过直接读写文件 tracing_on 来控制记录跟踪信息的暂停状态,以便了解应用程序运行期间内核中发生的活动。

  小结

  本系列文章对 ftrace 的配置和使用进行了介绍。本文是其中的第三部分,通过示例代码介绍了 ftrace 所提供的部分工具函数的使用,包括 trace_printk、tracing_on/tracing_off 。至此,本系列文章的所有内容都已经介绍完毕。通过本系列文章,读者可以了解如何使用 ftrace 来对内核进行调试和分析。ftrace 使用起来非常灵活,并且支持多种跟踪器,而且它的框架结构使得在添加新的跟踪器的时候会比较方便。读者可以在以后的工作和学习中探索 ftrace 的各种用法。

ftrace 提供的工具函数的更多相关文章

  1. 反射工具类.提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class,被AOP过的真实类等工具函数.java

    import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.ap ...

  2. 五、jquery使用工具函数

    工具函数对应的网址在 http://api.jquery.com/categouy/utilities/   工具函数处理对象的不同,可以将其分为几大类别:浏览器的检测.数组和对象的操作.字符串的操作 ...

  3. jQuery实用工具函数

    1. 什么是工具函数 在jQuery中,工具函数是指直接依附于jQuery对象.针对jquery对象本身定义的说法,即全局性的函数,我们统称为工具函数,或Utilities函数.它们有一个明显的特征, ...

  4. jQuery工具函数

    要点:1.字符串操作2.数组和对象操作3.测试操作4.URL 操作5.浏览器检测6.其他操作 工具函数是指直接依附于 jQuery 对象,针对 jQuery 对象本身定义的方法,即全局性的函数.它的作 ...

  5. map each 工具函数

    工具函数  即全局性的函数作用主要是提供比如字符串,数组,对象等方面的遍历 字符串工具 $.trim(str)  去除字符串两边的空格 遍历机制 map函数(function (obj,index){ ...

  6. 从零开始学习jQuery (九) jQuery工具函数

    一.摘要 本系列文章将带您进入jQuery的精彩世界, 其中有很多作者具体的使用经验和解决方案,  即使你会使用jQuery也能在阅读中发现些许秘籍. 我们经常要使用脚本处理各种业务逻辑, 最常见的就 ...

  7. 20151212jquery学习笔记--工具函数

    工具函数是指直接依附于 jQuery 对象,针对 jQuery 对象本身定义的方法,即全局性 的函数.它的作用主要是提供比如字符串.数组.对象等操作方面的遍历. 一.字符串操作 在 jQuery 中, ...

  8. 读 zepto 源码之工具函数

    Zepto 提供了丰富的工具函数,下面来一一解读. 源码版本 本文阅读的源码为 zepto1.2.0 $.extend $.extend 方法可以用来扩展目标对象的属性.目标对象的同名属性会被源对象的 ...

  9. jQuery源码分析-03扩展工具函数jQuery.extend

    // 扩展工具函数 jQuery.extend({ // http://www.w3school.com.cn/jquery/core_noconflict.asp // 释放$的 jQuery 控制 ...

随机推荐

  1. 多源最短路径floyd

    #include<iostream> #define INF 105 using namespace std; int main() { ][],mark,x,y,g; while(cin ...

  2. Robot Framework(十一) 执行测试用例——后处理输出

    3.3后处理输出 在测试执行期间生成的XML输出文件可以在之后由rebot工具进行后处理,该工具是Robot Framework的组成部分.在测试执行期间生成测试报告和日志时会自动使用它,但在执行后也 ...

  3. js获取当前时间的前一天/后一天

    Date curDate = new Date();var preDate = new Date(curDate.getTime() - 24*60*60*1000); //前一天var nextDa ...

  4. 官方webupload上传多个文件或者图片的方法

    文件上传 页面代码: <!--引入CSS--> <link rel="stylesheet" type="text/css" href=&qu ...

  5. javaEE(13)_jdbc框架

    一.使用模板方法设计模式简化开发 模板方法设计模式,执行一个程序有很多步骤,将每次都要执行的共有的提取出来放到一个抽象父类中,变化的部分通过让子类传递参数过来或将这部分抽象为抽象方法让子类通过继承的方 ...

  6. ios之UIProgressView

    UIProgressView和UIActivityIndicator有些类似   但是不同之处在于, UIProgressView能够更加精确的反应进度 UIActivityIndicator则只能表 ...

  7. Git学习之路

    目录 git安装 linux windows git命令 创建版本库 提交文件 仓库状态 版本回退 工作区和暂存区 工作区 暂存区 推送.下拉和克隆 推送 下拉 克隆 git应该可以说是程序员必备技能 ...

  8. python--触发器, 储存过程, 事务

    一. 触发器 使用触发器可以定制用户对某一张表的数据进行 [增, 删  ,改] 操作时前后的行为, (注意 没有查询),在进行增删改的时候出发的某个动作叫做 触发器. 其实就是在增删改的时候另外执行了 ...

  9. codeforces Lightsabers (hard)

    题目大意: 给定每种球的数量,求从中选取k个球有多少种不同的取法,同种球视为相同的. 题解: 多项式(1+x+x^2+...+x^a[1])*(1+x+x^2+...+x^a[2])*(1+x+x^2 ...

  10. linux相关技术

    1.查询服务器tcp连接状态及连接数 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'