如何在 linux 上的编程中每秒从 /proc 获取磁盘 read/write 字节?

how to get disk read/write bytes per second from /proc in programming on linux?

目的 :我想得到像iostat这样的信息命令可以得到。

我已经知道如果打开/proc/diskstats/sys/block/sdX/stat有信息说:sectors read and sectors write。所以如果我想得到 read/write bytes/s ,下面的公式是对的 ?

read/write bytes per second:
(sectors read/write(now)-sectors read/write(last))*512 bytes/time interval

read /write operations per second :
(read/write IOs(now)+read/write merges(now)-read/write IOs(last)-read/write merges(last ))/time interval

所以如果我有一个计时器,控制软件每秒从这两个文件中读取信息,然后使用上面的公式计算该值。我能得到正确答案吗?

TLDR扇区为512字节octets;1个扇区为512字节;每个字节为8位;每位为0或1,但不能叠加其中)。

"The standard sector size of 512 bytes for magnetic disks was established ....[dubious – discuss] " (c) 维基 https://en.wikipedia.org/wiki/Disk_sector

如何在 linux 中检查 io 统计信息(在 /proc 中)的扇区大小:

检查 iostat 工具的工作原理(它以 iostat 1 启动时显示每秒千字节数)- 它是 sysstat 包的一部分:

https://github.com/sysstat/sysstat/blob/master/iostat.c

 * Read stats from /proc/diskstats.
void read_diskstats_stat(int curr)
...
        /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */
        i = sscanf(line, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %u %u %u %u",
               &major, &minor, dev_name,
               &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec,
               &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks);

        if (i == 14) {
....
            sdev.rd_sectors = rd_sec_or_wr_ios;
....
            sdev.wr_sectors = wr_sec;
....

 * @fctr    Conversion factor.
...
        if (DISPLAY_KILOBYTES(flags)) {
            printf("    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn\n");
            *fctr = 2;
        }
...
    /*       rrq/s wrq/s   r/s   w/s  rsec  wsec  rqsz  qusz await r_await w_await svctm %util */
    ... 4 columns skipped
    cprintf_f(4, 8, 2,
          S_VALUE(ioj->rd_sectors, ioi->rd_sectors, itv) / fctr,
          S_VALUE(ioj->wr_sectors, ioi->wr_sectors, itv) / fctr,

因此,读取扇区计数并除以二得到 kilobyte/s(好像 1 个扇区读取是 0.5 kb 读取;2 个扇区读取是 1 kb 读取等等)。我们可以得出结论,扇区总是 512 字节。文档中也有说明,不是吗?:

互联网搜索“/proc/diskstats”->

https://www.kernel.org/doc/Documentation/ABI/testing/procfs-diskstats ->

https://www.kernel.org/doc/Documentation/iostats.txt "I/O statistics fields" 来自美国 ibm 的 ricklind

Field  3 -- # of sectors read
    This is the total number of sectors read successfully.

Field  7 -- # of sectors written
    This is the total number of sectors written successfully.

这里没有关于扇区大小的信息(为什么?)。源代码是否是最好的文档(可能是)? /proc/diskstats 的作者在文件 block/genhd.c 的内核源代码中,函数 diskstats_show:

http://lxr.free-electrons.com/source/block/genhd.c?v=4.4#L1149

1170                 seq_printf(seqf, "%4d %7d %s %lu %lu %lu "
1171                            "%u %lu %lu %lu %u %u %u %u\n",
...
1176                            part_stat_read(hd, sectors[READ]),
...
1180                            part_stat_read(hd, sectors[WRITE]),

结构 sectorshttp://lxr.free-electrons.com/source/include/linux/genhd.h?v=4.4#L82

中定义
 82 struct disk_stats {
 83         unsigned long sectors[2];       /* READs and WRITEs */

读取为part_stat_read,写入为__part_stat_add

http://lxr.free-electrons.com/source/include/linux/genhd.h?v=4.4#L307

添加到 sectors 计数器...是...在 http://lxr.free-electrons.com/source/block/blk-core.c?v=4.4#L2264

2264 void blk_account_io_completion(struct request *req, unsigned int bytes)
2265 {
2266         if (blk_do_io_stat(req)) {
2267                 const int rw = rq_data_dir(req);
2268                 struct hd_struct *part;
2269                 int cpu;
2270 
2271                 cpu = part_stat_lock();
2272                 part = req->part;
2273                 part_stat_add(cpu, part, sectors[rw], bytes >> 9);
2274                 part_stat_unlock();
2275         }
2276 }

它使用硬编码“bytes >> 9”根据以字节为单位的请求大小计算扇区大小(为什么要向下舍入??)或者对于人类而言,不是非浮点编译器,它与bytes / 512.

还有 blk_rq_sectors 函数(此处未使用...)从请求中获取扇区计数,这与从字节到扇区的操作相同 >>9 http://lxr.free-electrons.com/source/include/linux/blkdev.h?v=4.4#L853

841 static inline unsigned int blk_rq_bytes(const struct request *rq)
842 {
843         return rq->__data_len;
844 }

853 static inline unsigned int blk_rq_sectors(const struct request *rq)
854 {
855         return blk_rq_bytes(rq) >> 9;
856 }

Linux 中 FS/VFS 子系统的作者在回复 https://lkml.org/lkml/2015/8/17/234 "Why is SECTOR_SIZE = 512 inside kernel ?" (2015) 时说:

 #define SECTOR_SHIFT 9

Theodore Ts'o 的留言 https://lkml.org/lkml/2015/8/17/269

It's cast in stone. There are too many places all over the kernel, especially in a huge number of file systems, which assume that the sector size is 512 bytes. So above the block layer, the sector size is always going to be 512.

This is actually better for user space programs using /proc/diskstats, since they don't need to know whether a particular underlying hardware is using 512, 4k, (or if the HDD manufacturers fantasies become true 32k or 64k) sector sizes.

For similar reason, st_blocks in struct size is always in units of 512 bytes. We don't want to force userspace to have to figure out whether the underlying file system is using 1k, 2k, or 4k. For that reason the units of st_blocks is always going to be 512 bytes, and this is hard-coded in the POSIX standard.