trace_pipe_raw 更适合高吞吐采集,因其跳过内核格式化与字符串拼接,直接输出二进制事件流,避免 sprintf 级开销,cpu 占用低一个数量级,但需按事件边界原子读取并配合用户态解析工具。

trace_pipe_raw 为什么比 trace_pipe 更适合高吞吐采集
因为 trace_pipe_raw 跳过了内核的格式化和字符串拼接,直接输出二进制事件流,避免了每条 trace 都触发 sprintf 级别的开销。在高频事件(如 sched_switch、irq_handler_entry)场景下,trace_pipe 容易成为瓶颈,而 trace_pipe_raw 的 CPU 占用通常低一个数量级。
常见错误现象:cat /sys/kernel/tracing/trace_pipe 在压测时卡住或丢事件,但 cat /sys/kernel/tracing/trace_pipe_raw 仍能稳定读出数据;这是因为前者依赖 trace_event_printk,后者只做 memcpy + ring buffer copy。
- 必须配合用户态解析工具(如
perf script -F或自研 parser),不能直接 human-read -
trace_pipe_raw输出的是 per-CPU 二进制流,头部含struct trace_entry和 event-specific payload,无换行、无时间戳文本 - 若用
dd或head -c截断,可能切在事件中间,导致后续解析错位 —— 必须按完整事件边界读取
ring buffer size 设置不当会直接导致 trace_pipe_raw 丢事件
环形缓冲区大小不是“越大越好”,而是要匹配采集速率与消费速率的差值。默认的 buffer_size_kb(通常 1408 KB)在开启高频事件时几秒就满,一旦 buffer 满且 reader 没及时消费,新事件就会覆盖旧事件 —— trace_pipe_raw 不报错、不阻塞,只静默丢弃。
使用场景:监控 1000+ QPS 的系统调用入口(sys_enter),实测 buffer 需设为 8192 KB 以上才能撑过 30 秒采集窗口。
- 设置方式:
echo 8192 > /sys/kernel/tracing/buffer_size_kb(注意:单位是 KB,不是字节) - 该值对每个启用的 tracer(如 function_graph、event)独立生效,但
trace_pipe_raw读取的是所有启用事件共用的主 buffer - 过大的 buffer 会占用不可交换的内核内存(kmalloc-backed),在内存紧张机器上可能触发 OOM killer
- 可通过
cat /sys/kernel/tracing/buffer_total_size_kb查看当前总占用(含 per-CPU 备份)
如何安全读取 trace_pipe_raw 并避免解析错位
直接 cat 或 dd bs=1 会破坏事件结构,必须按事件长度原子读取。Linux 内核在 trace_pipe_raw 中每个事件前写入 struct trace_entry(固定 12 字节),其中 size 字段标明整条事件长度(含 header)。
示例关键逻辑(C 伪代码):
while (read(fd, &entry, sizeof(entry)) == sizeof(entry)) {
int len = entry.size;
uint8_t *buf = malloc(len);
if (read(fd, buf, len) != len) break; // 必须一次读完
parse_event(buf); // 自定义解析
free(buf);
}
- 不能用 stdio 缓冲(如
fread),必须用read()系统调用直通 fd - 务必检查每次
read()返回值是否等于预期长度,否则说明 buffer 已被覆盖或 reader 落后太多 -
trace_pipe_raw是阻塞式 fd,但 buffer 满时新事件会覆盖旧事件 —— 所以“阻塞”不等于“安全”,仍需监控丢弃计数 - 丢弃计数路径:
/sys/kernel/tracing/trace_buffer_overrun(全局)或 per-CPU 的/sys/kernel/tracing/per_cpu/cpu*/trace_buffer_overrun
function graph tracer 开启后对 trace_pipe_raw 的影响
启用 function_graph 会显著增加 ring buffer 压力:每个函数进出各记一条事件,且 payload 更大(含 call depth、parent ip 等)。此时即使 buffer_size_kb 相同,trace_pipe_raw 的丢事件概率也会飙升。
性能影响:在 4GHz CPU 上,function_graph 可使单核额外增加 5–15% 的开销,远高于普通 event tracer;其二进制格式也更复杂(含 struct ftrace_graph_ent / struct ftrace_graph_ret 两种 header)。
- 开启方式:
echo function_graph > /sys/kernel/tracing/current_tracer,之后再 echo event 名到set_event - 务必先调大 buffer(建议 ≥16384 KB),并优先关闭非必要函数(
echo ':mod:ext4' > /sys/kernel/tracing/set_ftrace_filter) -
trace_pipe_raw中的 function graph 事件无法用perf script直接解析,需用 kernel source 中的scripts/ftrace/ftrace-to-dot.pl或自研 parser - 如果只要函数调用关系图,不如用
perf record -e 'ftrace:function',它底层也走类似路径但封装了 buffer 管理
真正难的是平衡:buffer 太小,丢事件;太大,吃内存又拖慢系统;不用 trace_pipe_raw,开销压不住;用了,又得自己啃二进制格式和边界对齐。没人替你扛这些细节。










