ftrace 提供的工具函数

  内核头文件 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 进行跟踪

 [[email protected] tracing]# pwd 
 /sys/kernel/debug/tracing 
 [[email protected] tracing]# echo 0 > tracing_enabled 
 [[email protected] tracing]# echo 1 > /proc/sys/kernel/ftrace_enabled 
 [[email protected] tracing]# echo function_graph > current_tracer 
 
 # 事先加载模块 ftrace_demo 
 
 [[email protected] tracing]# echo ‘:mod:ftrace_demo‘ > set_ftrace_filter 
 [[email protected] tracing]# cat set_ftrace_filter 
 ftrace_demo_init 
 ftrace_demo_exit 
 
 # 将模块 ftrace_demo 卸载 
 
 [[email protected] tracing]# echo 1 > tracing_enabled 
 
 # 重新进行模块 ftrace_demo 的加载与卸载操作 
 
 [[email protected]inux 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. 跟踪

 [[email protected] tracing]# pwd 
 /sys/kernel/debug/tracing 
 [[email protected] tracing]# echo 0 > tracing_enabled 
 [[email protected] tracing]# echo 1 > /proc/sys/kernel/ftrace_enabled 
 [[email protected] tracing]# echo 1 > tracing_on 
 [[email protected] tracing]# echo function > current_tracer 
 [[email protected] tracing]# echo 1 > tracing_enabled 
 
 # 加载模块 ftrace_demo,模块初始化函数 ftrace_demo_init 被调用 
 
 [[email protected] tracing]# cat tracing_on 
 0 
 [[email protected] tracing]# cat trace | wc -l 
 120210 
 [[email protected] 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 
 
 [[email protected] tracing]# echo 1 > tracing_on  # 继续跟踪信息的记录 
 
 # 卸载模块 ftrace_demo,模块函数 ftrace_demo_exit 被调用 
 
 [[email protected] tracing]# cat tracing_on 
 0 
 [[email protected] tracing]# wc -l trace 
 120106 trace 
 [[email protected] 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 的各种用法。

时间: 2024-11-05 16:09:16

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

工具函数(一)

工具函数是指直接依附于jQuery对象,针对jQuery对象本身定义的方法,即全局性的函数.它的作用主要是提供比如字符串.数组.对象等操作方面的遍历. 字符串操作 在jQuery中,字符串的工具函数只有一个,就是去除字符串左右空格的工具函数:$.trim().如: var str = " jQuery "; alert(str); alert($.trim(str)); 数组和对象操作 jQuery为处理数组和对象提供了一些工具函数, 这些函数可以便利的给数组或对象进行遍历.筛选.搜索

读 zepto 源码之工具函数

Zepto 提供了丰富的工具函数,下面来一一解读. 源码版本 本文阅读的源码为 zepto1.2.0 $.extend $.extend 方法可以用来扩展目标对象的属性.目标对象的同名属性会被源对象的属性覆盖. $.extend 其实调用的是内部方法 extend, 所以我们先看看内部方法 extend 的具体实现. function extend(target, source, deep) { for (key in source) // 遍历源对象的属性值 if (deep && (i

工具函数(二)

测试操作 在jQuery中,数据有着各种类型和状态.有时,我们希望能通过判断数据的类型和状态做相应的操作.jQuery提供了五组测试用的工具函数. 测试工具函数 函数名 说明 $.isArray(obj) 判断是否为数组对象,是返回true $.isFunction(obj) 判断是否为函数,是返回true $.isEmptyObject(obj) 判断是否为空对象,是返回true $.isPlainObject(obj) 判断是否为纯粹对象,是返回true $.contains(obj) 判断

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

工具函数是指直接依附于 jQuery 对象,针对 jQuery 对象本身定义的方法,即全局性 的函数.它的作用主要是提供比如字符串.数组.对象等操作方面的遍历. 一.字符串操作 在 jQuery 中,字符串的工具函数只有一个,就是去除字符串左右空格的工具函数: $.trim(). //$.trim()去掉字符串两边空格 varstr=' jQuery '; alert(str); alert($.trim(str)); 二.数组和对象操作 jQuery 为处理数组和对象提供了一些工具函数,这些函

jquery 源码学习(四)构造jQuery对象-工具函数

jQuery源码分析-03构造jQuery对象-工具函数,需要的朋友可以参考下. 作者:nuysoft/高云 QQ:47214707 EMail:[email protected] 声明:本文为原创文章,如需转载,请注明来源并保留原文链接. 读读写写,不对的地方请告诉我,多多交流共同进步,本章的的PDF等本章写完了发布. jQuery源码分析系列的目录请查看 http://nuysoft.iteye.com/blog/1177451,想系统的好好写写,目前还是从我感兴趣的部分开始,如果大家有对哪

jQuery 工具函数

工具函数是指直接依附于 jQuery 对象,针对 jQuery  对象本身定义的方法,即全局性的函数.它的作用主要是提供比如字符串.数组.对象等操作方面的遍历. 一.字符串操作 在 jQuery 中,字符串的工具函数只有一个,就是去除字符串左右空格的工具函数: $.trim(). //$.trim()去掉字符串两边空格 var str=' jQuery '; alert(str); alert($.trim(str)); 二.数组和对象操作 jQuery 为处理数组和对象提供了一些工具函数,这些

第一百七十五节,jQuery,工具函数

jQuery,工具函数 学习要点: 1.字符串操作 2.数组和对象操作 3.测试操作 4.URL 操作 5.浏览器检测 6.其他操作 工具函数是指直接依附于 jQuery 对象,针对 jQuery 对象本身定义的方法,即全局性 的函数.它的作用主要是提供比如字符串.数组.对象等操作方面的遍历. 一.字符串操作 在 jQuery 中,字符串的工具函数只有一个,就是去除字符串左右空格的工具函数: trim()去掉字符串两边空格 var str = ' jQuery '; alert(str); al

jQuery使用工具函数

1. 什么是工具函数 在jQuery中,工具函数是指直接依附于jQuery对象.针对jquery对象本身定义的说法,即全局性的函数,我们统称为工具函数,或Utilities函数.它们有一个明显的特征,一般情况下,采用如下的格式进行调用: $.函数名()或jquery.函数() 2.工具函数的分类 根据工具函数处理对象的不同,可以将其分为下列几大类别:浏览器的检测.数组和对象的操作.字符串操作.测试操作.URL操作. 1)浏览器的检测 在浏览器检测中,又可分为浏览器类型与特征的检测,前者获取浏览器

jquery学习随笔(工具函数)

在jQuery 中,字符串的工具函数只有一个,就是去除字符串左右空格的工具函数:$.trim(). //$.trim()去掉字符串两边空格 var str = ' jQuery '; alert(str); alert($.trim(str)); jQuery 为处理数组和对象提供了一些工具函数,这些函数可以便利的给数组或对象进行遍历.筛选.搜索等操作. //$.each()遍历数组 var arr = ['张三', '李四', '王五', '马六']; $.each(arr, function