linux下通过/proc/diskstats获取物理磁盘i/o吞吐量需两次采样第6、10列(读写扇区数)求差,乘512再除以时间间隔得字节/秒;windows则用wmi查询win32_perfformatteddata_perfdisk_physicaldisk的diskreadbytespersec等字段直接获取实时速率。

Linux下用/proc/diskstats解析物理磁盘I/O累计值
Linux内核通过 /proc/diskstats 暴露每块物理磁盘的原始I/O统计,包括读写扇区数、完成次数、毫秒耗时等。它不是实时“负载”(如%util),而是自系统启动以来的**累计计数器**,需两次采样做差值才能算出速率。
关键字段顺序固定(共14列),前3列为:主设备号、次设备号、设备名;第6列是读取完成的扇区总数(sectors_read),第10列是写入完成的扇区总数(sectors_written)。扇区大小通常为512字节,所以吞吐量 = (Δ读扇区 + Δ写扇区) × 512 / 采样间隔(字节/秒)。
- 只解析真实物理磁盘(如
sda、nvme0n1),跳过分区(sda1)、LVM逻辑卷、md设备——它们在/proc/diskstats中虽存在,但数据会重复或失真 - 设备名可能含空格(如
loop0后跟空格),建议按列切分而非简单空格split - 同一磁盘可能有多个条目(如NVMe多命名空间),需按主/次设备号去重,或优先匹配
name == "nvme0n1"这类根设备名
Windows下用WMI查询Win32_PerfFormattedData_PerfDisk_PhysicalDisk
Windows没有类似 /proc/diskstats 的文件接口,必须走WMI。目标类 Win32_PerfFormattedData_PerfDisk_PhysicalDisk 提供的是**已格式化后的性能计数器**,其中 DiskReadBytesPerSec 和 DiskWriteBytesPerSec 是直接可用的实时吞吐率(字节/秒),无需自己差分计算。
注意:该WMI类返回的是“格式化后”数据,值已除以采样周期,且自动处理了计数器回绕。但默认只包含非空闲磁盘实例,Name 字段值为 _Total 或具体磁盘名(如 0 C:),需过滤掉 _Total 才能得到单盘数据。
- 必须链接
ole32.lib和oleaut32.lib,初始化COM和Security(CoInitializeEx+CoSetProxyBlanket)缺一不可,否则查询直接失败 - WMI查询可能阻塞数秒,尤其在磁盘繁忙或远程WMI服务响应慢时,建议设超时(
IWbemContext或手动线程控制) -
DiskReadBytesPerSec值为uint64,但WMI返回的是VARIANT,需检查vt == VT_UI8再取ullVal,否则读到垃圾值
跨平台C++封装要点:避免误把逻辑卷当物理盘
统一获取物理磁盘I/O的前提是准确识别设备类型。Linux下靠 /sys/block/*/device 软链接是否存在来判断是否为真实物理设备(如指向 ../devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0);Windows下则依赖WMI中 Win32_DiskDrive 的 InterfaceType("IDE"/"SCSI"/"NVMe")与 Win32_PerfFormattedData_PerfDisk_PhysicalDisk 的 Name 字段映射。
- 不要依赖
/proc/sys/dev/block下的主次号匹配——它不区分物理盘和RAID阵列 - Linux下若启用device-mapper(如LVM、加密),
/dev/mapper/*设备在/proc/diskstats中有独立条目,但它们是逻辑层,应跳过 - macOS无直接等效接口,
IOKit可查磁盘信息但无累计I/O计数器,只能退回到diskutil iostat解析命令行输出(不推荐用于生产)
采样频率与精度陷阱:别被“实时”二字误导
所谓“实时吞吐负载”,本质是短周期内的平均速率。采样间隔太短(如100ms),噪声大且受单次I/O延迟影响严重;太长(如5s),无法反映突发负载。实际建议1–2秒间隔,连续采样3次取中位数。
更隐蔽的问题是计数器回绕:Linux /proc/diskstats 的扇区计数为unsigned long long,几乎不会溢出;但Windows WMI某些旧版本驱动可能返回32位计数器(DiskReadBytesPerSec 实际是差分值,本身不回绕,但底层原始计数器如 ReadBytes 会)。只要坚持用格式化类(PerfFormattedData),WMI已帮你处理了回绕。
- Linux下两次读取
/proc/diskstats必须确保同一设备行未被内核动态增删(热插拔SSD可能触发),建议先缓存设备列表再逐个读取 - Windows WMI结果中
DiskReadBytesPerSec为0不代表无I/O,可能是采样窗口内恰好无完成操作,需结合AvgDiskQueueLength判断队列积压 - 吞吐量单位始终是字节/秒,别混淆扇区数、KB、MB——尤其Windows WMI文档里写“bytes”,但实测值就是字节,无需再×1024
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











