ftrace 的 function tracer 不能直接看函数耗时,因其仅记录函数入口时间戳而不记录退出时间,只能反映调用顺序;function_graph tracer 通过记录 entry/exit 时间差提供单次近似耗时,但含子函数且不剔除中断抢占;function_profile_enabled 则统计总驻留时间与调用频次,用于识别高频高占比热点。

ftrace 能直接分析函数执行耗时,但不是靠“测单次时间戳”,而是靠采样统计或调用图推导;真要精确到微秒级单次耗时,得用 function_graph tracer + 手动算差值,或者配合 trace-cmd 导出结构化数据。
为什么 function tracer 不能直接看函数耗时
它只记录函数调用顺序和入口时间戳,不记录退出时间。输出类似:
0) 1.234567: sys_open <-- do_syscall_64
你只能知道 sys_open 是什么时候被调的,但不知道它啥时候返回。所以它适合查“谁调了谁”,不适合查“谁最慢”。
-
function的核心用途是路径分析、调用频次统计(需开启function_profile_enabled) - 若强行用它估算耗时,得配合外部时间戳对齐,误差大、不可靠
- 它默认开销极低,适合长时间开启观察行为模式
用 function_graph 看函数进出与粗略耗时
这个 tracer 会为每个函数记录 entry 和 exit 两行,时间差就是该次调用的近似耗时(含子函数,不含中断延迟)。
- 启用方式:
echo function_graph > current_tracer,再echo 1 > tracing_on - 典型输出:
0) 1.234567: sys_open(<ptr>) 0) 1.234890: <== sys_open
差值 ≈ 323μs —— 这是内核认为该次调用从进到出的时间,已排除部分上下文切换干扰,但不剔除中断抢占。
- 注意:高频率小函数(如
atomic_inc)会被自动过滤,避免日志爆炸;可通过set_ftrace_filter指定目标函数 - 深度过大会撑爆缓冲区,建议先设
max_graph_depth=1缩小范围 - 输出里带缩进,直观反映调用层级,但耗时是累计值(含所有子调用)
定位热点函数:靠 function + function_profile_enabled
这不是实时耗时,而是统计一段时间内各函数被调了多少次、总驻留时间(基于插桩计数器),更适合找“高频+高占比”的热点。
- 先启用函数跟踪:
echo function > current_tracer - 打开性能分析开关:
echo 1 > function_profile_enabled - 跑负载后,读
cat trace_stat/function,输出形如:
schedule 124567 124567000
第二列是调用次数,第三列是总纳秒级驻留时间(注意:非精确执行时间,含调度延迟等)
- 必须确保内核编译时开了
CONFIG_FUNCTION_PROFILER=y,否则该文件不存在 - 结果按总时间倒序排列,一眼看出 top 热点;但无法区分是函数本身慢,还是它调的子函数慢
- 若只想看某几个函数,写入
set_ftrace_filter再开启 profiling,减少干扰
容易被忽略的关键限制
所有 ftrace 耗时类分析都绕不开两个硬约束:
- 时间精度依赖于内核
jiffies或hrtimer,在低负载下可到微秒,高负载时可能抖动达毫秒级 - 函数插桩本身有开销(哪怕只是 nop),开启
function_graph后,内核吞吐量可能下降 10%~30%,不能长期开着压测 -
trace缓冲区默认只有 1MB,函数调用密集时会丢帧;要用buffer_size_kb手动调大,但内存占用同步上升 - 不跟踪 inline 函数、
__always_inline函数,也不跟踪部分 hotpath 上被编译器优化掉的函数调用


















