linux下解析实时i/o吞吐量需轮询/proc/diskstats计算扇区差值(512字节/扇区),结合major:minor匹配设备并区分物理盘;windows需用pdh api采集physicaldisk(*)disk bytes/sec计数器,两次调用取差值,注意通配符与large_integer接收。

Linux下用/proc/diskstats解析实时I/O吞吐量
Linux没有“实时吞吐负载明细”的现成API,最可靠方式是轮询/proc/diskstats并计算差值。该文件每行对应一个磁盘或分区,字段含义固定(第1、2、3列是主/次设备号,第4列是设备名,第6列是读取完成次数,第7列是读取扇区数,第10列是写入扇区数,第11列是写入完成次数)。注意:扇区大小默认为512字节,不是1KB。
- 每次读取后需至少间隔1秒再读一次,否则差值可能为0或失真
- 不要直接信任
dev/sda这类名字——同一设备重启后可能变成sdb,应结合/sys/block/*/dev或major:minor匹配设备 - 若要区分物理盘(排除LVM/RAID虚拟层),优先读
/sys/block/*/device/model和/sys/block/*/device/vendor,跳过含dm-、md、nvme命名但实际是NVMe命名规范的例外情况
Windows上用PdhAddCounter采集PhysicalDisk% Disk Read Time等计数器
Windows不暴露原始I/O字节数,只能通过PDH(Performance Data Helper)API获取性能计数器。关键点在于:必须用\PhysicalDisk(*)\% Disk Read Time这种带通配符的路径,否则会漏掉多盘系统;且首次调用PdhCollectQueryData返回的是初始快照,需两次调用+时间差才能算出速率。
-
PhysicalDiskDisk Bytes/sec才是吞吐量(单位字节/秒),但该计数器在某些旧版系统中可能不可用,需先用PdhEnumObjectItems确认存在 - 计数器名称里的
(*)不能省略,否则只返回“_Total”,无法区分单个物理盘 - 调用
PdhGetFormattedCounterValue时,PDH_FMT_LARGE必须配合LARGE_INTEGER接收,否则高位截断导致数值错误
C++跨平台封装的关键陷阱:不要依赖std::filesystem枚举磁盘
std::filesystem::filesystem::space只返回总/可用空间,完全不提供I/O负载信息;而std::filesystem::directory_iterator遍历/dev或\.路径,既无权限又无意义——这些路径下文件节点不代表物理设备,更不反映实时IO状态。
- Linux下真正设备节点在
/sys/block/,不在/dev/;Windows下物理盘由SetupDiEnumDeviceInterfaces枚举GUID_DEVINTERFACE_DISK获得,而非靠路径字符串猜测 - 试图用
statvfs或GetDiskFreeSpaceEx反推吞吐量,结果必然是零——它们是静态容量信息,和I/O速率无关 - 第三方库如
libstatgrab或psutil绑定Python,C++项目集成成本高,且底层仍是调用上述系统接口,不如自己精简实现
吞吐量单位换算与采样频率的实际影响
吞吐量数值本身没意义,关键在采样窗口。例如:1秒内读取1048576扇区(512B/扇区),即512MB/s;但若采样间隔为500ms,差值可能剧烈抖动,尤其在SSD随机小IO场景下。真实负载要看连续多个周期的移动平均,而非单次差值。
- Linux下
/proc/diskstats的第7/10列是累计扇区数,溢出为unsigned long long,32位系统需特别注意——现代内核已基本淘汰32位,但仍需检查编译目标 - Windows PDH计数器默认刷新间隔是1秒,但
PdhSetQueryTimeRange设为更短间隔无效;低于1秒的采样无实际增益,反而增加CPU开销 - 显示时建议统一转为MB/s(除以1024/1024),避免混淆KiB/s与KB/s;注意有些监控工具用1000进制,而操作系统内核用1024进制,差约2.4%
物理磁盘I/O明细从来不是“查一个函数就完事”的事情,它本质是定时采样+设备识别+单位校准的组合动作。最容易被忽略的是设备动态重命名和扇区单位隐式转换——这两点一旦出错,数字看着漂亮,实际和真实负载偏差十倍以上。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











