【问题标题】:how to get disk read/write bytes per second from /proc in programming on linux?如何在Linux上的编程中从/proc获取每秒磁盘读/写字节数?
【发布时间】:2016-09-11 22:47:23
【问题描述】:

目的 :我想获取iostat命令可以获取的信息。

我已经知道,如果打开 /proc/diskstats/sys/block/sdX/stat 有信息:sectors readsectors write。所以如果我想读/写字节/秒,下面的公式是对的吗?

每秒读/写字节数
(扇区读/写(现在)-扇区读/写(最后))*512字节/时间间隔

每秒读取/写入操作数
(读/写IOs(now)+read/write merges(now)-read/write IOs(last)-read/write merges(last))/时间间隔

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

【问题讨论】:

标签: linux profiling disk


【解决方案1】:

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

“磁盘的标准扇区大小为 512 字节已建立....[可疑 – 讨论]” (c) wiki 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,

因此,读取扇区数并除以 2 以获得千字节/秒(似乎 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美国 ibm 的 ricklind 的“I/O 统计字段”

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 时说“为什么 SECTOR_SIZE = 512 在内核中?” (2015):

 #define SECTOR_SHIFT 9

Theodore Ts'o 的消息https://lkml.org/lkml/2015/8/17/269

它是一成不变的。整个内核的地方太多了, 尤其是在大量文件系统中,它们假设 扇区大小为 512 字节。所以在块层之上,扇区大小 永远是 512。

这实际上更好用户空间程序使用 /proc/diskstats,因为它们不需要知道某个特定的 底层硬件使用 512、4k(或者如果 HDD 制造商 幻想变成了真正的 32k 或 64k) 扇区大小。

出于类似的原因,st_blocks 的结构大小总是以 512 为单位 字节。我们不想强迫用户空间必须弄清楚是否 底层文件系统使用 1k、2k 或 4k。是因为 st_blocks 的单位总是 512 字节,这是 在 POSIX 标准中硬编码。

【讨论】:

  • 嗯,为什么 iostat 将值除以 2,而不是相乘 (s_value()/fctr)?
  • @osgx,有 read_sectors 的计数器:例如,1 秒内读取了 54 个扇区,每个扇区 512 个字节。因此,要获得每秒千字节,我们应该将 read_sectors 转换为 read_kilobytes;扇区是 512 字节,千字节是 1024 字节,所以千字节是 2 个扇区长。当我们将 s_value (read_sectors) 除以 2 时,我们将得到每秒 27 KB,因此使用 fctr 是正确的。
  • 这个答案已经得到了如此完整和深刻的回答,我只能放弃我的搜索。谢谢!
  • @MaxCuttins,唯一的问题是 iostat 的 %util 字段。stackoverflow.com/questions/4458183/… 需要更好的答案 - %util 就像至少有一个请求正在进行时块 io 滴答声的百分比( “在飞行中”)。
  • 我使用这个概念写了一个 bash 脚本:github.com/seffparker/nagios-plugins/blob/master/check_iokbps
猜你喜欢
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 2019-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-29
  • 1970-01-01
相关资源
最近更新 更多