Steins;Lab

  • 项目
  • 折腾
  • 笔记
  • 图册
  • 杂谈
  • 文章索引 - 博主自荐博文
  • 关于/留言
Steins;Lab
某团的自留研究所
  1. 首页
  2. 学习笔记
  3. 正文

iowait 到底是什么?

2023年9月4日 7284点热度 3人点赞 3条评论

本文中,我们将探究 Linux 中 cpu 使用率 iowait 定义和计算方式。iowait 很高的系统,一定存在 IO 瓶颈吗?通过实验验证和讨论了综合观测系统的 IO 压力的方式。

Table of Contents

  • 0 tl;dr
  • 1 引入和问题
  • 2 iowait
    • 2.1 CPU 使用率
    • 2.2 iowait 的来源和定义
    • 2.3 iowait linux 源码小探
      • a. stat 系统文件
      • b. tick_sched 结构体
      • c. 通过 cpu 调度器 runqueue 信息判断 iowait 状态
  • 3实验
    • 3.1 试着让 iowait 逼近 100%!
    • 3.2 高 io 压力,但系统 iowait 很小
  • 4 综合观测系统 IO 压力
  • 5 小结

0 tl;dr

  1. iowait% 是 CPU 空闲且有 disk I/O 任务 所占的时间比例。
  2. cpu 处于 iowait 状态时,仍然可以处理其他计算密集型任务。
  3. iowait 高,反映有大量 cpu 空闲时间在等待 IO。
  4. 如果有 IO 密集型和计算密集型任务同时存在在系统中,iowait 可能很低。
  5. 系统的 IO 瓶颈,需要结合其他工具 (比如 iostat) 综合判断。

1 引入和问题

在定位性能瓶颈时,我们首先会看的状态便是 cpu 使用率(user, system, iowait, idle)。

按照经验,iowait 很高的系统,很可能存在 IO 瓶颈。但

  • iowait 究竟是怎么计算得来的?
  • 一个存在 IO 瓶颈的系统,iowait 一定很高吗?
  • 反过来讲,iowait 很高,系统一定不健康吗?

2 iowait

2.1 CPU 使用率

我们可以通过系统工具的手册查看具体 cpu 使用定义。
man top

    us, user    : time running un-niced user processes
    sy, system  : time running kernel processes
    ni, nice    : time running niced user processes
    id, idle    : time spent in the kernel idle handler
    wa, IO-wait : time waiting for I/O completion
    hi : time spent servicing hardware interrupts
    si : time spent servicing software interrupts
    st : time stolen from this vm by the hypervisor

iowait 代表的是用于等待 I/O 完成的时间。
似乎没有解释明白。

man sar

    %user
            Percentage of CPU utilization that occurred while executing at the user level (application). Note that this field includes time spent running virtual processors.

    %usr
            Percentage of CPU utilization that occurred while executing at the user level (application). Note that this field does NOT include time spent running virtual processors.

    %nice
            Percentage of CPU utilization that occurred while executing at the user level with nice priority.

    %system
            Percentage of CPU utilization that occurred while executing at the system level (kernel). Note that this field includes time spent servicing hardware and software interrupts.

    %sys
            Percentage of CPU utilization that occurred while executing at the system level (kernel). Note that this field does NOT include time spent servicing hardware or software interrupts.

    %iowait
            Percentage of time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request.

......

sar 明确指出,iowait 是 CPU 空闲且有 disk I/O 任务 所占的时间比例。

这意味在 cpu 处于 iowait 状态时,仍然可以被调度其他进程。

2.2 iowait 的来源和定义

我们使用的性能工具一般是通过读取系统状态文件获得的。CPU 原始信息可以查看系统文件 cat /proc/stat 获得。

cpu  71312 7195 54602 378230 320199 0 61952 0 0 0
cpu0 19890 1985 15222 92986 91033 0 177 0 0 0
cpu1 11611 1584 10664 91301 53700 0 60426 0 0 0
cpu2 20344 1776 13989 90313 95029 0 92 0 0 0
cpu3 19466 1849 14727 103627 80436 0 1256 0 0 0
......

通过阅读 proc 手册可以清晰地得到各列的定义:
man proc

/proc/stat
        kernel/system statistics.  Varies with architecture.  Common entries include:

        cpu 10132153 290696 3084719 46828483 16683 0 25195 0 175628 0
        cpu0 1393280 32966 572056 13343292 6130 0 17875 0 23933 0
                The amount of time, measured in units of USER_HZ (1/100ths of a second on most architectures, use sysconf(_SC_CLK_TCK) to obtain the right value), that the system ("cpu" line) or the specific  CPU
                ("cpuN" line) spent in various states:

                user   (1) Time spent in user mode.

                nice   (2) Time spent in user mode with low priority (nice).

                system (3) Time spent in system mode.

                idle   (4) Time spent in the idle task.  This value should be USER_HZ times the second entry in the /proc/uptime pseudo-file.

                iowait (since Linux 2.5.41)
                    (5) Time waiting for I/O to complete.  This value is not reliable, for the following reasons:

                    1. The  CPU will not wait for I/O to complete; iowait is the time that a task is waiting for I/O to complete.  When a CPU goes into idle state for outstanding task I/O, another task will be
                        scheduled on this CPU.

                    2. On a multi-core CPU, the task waiting for I/O to complete is not running on any CPU, so the iowait of each CPU is difficult to calculate.

                    3. The value in this field may decrease in certain conditions.

没有想到,我们关于 iowait 的疑惑可以轻轻松松通过系统手册获得解答:

  1. CPU 不会等待 IO 完成,iowait 是某个 task 等待 IO 完成的时间。
  2. 当一个 cpu 因为显著的 task I/O 进入空闲状态时,另一个 task 可以被调度到它。
  3. 在多核系统中,因为等待 IO 的 task 不在任何 cpu 上运行,所以每个核心精确的 iowait 难以被计算。

2.3 iowait linux 源码小探

为了验证我们的想法,根据 /proc/stat 系统文件实现,我们反向追踪 linux 内核是如何记录 iowait 状态的。

注:本文跟踪的内核版本是 v6.5.1。

a. stat 系统文件

stat 系统文件实现在 linux/fs/proc/stat.c。通过 get_iowait_time 获取并打印。
值得注意的是,实现中基本将 idle_time 和 iowait_time 做了相似的处理。

    for_each_online_cpu(i) {
        struct kernel_cpustat kcpustat;
        u64 *cpustat = kcpustat.cpustat;

        kcpustat_cpu_fetch(&kcpustat, i);

        /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
        user        = cpustat[CPUTIME_USER];
        nice        = cpustat[CPUTIME_NICE];
        system      = cpustat[CPUTIME_SYSTEM];
        idle        = get_idle_time(&kcpustat, i);
        iowait      = get_iowait_time(&kcpustat, i);
        irq     = cpustat[CPUTIME_IRQ];
        softirq     = cpustat[CPUTIME_SOFTIRQ];
        steal       = cpustat[CPUTIME_STEAL];
        guest       = cpustat[CPUTIME_GUEST];
        guest_nice  = cpustat[CPUTIME_GUEST_NICE];
        seq_printf(p, "cpu%d", i);
        seq_put_decimal_ull(p, " ", nsec_to_clock_t(user));
        //...
        seq_putc(p, '\n');
    }

b. tick_sched 结构体

从 tick_sched 计时结构体中获得 iowait 时间。结构体如下
linux/kernel/time/tick-sched.h

    /**
    * struct tick_sched - sched tick emulation and no idle tick control/stats
    *
    * @inidle:      Indicator that the CPU is in the tick idle mode
    ......
    * @idle_sleeptime:  Sum of the time slept in idle with sched tick stopped
    * @iowait_sleeptime:    Sum of the time slept in idle with sched tick stopped, with IO outstanding
    ......
    */
    struct tick_sched {
        /* Common flags */
        unsigned int            inidle      : 1;

        ......

        /* Idle exit */
        ktime_t             idle_exittime;
        ktime_t             idle_sleeptime;
        ktime_t             iowait_sleeptime;

        ......
    };

c. 通过 cpu 调度器 runqueue 信息判断 iowait 状态

idle_sleeptime 和 iowait_sleeptime 由内核计算。
判断一个 cpu 核心空闲时,在不在 iowait 状态,可通过 rq->nr_iowait > 0 判断。

kernel/sched/cputime.c

    void account_idle_time(u64 cputime)
    {
        u64 *cpustat = kcpustat_this_cpu->cpustat;
        struct rq *rq = this_rq();

        if (atomic_read(&rq->nr_iowait) > 0)
            cpustat[CPUTIME_IOWAIT] += cputime;
        else
            cpustat[CPUTIME_IDLE] += cputime;
    }

其中,rq 为每个 CPU 的 runqueue 数据结构。
runqueue 部分组成如下,包含很多的计数变量。(nr_iowait: number of iowait)

kernel/sched/sched.h

    /*
    * This is the main, per-CPU runqueue data structure.
    ......
    */
    struct rq {
        /* runqueue lock: */
        raw_spinlock_t      __lock;
        ......
        unsigned int        nr_running;
        ......
        u64         nr_switches;
        ......
        unsigned int        nr_uninterruptible;
        ......
        atomic_t        nr_iowait;
        ....
    };

其中 nr_iowait 在调度器调度 task 时候更新。每次更新也会更新 IO 延迟状态信息 delayacct_blkio_start,可用于分析进程的 io 负载。

    if (p->in_iowait) {
        delayacct_blkio_end(p);
        atomic_dec(&task_rq(p)->nr_iowait);
    }
    ......
    if (prev->in_iowait) {
        atomic_inc(&rq->nr_iowait);
        delayacct_blkio_start();
    }

通过翻阅源码,我们可以得知,iowait 基本上是一种 CPU 空闲的状态。

3实验

3.1 试着让 iowait 逼近 100%!

目标:尝试让你的系统 iowait 接近 100%!
根据我们上面的分析,只需要在一个空闲的系统中,堆满重度 IO 任务即可。
笔者使用的一个 4 核心的 x86 机器,启动了 6 个重度 IO 任务:

dd if=/dev/sde1 of=/dev/null bs=1MB

sde1 是我的一块机械硬盘,它的速度足够慢。

启动 6 个 io 任务后,查看系统 cpu 使用情况:

mpstat -P ALL 5 # 每 5 秒输出

可以看到,系统 iowait 达到了 87%, idle 状态基本不存在。

因为 sde1 并不是系统盘,现在系统响应未感到卡顿。

这里的高 iowait,更意味着现在系统有大量 cpu 空闲时间在等待 IO。可以和 cpu 密集型应用混布,或尝试优化高 iowait 程序。

3.2 高 io 压力,但系统 iowait 很小

在 3.1 的基础上,我们添加计算密集型任务:

stress --cpu 4 --timeout 600  # 计算密集型压力,压测 4 核心

我们成功抢走了 cpu 的 iowait 时间,cpu 时间大部分集中在计算密集型任务上。
但同时,sde 仍然在机械硬盘的 IO 瓶颈上。

➜  ~ iostat -s 4 -h   # 每 4 秒输出 io 状态          
Linux 6.2.0-31-generic (pi-HP-t610)     2023年09月03日     _x86_64_    (4 CPU)
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          93.1%    0.4%    6.6%    0.0%    0.0%    0.0%

      tps    kB_read/s     kB_w+d/s    kB_read     kB_w+d Device
   666.75        81.4M         0.0k     325.7M       0.0k sde

这意味着,我们需要综合判断系统是否存在 IO 瓶颈。
一个高负载的 IO 系统,可能并不会体现出高 iowait。

4 综合观测系统 IO 压力

综上,实际排查 IO 瓶颈时,还要结合多种工具判断。比如 iostat, iotop。

iostat -c -h -d -x 2 #显示 CPU 和磁盘使用情况,每 2 秒刷新

笔者会再写一篇文章,分享自己用过的一些工具。

5 小结

  1. iowait 是 CPU 空闲且有 disk I/O 任务 所占的时间比例。
  2. cpu 处于 iowait 状态时,仍然可以处理其他计算密集型任务。
  3. iowait 高,反映有大量 cpu 空闲时间在等待 IO。
  4. 如果有 IO 密集型和计算密集型任务同时存在在系统中,iowait 可能很低。
  5. 系统的 IO 瓶颈,需要结合其他工具 (比如 iostat) 综合判断

相关

标签: Linux
最后更新:2023年9月4日

SPtuan

SPtuan 是一名普通的工程师,最大的愿望是度过平静的时光。 当前从事网络/CDN/对象存储研发。

点赞
< 上一篇
下一篇 >
0 0 votes
文章评分
Subscribe
Login
提醒
guest

guest

3 评论
最新
最旧 得票最多
Inline Feedbacks
View all comments
William Lui
William Lui
1 年 之前

我的理解是:
IOWait 高, 說明 IO 一定繁忙, 但是IOwait 低, IO 可能繁忙或者不繁忙.

理由:
從proc的手冊上看, 1,2,3點理由, 都在說少算了CPU在等待 IO 完成的 idle 時間.

這是我的理解,請多多指教.

0
回复
fandy
fandy
1 年 之前

居然还在坚持更新网站,太牛了,佩服这种持续学习的能力w

0
回复
SPtuan
SPtuan
作者
Reply to  fandy
1 年 之前

@fandy 感谢夸夸

0
回复

SPtuan

SPtuan 是一名普通的工程师,最大的愿望是度过平静的时光。
当前从事网络/CDN/对象存储研发。

  • 0 tl;dr
  • 1 引入和问题
  • 2 iowait
    • 2.1 CPU 使用率
    • 2.2 iowait 的来源和定义
    • 2.3 iowait linux 源码小探
      • a. stat 系统文件
      • b. tick_sched 结构体
      • c. 通过 cpu 调度器 runqueue 信息判断 iowait 状态
  • 3实验
    • 3.1 试着让 iowait 逼近 100%!
    • 3.2 高 io 压力,但系统 iowait 很小
  • 4 综合观测系统 IO 压力
  • 5 小结
分类
  • Uncategorized
  • 图册
  • 学习笔记
  • 库
  • 折腾
  • 杂谈
  • 瞎**扯
  • 碎碎念
  • 项目跟踪
最近评论
SPtuan 发布于 2 个月前(03月22日) 书签: 关于 disk-io 的经验, 异步/同步 io 系统设计的经验 https://you...
SPtuan 发布于 2 个月前(03月21日) 如果公司不是对外提供这些服务的,这种岗位都是 infra 部门,平均年龄确实会大一些。尤其构建和维护...
HUA 发布于 2 个月前(03月19日) 想请问博主对于国内CDN行业,以及CDN调度、DNS托管类服务相关岗位的看法,以及是否还推荐校招新人...
SPtuan 发布于 3 个月前(02月03日) 2025 注: 长辈对于只身去深圳的担忧,更多地来自于 80s/90s 治安情况。近几年了解了严打...
SPtuan 发布于 4 个月前(01月16日) 哈哈,100就100吧,新年快乐!
热门主题 & 页面
  • 全球互联网拓扑探索 (1) : 互联网是如何工作的
  • 使用 WSL2 + X11 转发 - 在 Windows10 中打造 GNU/Linux 学习生产环境
  • 动手做!基于nRF24L01P的Arduino无线通信
  • [实验]VPS搭建ss服务中转实现纯ipv6访问网络-校园网免流量
  • PYNQ上手体验:以目标检测应用为例
归档
  • 2025 年 5 月
  • 2025 年 3 月
  • 2024 年 12 月
  • 2024 年 9 月
  • 2024 年 8 月
  • 2024 年 5 月
  • 2024 年 3 月
  • 2024 年 2 月
  • 2023 年 12 月
  • 2023 年 11 月
  • 2023 年 9 月
  • 2023 年 8 月
  • 2023 年 4 月
  • 2023 年 1 月
  • 2022 年 12 月
  • 2022 年 10 月
  • 2022 年 9 月
  • 2022 年 7 月
  • 2022 年 6 月
  • 2022 年 2 月
  • 2021 年 12 月
  • 2021 年 11 月
  • 2021 年 2 月
  • 2021 年 1 月
  • 2020 年 9 月
  • 2020 年 4 月
  • 2020 年 3 月
  • 2020 年 1 月
  • 2019 年 8 月
  • 2019 年 7 月
  • 2019 年 5 月
  • 2019 年 4 月
  • 2019 年 3 月
  • 2019 年 2 月
  • 2018 年 12 月
  • 2018 年 10 月
  • 2018 年 9 月
  • 2018 年 8 月
  • 2018 年 5 月
  • 2018 年 2 月
  • 2018 年 1 月
  • 2017 年 11 月
  • 2017 年 9 月
  • 2017 年 7 月
  • 2017 年 6 月
  • 2017 年 5 月
  • 2017 年 4 月
  • 2017 年 3 月
  • 2017 年 2 月
  • 2017 年 1 月
  • 2016 年 12 月
  • 2016 年 11 月
  • 2016 年 10 月
  • 2016 年 9 月
  • 2016 年 8 月
  • 2016 年 7 月
  • 2016 年 6 月
  • 2016 年 5 月
  • 2016 年 4 月
  • 2016 年 3 月
  • 2016 年 2 月
  • 2016 年 1 月
  • 2015 年 12 月
  • 2015 年 11 月
  • 2015 年 9 月

友情链接:

Blessing Studio hahaschool 绘枫和畅 魔法少女Fandy monsterx Clarke的博客 Luminous’ Home Shintaku's Blog
蓝黑的博客 haruhi.club Yida的博客 Bo2SS 涛叔 TangBao 同和君Hocassian

Steins;Lab 团子神社 zdfmc.net

steinslab.io built with ❤. Thanks for all 2015-2025.

Theme Kratos Made By Seaton Jiang

wpDiscuz