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

ftrace 能直接分析函数执行耗时,但不是靠“测单次时间戳”,而是靠采样统计或调用图推导;真要精确到微秒级单次耗时,得用 function_graph tracer + 手动算差值,或者配合 trace-cmd 导出结构化数据。
为什么 function tracer 不能直接看函数耗时
它只记录函数调用顺序和入口时间戳,不记录退出时间。输出类似:
0) 1.234567: sys_open <p>你只能知道 <code>sys_open</code> 是什么时候被调的,但不知道它啥时候返回。所以它适合查“谁调了谁”,不适合查“谁最慢”。</p>
-
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: <p>差值 ≈ 323μs —— 这是内核认为该次调用从进到出的时间,已排除部分上下文切换干扰,但不剔除中断抢占。</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill8828" title="Obsidian (Linux)"><img src="https://img.php.cn/upload/skill/000/000/081/179228531040284.jpg" alt="Obsidian (Linux)" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill8828" title="Obsidian (Linux)" class="overflowclass">Obsidian (Linux)</a> <p class="overflowclass">操作 Obsidian 库(纯 Markdown 笔记),并通过 notesmd-cli 实现自动化。</p> </div> <a rel="nofollow" href="/xiazai/skill8828" title="Obsidian (Linux)" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div><ul> <li>注意:高频率小函数(如 <code>atomic_inc</code>)会被自动过滤,避免日志爆炸;可通过 <code>set_ftrace_filter</code> 指定目标函数</li> <li>深度过大会撑爆缓冲区,建议先设 <code>max_graph_depth=1</code> 缩小范围</li> <li>输出里带缩进,直观反映调用层级,但耗时是累计值(含所有子调用)</li> </ul><h3>定位热点函数:靠 <code>function</code> + <code>function_profile_enabled</code> </h3><p>这不是实时耗时,而是统计一段时间内各函数被调了多少次、总驻留时间(基于插桩计数器),更适合找“高频+高占比”的热点。</p><ul> <li>先启用函数跟踪:<code>echo function > current_tracer</code> </li> <li>打开性能分析开关:<code>echo 1 > function_profile_enabled</code> </li> <li>跑负载后,读 <code>cat trace_stat/function</code>,输出形如:</li> </ul><pre class="brush:php;toolbar:false;"> 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 上被编译器优化掉的函数调用










