最直接方法是用 perf 成对捕获 syscalls:sysenter 和 syscalls:sysexit 事件计算时间差;bpftrace 更轻量,支持内核态实时统计延迟分布。

Linux 下用 perf 抓取文件 I/O 延迟事件最直接
Linux 内核的 perf 工具能直接跟踪 sys_enter_read、sys_enter_write 及其返回,配合时间戳差值就能算出单次系统调用延迟。不需要自己写内核模块或 hook libc。
常见错误是只用 perf record -e syscalls:sys_enter_read,这只能抓入口,没出口就无法算延迟。必须成对捕获入口和出口事件:
perf record -e 'syscalls:sys_enter_read,syscalls:sys_exit_read,syscalls:sys_enter_write,syscalls:sys_exit_write' -a -g -- sleep 10- 导出为脚本:
perf script > trace.txt,再用 Python 或 awk 解析每对sys_enter_*和紧随其后的sys_exit_*,按 PID + syscall number 匹配,计算exit_time - enter_time - 注意:不同内核版本中事件名可能带
syscalls:sys_enter_read或syscalls:sys_enter_readv等变体,用perf list | grep sys_enter确认可用名
用 bpftrace 实时统计读写延迟分布(推荐)
bpftrace 比 perf script 解析更轻量,适合长期运行监控。它能直接在内核态完成时间差计算和直方图聚合,避免用户态大量日志 IO 拖慢分析本身。
典型场景是想看延迟是否集中在某个区间(比如 99%
- 运行:
bpftrace -e 'kprobe:sys_read { @start[tid] = nsecs; } kretprobe:sys_read /@start[tid]/ { @read_us = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }' - 输出是微秒级延迟直方图,自动分桶;换成
sys_write同理 - 坑点:
kretprobe可能因内核优化被跳过(如函数内联),遇到空直方图先加-d看是否 probe 失败;可改用tracepoint:syscalls:sys_exit_read更稳定 - 不支持 Windows 或 macOS,仅限 Linux 4.15+ 且开启
CONFIG_BPF_SYSCALL=y
C++ 程序里埋点测延迟要绕开 stdio 缓冲干扰
如果只监控自己写的 C++ 程序,用 std::chrono 测 read()/write() 调用耗时最准,但必须确保没被 std::ifstream 或 printf 的缓冲层掩盖真实系统调用行为。
常见错误是测 ofstream ,这根本没触发 write 系统调用,只是拷贝进 FILE* 缓冲区:
- 测真实磁盘 I/O 延迟,必须用
::read(fd, buf, size)和::write(fd, buf, size)(即 unistd.h 的裸系统调用) - 打开文件时加
O_DIRECT(需对齐 buffer 和 offset)可绕过 page cache,反映底层存储真实延迟;但多数场景应保留 cache,否则测的是“冷读”而非业务常态 - 注意
clock_gettime(CLOCK_MONOTONIC, &ts)比std::chrono::steady_clock更低开销,尤其高频采样时
生成性能报告时别忽略上下文关联
单纯输出“平均读延迟 2.3ms”意义有限。真正影响判断的是延迟和什么相关:是特定文件?某个进程?还是某类 I/O size?
容易被忽略的点是缺乏横向维度,导致无法定位根因:
- 在
bpftrace直方图里加pid或comm分组:@read_us[pid, comm] = hist(...) - 记录每次 I/O 的
size参数(从寄存器取),画 “size vs latency” 散点图,常能发现大块写突然变慢(如 ext4 journal 刷盘) - 延迟 spike 期间检查
/proc/diskstats的await和%util,确认是本机磁盘瓶颈,还是 NFS 远端卡顿(此时strace -T显示 write 返回极慢但await正常)
最麻烦的其实是延迟抖动来源混杂:page cache 回收、ext4 barrier、NVMe 队列深度突降、甚至 CPU frequency scaling 都可能让同一操作耗时差 10 倍。抓数据时得同步录下这些指标,不能只盯着 read/write 本身。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











