❶ 使用 ftrace 来跟踪系统问题 - ftrace 介绍
虽然之前一直听说过 ftrace,但从来没将它用在实战中,在一次客户排查问题中,遇到了比较奇怪的现象,一位精通内核的朋友建议使用 ftrace 来定位一下。虽然那一次并没有使用 ftrace,但也让我觉得,后面我们势必要提供 ftrace 相关的工具帮助我们在线上定位问题,所以自己也决定重新学习使用下 ftrace,当然也决定写一系列的相关出来,这里就先简单介绍下 ftrace。
首先我们需要知道,什么是 ftrace?根据 linux Doc 的介绍,ftrace 是一个 Linux 内部的 trace 工具,能够帮助开发者和系统设计者知道内核当前正在干啥,从而更好的去分析性能问题。
Ftrace 能帮我们分析内核特定的事件,譬如调度,中断等,也能帮我们去追踪动态的内核函数,以及这些函数的调用栈还有栈的使用这些。它也能帮我们去追踪延迟,譬如中断被屏蔽,抢占被禁止的时间,以及唤醒一个进程之后多久开始执行的时间。
可以看到,使用 ftrace 真的能做到对系统内核非常系统的剖析,甚至都能通过 ftrace 来学习 Linux 内核,不过在更进一步之前,我们需要学会的是 - 如何使用 ftrace。
要使用 ftrace,首先就是需要将系统的 debugfs 或者 tracefs 给挂载到某个地方,幸运的是,几乎所有的 Linux 发行版,都开启了 debugfs/tracefs 的支持,所以我们也没必要去重新编译内核了。
在比较老的内核版本,譬如 CentOS 7 的上面,debugfs 通常被挂载到 /sys/kernel/debug 上面(debug 目录下面有一个 tracing 目录),而比较新的内核,则是将 tracefs 挂载到 /sys/kernel/tracing ,无论是什么,我都喜欢将 tracing 目录直接 link 到 /tracing 。后面都会假设直接进入了 /tracing 目录,后面,我会使用 Ubuntu 16.04 来举例子,内核版本是 4.13 来举例子。
我们使用 ls 来看看目录下面到底有什么:
可以看到,里面有非常多的文件和目录,具体的含义,大家可以去详细的看官方文档的解释,后面只会重点介绍一些文件。
我们可以通过 available_tracers 这个文件知道当前 ftrace 支持哪些插件。
通常用的最多的就是 function 和 function_graph ,当然,如果我们不想 trace 了,可以使用 nop 。我们首先打开 function :
上面我们将 function 写入到了 current_tracer 来开启 function 的 trace,我通常会在 cat 下 current_tracer 这个文件,主要是防止自己写错了。
然后 ftrace 就开始工作了,会将相关的 trace 信息放到 trace 文件里面,我们直接读取这个文件就能获取相关的信息。
我们可以设置只跟踪特定的 function
当然,如果我们不想 trace schele 这个函数,也可以这样做:
或者也可以这样做:
Function filter 的设置也支持 *match , match* , *match* 这样的正则表达式,譬如我们可以 echo '*lock*' < set_ftrace_notrace 来禁止跟踪带 lock 的函数, set_ftrace_notrace 文件里面这时候就会显示:
相比于 function , function_graph 能让我们更加详细的去知道内核函数的上下文,我们打开 function_graph :
我们也可以只跟踪某一个函数的堆栈
上面提到了 function 的 trace,在 ftrace 里面,另外用的多的就是 event 的 trace,我们可以在 events 目录下面看支持那些事件:
上面列出来的都是分组的,我们可以继续深入下去,譬如下面是查看 sched 相关的事件:
对于某一个具体的事件,我们也可以查看:
不知道大家注意到了没有,上述目录里面,都有一个 enable 的文件,我们只需要往里面写入 1,就可以开始 trace 这个事件。譬如下面就开始 trace sched_wakeup 这个事件:
我们也可以 trace sched 里面的所有事件:
当然也可以 trace 所有的事件:
从上面的例子可以看到,其实使用 ftrace 并不是那么方便,我们需要手动的去控制多个文件,但幸运的是,我们有 trace-cmd ,作为 ftrace 的前端, trace-cmd 能够非常方便的让我们进行 ftrace 的操作,譬如我们可以使用 record 命令来 trace sched 事件:
然后使用 report 命令来查看 trace 的数据:
当然,在 report 的时候也可以加入自己的 filter 来过滤数据,譬如下面,我们就过滤出 sched_wakeup 事件并且是 success 为 1 的。
大家可以注意下 success == 1 ,这其实是一个对事件里面 field 进行的表达式运算了,对于不同的事件,我们可以通过查看起 format 来知道它的实际 fields 是怎样的,譬如:
上面只是简单的列出了 ftrace 相关的使用,后续我会在写一些我们或者业界是如何用 ftrace 来解决问题的。另外,我们正在用 ftrace 开发非常多的性能诊断工具,如果你对这一块感兴趣,欢迎联系我 [email protected] 。
❷ 如何linux内核报告问题
Linux Kernel BUG:soft lockup CPU#1 stuck分析
1.线上内核bug日志
kernel: Deltaway too big! 18428729675200069867 ts=18446743954022816244 write stamp =18014278822746377
kernel:------------[ cut here ]------------
kernel:WARNING: at kernel/trace/ring_buffer.c:1988 rb_reserve_next_event+0x2ce/0x370()(Not tainted)
kernel:Hardware name: ProLiant DL360 G7
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel: Pid:5483, comm: master Not tainted 2.6.32-220.el6.x86_64 #1
kernel: CallTrace:
kernel:[<ffffffff81069b77>] ? warn_slowpath_common+0x87/0xc0
kernel:[<ffffffff81069bca>] ? warn_slowpath_null+0x1a/0x20
kernel:[<ffffffff810ea8ae>] ? rb_reserve_next_event+0x2ce/0x370
kernel:[<ffffffff810eab02>] ? ring_buffer_lock_reserve+0xa2/0x160
kernel:[<ffffffff810ec97c>] ? trace_buffer_lock_reserve+0x2c/0x70
kernel:[<ffffffff810ecb16>] ? trace_current_buffer_lock_reserve+0x16/0x20
kernel:[<ffffffff8107ae1e>] ? ftrace_raw_event_hrtimer_cancel+0x4e/0xb0
kernel:[<ffffffff81095e7a>] ? hrtimer_try_to_cancel+0xba/0xd0
kernel:[<ffffffff8106f634>] ? do_setitimer+0xd4/0x220
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
kernel: ---[end trace 4d0a1ef2e62cb1a2 ]---
abrt-mp-oops: Reported 1 kernel oopses to Abrt
kernel: BUG: softlockup - CPU#11 stuck for 4278190091s! [qmgr:5492]
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel: CPU 11
kernel:Moles linked in: fuse ipv6 power_meter bnx2 sg microcode serio_raw iTCO_wdtiTCO_vendor_support hpilo hpwdt i7core_edac edac_core shpchp ext4 mbcache jbd2sd_mod crc_t10dif hpsa radeon ttm drm_kms_helper drm i2c_algo_bit i2c_coredm_mirror dm_region_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
kernel:
kernel: Pid:5492, comm: qmgr Tainted: G W ---------------- 2.6.32-220.el6.x86_64 #1 HPProLiant DL360 G7
kernel: RIP:0010:[<ffffffff8106f730>] [<ffffffff8106f730>]do_setitimer+0x1d0/0x220
kernel: RSP:0018:ffff88080a661ef8 EFLAGS: 00000286
kernel: RAX:ffff88080b175a08 RBX: ffff88080a661f18 RCX: 0000000000000000
kernel: RDX:0000000000000000 RSI: 0000000000000082 RDI: ffff88080c8c4c40
kernel: RBP:ffffffff8100bc0e R08: 0000000000000000 R09: 0099d7270e01c3f1
kernel: R10:0000000000000000 R11: 0000000000000246 R12: ffffffff810ef9a3
kernel: R13:ffff88080a661e88 R14: 0000000000000000 R15: ffff88080a65a544
kernel: FS:00007f10b245f7c0(0000) GS:ffff88083c4a0000(0000) knlGS:0000000000000000
kernel: CS:0010 DS: 0000 ES: 0000 CR0: 000000008005003b
kernel: CR2:00007ff955977380 CR3: 000000100a80b000 CR4: 00000000000006e0
kernel: DR0:0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
kernel: DR3:0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
kernel:Process qmgr (pid: 5492, threadinfo ffff88080a660000, task ffff880809577500)
kernel: Stack:
kernel:00007f10b323def0 00007f10b248ead0 00007f10b26d0f78 00007f10b248ede0
kernel:<0> ffff88080a661f68 ffffffff8106f88a 0000000000000000 0000000000000000
kernel:<0> 000000000000014c 00000000000f423d 0000000000000000 0000000000000000
kernel: CallTrace:
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
kernel: Code:89 ef e8 74 66 02 00 83 3d 15 69 b5 00 00 75 37 49 8b 84 24 70 07 00 00 48 0508 08 00 00 66 ff 00 66 66 90 fb 66 0f 1f 44 00 00 <31> c0 e9 64 fe ff ff49 8b 84 24 68 07 00 00 48 c7 80 d0 00 00
kernel: CallTrace:
kernel:[<ffffffff8106f769>] ? do_setitimer+0x209/0x220
kernel:[<ffffffff8106f88a>] ? alarm_setitimer+0x3a/0x60
kernel:[<ffffffff8107c27e>] ? sys_alarm+0xe/0x20
kernel:[<ffffffff8100b308>] ? tracesys+0xd9/0xde
abrt-mp-oops: Reported 1 kernel oopses to Abrt
2.内核软死锁(soft lockup)bug原因分析
Soft lockup名称解释:所谓,soft lockup就是说,这个bug没有让系统彻底死机,但是若干个进程(或者kernel thread)被锁死在了某个状态(一般在内核区域),很多情况下这个是由于内核锁的使用的问题。
Linux内核对于每一个cpu都有一个监控进程,在技术界这个叫做watchdog(看门狗)。通过ps –ef | grep watchdog能够看见,进程名称大概是watchdog/X(数字:cpu逻辑编号1/2/3/4之类的)。这个进程或者线程每一秒钟运行一次,否则会睡眠和待机。这个进程运行会收集每一个cpu运行时使用数据的时间并且存放到属于每个cpu自己的内核数据结构。在内核中有很多特定的中断函数。这些中断函数会调用soft lockup计数,他会使用当前的时间戳与特定(对应的)cpu的内核数据结构中保存的时间对比,如果发现当前的时间戳比对应cpu保存的时间大于设定的阀值,他就假设监测进程或看门狗线程在一个相当可观的时间还没有执。Cpu软锁为什么会产生,是怎么产生的?如果linux内核是经过精心设计安排的CPU调度访问,那么怎么会产生cpu软死锁?那么只能说由于用户开发的或者第三方软件引入,看我们服务器内核panic的原因就是qmgr进程引起。因为每一个无限的循环都会一直有一个cpu的执行流程(qmgr进程示一个后台邮件的消息队列服务进程),并且拥有一定的优先级。Cpu调度器调度一个驱动程序来运行,如果这个驱动程序有问题并且没有被检测到,那么这个驱动程序将会暂用cpu的很长时间。根据前面的描述,看门狗进程会抓住(catch)这一点并且抛出一个软死锁(soft lockup)错误。软死锁会挂起cpu使你的系统不可用。
如果是用户空间的进程或线程引起的问题backtrace是不会有内容的,如果内核线程那么在soft lockup消息中会显示出backtrace信息。
3.根据linux内核源码分析错误
根据我们第一部分内核抛出的错误信息和call trace(linux内核的跟踪子系统)来分析产生的具体原因。
首先根据我们的centos版本安装相应的linux内核源码,具体步骤如下:
(1)下载源码的rpm包kernel-2.6.32-220.17.1.el6.src.rpm
(2)安装相应的依赖库,命令:yuminstall rpm-build redhat-rpm-config asciidoc newt-devel
(3)安装源码包:rpm -ikernel-2.6.32-220.17.1.el6.src.rpm
(4)进入建立源码的目录:cd~/rpmbuild/SPECS
(5)建立生成源码目录:rpmbuild-bp --target=`uname -m` kernel.spec
下面开始真正的根据内核bug日志分析源码:
(1)第一阶段内核错误日志分析(时间在Dec 4 14:03:34这个阶段的日志输出代码分析,其实这部分代码不会导致cpu软死锁,主要是第二阶段错误日志显示导致cpu软死锁)
我们首先通过日志定位到相关源代码:看下面日志:Dec 4 14:03:34 BP-YZH-1-xxxx kernel: WARNING: atkernel/trace/ring_buffer.c:1988 rb_reserve_next_event+0x2ce/0x370() (Not tainted)
根据日志内容我们可以很容易的定位到kernel/trace/ring_buffer.c这个文件的1988行代码如下:WARN_ON(1)。
先简单解释一下WARN_ON的作用:WARN_ON只是打印出当前栈信息,不会panic。所以会看到后面有一大堆的栈信息。这个宏定义如下:
#ifndef WARN_ON
#defineWARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
if (unlikely(__ret_warn_on)) \
__WARN(); \
unlikely(__ret_warn_on); \
})
#endif
这个宏很简单保证传递进来的条件值为0或者1(两次逻辑非操作的结果),然后使用分支预测技术(保证执行概率大的分支紧邻上面的指令)判断是否需要调用__WARN()宏定义。如果满足条件执行了__WARN()宏定义也接着执行一条空指令;。上面调用WARN_ON宏是传递的1,所以会执行__WARN()。下面继续看一下__WARN()宏定义如下:
#define __WARN() warn_slowpath_null(__FILE__,__LINE__)
从接下来的call trace信息中我们也确实发现调用了warn_slowpath_null这个函数。通过在linux内核源代码中搜索这个函数的实现,发现在panic.c(内核恐慌时的相关功能实现)中实现如下:
voidwarn_slowpath_null(const char *file, int line)
{
warn_slowpath_common(file, line,__builtin_return_address(0),
TAINT_WARN, NULL);
}
EXPORT_SYMBOL(warn_slowpath_null);//都出这个符号,让其他模块可以使用这个函数
同样的我们看到了warn_slowpath_common这个函数,而在call trace当中这个函数在warn_slowpath_null函数之前打印出来,再次印证了这个流程是正确的。同样在panic.c这个文件中我发现了warn_slowpath_common这个函数的实现如下:
static voidwarn_slowpath_common(const char *file, int line, void *caller,
unsigned taint, struct slowpath_args *args)
{
const char *board;
printk(KERN_WARNING "------------[ cut here]------------\n");
printk(KERN_WARNING "WARNING: at %s:%d %pS()(%s)\n",
file, line, caller, print_tainted());
board = dmi_get_system_info(DMI_PRODUCT_NAME);//得到dmi系统信息
if (board)
printk(KERN_WARNING "Hardware name:%s\n", board);//通过我们的日志信息可以发现我们硬件名称是ProLiant DL360 G7
if (args)
vprintk(args->fmt, args->args);
print_moles();//打印系统模块信息
mp_stack();//mp信息输出(call trace开始)
print_oops_end_marker();//打印oops结束
add_taint(taint);
}
分析这个函数的实现不难发现我们的很多日志信息从这里开始输出,包括打印一些系统信息,就不继续深入分析了(请看代码注释,里面调用相关函数打印对应信息,通过我分析这些函数的实现和我们的日志信息完全能够对应,其中mp_stack是与cpu体系结构相关的,我们的服务器应该是属于x86体系)。这里在继续分析一下mp_stack函数的实现,因为这个是与cpu体系结构相关的,而且这个函数直接反应出导致内核panic的相关进程。这个函数实现如下:
/*
* The architecture-independent mp_stackgenerator
*/
void mp_stack(void)
{
unsigned long stack;
printk("Pid: %d, comm: %.20s %s %s %.*s\n",
current->pid, current->comm,print_tainted(),
init_utsname()->release,
(int
❸ Android-trace分析工具
1.TraceView
官方说明文档:
https://developer.android.google.cn/studio/profile/cpu-profiler
android CPU profiler
CPU profiler可以实时检查应用的CPU使用率和线程activity,并记录函数跟踪,以便于您可以优化和调试您的应用程序.
Flame Chart如果出现问题 颜色也会加深
2.systrace
简介:
systrace是Android4.1版本之后推出的,对系统Performance分析的工具。systrace的功能包括跟踪系统I/O操作,内核工作队列,CPU负载以及Android各个子系统的运行状况等。
主要由三部分构成:
1.内核部分
systrace采用了linux Kernel的ftrace功能,所以如果要使用systrace的话,必须开启Kernel和ftrace相关的模块.
2.数据采集部分
Android中定义了一个trace类,应用程序可以使用该类把统计信息输出给trace,同时,android有一个atrace程序,它可以从ftrace中读取统计信息然后交给数据分析工具来处理.
3.数据分析工具
Android提供一个systrace.py用来配置数据采集的方法(如采集数据的标签,输出文件名等)和收集ftrace统计数据并生成一个结果网页文件供用户查看。
简单的说,当机器以60帧/秒显示,用户会感知机器流畅。如果出现显示时丢帧的情况,就需要知道系统在做什么?Systrace是用来收集系统和应用的数据信息和一些中间生成数据的细节,在Android4.1和4.2系统之后出现。Systrace在分析一些显示问题上特别有用,如应用画图慢,显示动作或者动画时变形。
抓取systrace
进入本地Android/Sdk/platform-tools/systrace目录下,执行python systrace.py view --time = 10
python脚本的option
❹ Linux性能工具(一)ftrace使用
Ftrace设计作为一个内部的tracer提供给系统的开发者和设计者,帮助他们弄清kernel正在发生的行为,它能够调式分析延迟和性能问题。对于前一章节,我们学习了Ftrace发展到现在已经不仅仅是作为一个function tracer了,它实际上成为了一个通用的trace工具的框架。
一方面已经从function tracer扩展到irqsoff tracer、preemptoff tracer;另一方面静态的trace event也成为trace的一个重要组成部分;通过前面两节的学习,我们知道了什么是ftrace,能够解决什么问题,从这章开始我们主要是学习,怎么去使用ftreace解决问题。
ftrace 通过 debugfs 向用户态提供访问接口。配置内核时激活 debugfs 后会创建目录 /sys/kernel/debug ,debugfs 文件系统就是挂载到该目录。要挂载该目录,需要将如下内容添加到 /etc/fstab 文件:
或者可以在运行时挂载:
激活内核对 ftrace 的支持后会在 debugfs 下创建一个 tracing 目录 /sys/kernel/debug/tracing 。该目录下包含了 ftrace的控制和输出文件
其中重点关注以下文件:
查看当前的跟踪器current_tracer ,可以echo选择:
trace使能
tracing_on :是否往循环buffer写跟踪记录,可以echo设置
trace过滤器选择(可选)
trace数据读取
更多linux内核视频教程文档资料免费领取后台私信【 内核 】自行获取。
所以对于ftrace的三步法为:
1.2 function trace实例
function,函数调用追踪器, 跟踪函数调用,默认跟踪所有函数,如果设置set_ftrace_filter, 则跟踪过滤的函数,可以看出哪个函数何时调用。
Disable tracer:
设置 tracer 类型为 function:
set_ftrace_filter 表示要跟踪的函数,这里我们只跟踪 dev_attr_show 函数:
Enable tracer:
提取trace结果:
从上图可以看到 function trace 一个函数的方法基本就是三板斧:
function 跟踪器可以跟踪内核函数的调用情况,可用于调试或者分析 bug ,还可用于了解和观察 Linux 内核的执行过程。同时ftrace允许你对一个特定的进程进行跟踪,在/sys/kernel/debug/tracing目录下,文件set_ftrace_pid的值要更新为你想跟踪的进程的PID。
1.3 function_graph Trace 实例
function_graph 跟踪器则可以提供类似 C 代码的函数调用关系信息。通过写文件 set_graph_function 可以显示指定要生成调用关系的函数,缺省会对所有可跟踪的内核函数生成函数调用关系图。
函数图跟踪器对函数的进入与退出进行跟踪,这对于跟踪它的执行时间很有用。函数执行时间超过10微秒的标记一个“+”号,超过1000微秒的标记为一个“!”号。通过echo function_graph > current_tracer可以启用函数图跟踪器。
与 function tracer 类似,设置 function_graph 的方式如下:
设置 tracer 类型为 function_graph:
set_graph_function 表示要跟踪的函数:
捕捉到的 trace 内容:
我们跟踪的是 __do_fault 函数,但是 function_graph tracer 会跟踪函数内的调用关系和函数执行时间,可以协助我们确定代码执行流程。比如一个函数内部执行了很多函数指针,不能确定到底执行的是什么函数,可以用 function_graph tracer 跟踪一下。
需要注意:
对于不调用其它函数的函数,其对应行以“;”结尾,而且对应的 DURATION 字段给出其运行时长;
对于调用其它函数的函数,则在其“}”对应行给出了运行时长,该时间是一个累加值,包括了其内部调用的函数的执行时长。DURATION 字段给出的时长并不是精确的,它还包含了执行 ftrace 自身的代码所耗费的时间,所以示例中将内部函数时长累加得到的结果会与对应的外围调用函数的执行时长并不一致;不过通过该字段还是可以大致了解函数在时间上的运行开销的。
1.4 wakeup
wakeup tracer追踪普通进程从被唤醒到真正得到执行之间的延迟。
non-RT进程通常看平均延迟。RT进程的最大延迟非常有意义,反应了调度器的性能
trace event 就是利用 ftrace 框架,实现低性能损耗,对执行流无影响的一种信息输出机制。相比 printk,trace event:
2.2 使用实例
上面提到了 function 的 trace,在 ftrace 里面,另外用的多的就是 event 的 trace,我们可以在 events 目录下面看支持那些事件:
上面列出来的都是分组的,我们可以继续深入下去,譬如下面是查看 sched 相关的事件
对于某一个具体的事件,我们也可以查看:
上述目录里面,都有一个 enable 的文件,我们只需要往里面写入 1,就可以开始 trace 这个事件。譬如下面就开始 trace sched_wakeup 这个事件
我们也可以 trace sched 里面的所有事件
查看函数调用栈
查看函数调用栈是内核调试最最基本得需求,常用方法:
trace 函数的时候,设置 echo 1 > options/func_stack_trace 即可在 trace 结果中获取追踪函数的调用栈。
以 dev_attr_show 函数为例,看看 ftrace 如何帮我们获取调用栈:
如何跟踪一个命令,但是这个命令执行时间很短
我们可以设置ftrace过滤器控制相关文件:
如果这时候问:如何跟踪某个进程内核态的某个函数?
答案是肯定的,将被跟踪进程的 pid 设置到 set_event_pid/set_ftrace_pid 文件即可。
但是如果问题变成了,我要调试 kill 的内核执行流程,如何办呢?
因为 kill 运行时间很短,我们不能知道它的 pid,所以就没法过滤了。
调试这种问题的小技巧,即 脚本化,这个技巧在很多地方用到:
如何跟踪过滤多个进程?多个函数?
用法为: echo xxx >> set_ftrace_filter ,例如,先设置 dev_attr_* :
再将 ip_rcv 追加到跟踪函数中:
基于模块过滤
格式为: : : ,例如,过滤 ext3 mole 的 write* 函数:
从过滤列表中删除某个函数,使用“感叹号”
感叹号用来移除某个函数,把上面追加的 ip_rcv 去掉:
我们可以手工操作/sys/kernel/debug/tracing路径下的大量的配置文件接口,来使用ftrace的强大功能。但是这些接口对普通用户来说太多太复杂了,我们可以使用对ftrace功能进行二次封装的一些命令来操作。
trace-cmd就是ftrace封装命令其中的一种。该软件包由两部分组成
下载编译ARM64 trace-cmd方法:
先通过 record 子命令将结果记录到 trace.dat,再通过 report 命令进行结果提取。命令解释:
在很有情况下不能使用函数追踪,需要依赖 事件追踪 的支持,例如:
4.2 kernelshark图形化分析数据
trace-cmd report主要是使用统计的方式来找出热点。如果要看vfs_read()一个具体的调用过程,除了使用上一节的trace-cmd report命令,还可以使用kernelshark图形化的形式来查看,可以在板子上使用trace-cmd record 记录事件,把得到的trace.data放到linux 桌面系统,用kernelshark打开,看到图形化的信息
❺ red hat 内核2.6.32的kernel/fork.c在哪里
装了源码的话,find -name fork.c 找下就知道了
❻ systrace实现原理
systrace是通过atrace和ftrace一起实现。
抓取systrace的adb命令如下:
adb shell atrace -t 8 -z gfx view wm am sched freq input > atrace
python命令:
python systrace.py -b 10240 -t 10 wm am input ss power view freq workq sched idle sync gfx view hal dalvik disk -a com.tencent.mm -o PD1982_weixin.html
systrace抓取实质是通过atrace实现,下面以ATRACE_CALL()为例说明systrace实现
system/core/libutils/include/utils/Trace.h
system/core/libcutils/include/cutils/trace.h
system/core/libcutils/trace-dev.cpp
system/core/libcutils/trace-dev.inc
到这可以看出:
ATRACE_CALL其实就是往atrace_marker_fd写入函数名和进程pid等信息,其中atrace_marker_fd对应“/sys/kernel/debug/tracing/trace_marker”文件
systrace在内核层实质是通过ftrace来实现,systrace的内容是写入内核分配的ringbuffer里面的,开关的实质是disable/enable ringbuffer,ftrace的总开关/sys/kernel/debug/tracing/tracing_on
开关ftrace命令如下:
adb shell echo 1 > /sys/kernel/debug/tracing/tracing_on
adb shell echo 0 > /sys/kernel/debug/tracing/tracing_on
通过tracing_mark_write函数把内容写入ringbuffer
msm-4.19/kernel/trace/trace.c
大致原理参考下图:
ftrace就是function trace的缩写,每个函数的追踪都有一个对应的tracepoint结构来表示,这个结构存放在特殊的section内存中。
msm-4.19/include/linux/tracepoint-defs.h
3.1 tracepoint的probe函数注册
以高通gpu驱动ftrace为例,通过以下命令可以触发tracepoint的probe函数注册
adb shell echo 1 > /sys/kernel/debug/tracing/events/kgsl/enable
msm-4.19/kernel/tracepoint.c
tracepoint的probe函数实质是在下面这个宏里面定义,通过这个函数ftrace往对应的ringbuffer里面写入函数追踪数据
msm-4.19/include/trace/trace_events.h
3.2 probe函数的调用
以高通gpu驱动入列一条绘制命令_queue_drawobj函数为例
msm-4.19/drivers/gpu/msm/adreno_dispatch.c
通过trace_adreno_cmdbatch_queued来追踪_queue_drawobj函数,调用tracepoint的probe函数
接下来看下trace_adreno_cmdbatch_queued的实现
msm-4.19/drivers/gpu/msm/adreno_trace.h
trace_adreno_cmdbatch_queued真正定义在下面这个宏里面
msm-4.19/include/linux/tracepoint.h
最终调用到tracepoint注册的probe函数
msm-4.19/include/linux/tracepoint.h
总结下:Native层调用内核的tracing_mark_write来往ftrace的ringbuffer里面写入数据,而内核函数调用其对应probe函数往ftrace ringbuffer写入数据。