Linux下最可靠方式是两次采样/proc/diskstats取差值再除以时间间隔,第6、10列扇区数乘512换算为字节,优先匹配主设备行(minor=0),间隔≥100ms以避免噪声。

Linux 下用 /proc/diskstats 解析实时 I/O 吞吐量最可靠
直接读取 /proc/diskstats 是 Linux 上获取物理磁盘(非设备映射层)真实吞吐量的首选方式,它绕过内核缓存统计偏差,提供每秒扇区读/写数,换算成字节后即为真实物理 I/O。注意:这里必须过滤掉逻辑设备(如 dm-0、loop0),只保留真实块设备(如 sda、nvme0n1)。
常见错误是误读 /sys/class/block/*/stat —— 它和 /proc/diskstats 数据源一致,但字段顺序与文档不一致,且部分内核版本存在字段偏移;而 iostat 默认显示的是“请求速率”,不是物理吞吐量,且含缓存影响。
- 解析时跳过前 3 列(主次设备号、设备名),第 6 列是累计读取扇区数(
sectors_read),第 10 列是累计写入扇区数(sectors_written) - 扇区大小固定为 512 字节(即使逻辑扇区是 4K,
/proc/diskstats仍以 512 字节为单位计数) - 两次采样间隔建议 ≥ 100ms,太短会导致浮点除零或抖动过大;间隔太长则丢失瞬态峰值
- 示例片段:
std::ifstream f("/proc/diskstats"); std::string line; while (std::getline(f, line)) { std::istringstream iss(line); std::string name; int major, minor; uint64_t rd_sect, wr_sect; iss >> major >> minor >> name >> std::skipws >> rd_sect >> wr_sect; if (name == "sda") { /* 处理 sda 的 rd_sect/wr_sect */ } }
Windows 上必须用 PDH 查询 PhysicalDiskDisk Bytes/sec 计数器
Windows 没有类 Unix 的伪文件系统接口,GetDiskFreeSpaceEx 或 IOCTL_STORAGE_QUERY_PROPERTY 都不提供实时吞吐数据。唯一稳定方案是 Windows 性能计数器(PDH),其中 PhysicalDiskDisk Bytes/sec 直接对应物理磁盘每秒字节数,且区分 _Total 和具体实例(如 0 C:)。
容易踩的坑:使用 QueryPerformanceCounter + FILE_IO_COUNTERS 只能拿到进程级 I/O,不是系统级物理吞吐;WMI 查询 Win32_PerfFormattedData_PerfDisk_PhysicalDisk 延迟高、开销大,且默认采样周期为 1 秒,无法满足“实时”要求。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 必须调用
PdhAddCounter显式添加\PhysicalDisk(0 C:)\Disk Bytes/sec类型路径,不能依赖通配符自动枚举 - 首次调用
PdhCollectQueryData返回PDH_INVALID_DATA是正常现象,需等待至少一次完整采样周期(约 100–200ms)后再读值 - 计数器返回值是
PDH_FMT_DOUBLE类型,需用PdhGetFormattedCounterValue转换,不能直接 reinterpret_cast - 实例名需从
PdhEnumObjectItems获取,不能硬编码0 C:—— RAID 卡或 NVMe 可能暴露多个实例(如0 D:、1 C:)
跨平台封装要注意设备名映射和采样同步问题
同一块 SSD 在 Linux 是 nvme0n1,在 Windows 是 0 C:,没有通用命名规则。若想统一监控逻辑盘(如挂载点 /mnt/data 对应 Windows 的 D:),必须先做设备绑定:Linux 查 /sys/block/nvme0n1/dm/name 或 lsblk -no PKNAME,MOUNTPOINT;Windows 查 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 获取卷到物理磁盘的映射。
另一个关键点是采样时间对齐:两次 /proc/diskstats 读取之间,若被调度延迟或发生 page fault,会导致吞吐计算失真。建议用 clock_gettime(CLOCK_MONOTONIC, ...)(Linux)或 QueryPerformanceCounter(Windows)记录精确时间戳,而非依赖 sleep。
- 避免在循环中反复 fopen/fclose
/proc/diskstats—— 文件描述符复用更高效,且内核保证该文件读取原子性 - Windows PDH 查询失败常见原因是权限不足(需管理员运行)或服务未启动(
winmgmt服务状态不影响 PDH,但Performance Logs and Alerts服务需启用) - 不要用 C++ 标准库
std::chrono做跨平台时间差计算:Windows 上steady_clock可能回退,Linux 上high_resolution_clock不一定等于CLOCK_MONOTONIC
实际部署时,物理磁盘识别比吞吐计算更易出错——NVMe 设备可能被 udev 规则重命名,RAID 卡虚拟盘在 Windows 中可能显示为 Intel RST Controller 实例,这些都需要运行时探测,而不是靠配置文件硬编码。

















