作者: 朱辉 (茶水)
朱辉, 个人主页 http://teawater.github.io/, 微信公众号茶水侃山 (cschatcs).
做过几年模拟器, 做过几年 GDB, 在小米电视做过几年 Linux 内核优化, 主要围绕 MM.
现在在 HyperHQ 当软件工程师.
更新记录
2017.12.15:
对扩展文章的问题描述进行了精确化.
2017.12.10:
根据张骁和宋宝华老师的建议, 将结尾的错误进行了修正.
增加了对 CPU 负载均衡问题的讲解.
之前在我热爱的公众号 Linux 阅码场看到 The precise meaning of I/O wait time in Linux 这篇文章, 感觉写的不错, 就是没有落实到源码上感觉稍微有点晦涩, 于是自己读了一下代码.
当 task 发生 iowait 的时候, 内核对他们的处理方法是将 task 切换出去, 让可运行的 task 先运行, 而在切换出去前, 会将其 in_iowait 设置为 1, 再次被唤醒的时候 in_iowait 被设置为原值. 相关函数 io_schedule,io_schedule_timeout,mutex_lock_io,mutex_lock_io_nested.
例如:
由此可见 in_iowait 表明了这个 task 是否在 iowait.
另外要注意的是, 这几个切换函数除了 mutex_lock_io,mutex_lock_io_nested 会设置 task 运行状态为 TASK_UNINTERRUPTIBLE 外, 内核在调用 io_schedule,io_schedule_timeout 前都会设置 task 运行状态 TASK_UNINTERRUPTIBLE.
在进程切换函数__schedule 在切换 task 的时候, 如果被切换出的 task 的 in_iowait 为真, 则会对这个 CPU 的运行队列 rq 结构中的 nr_iowait 加 1.
因为前面对 task 已经被设置为 TASK_UNINTERRUPTIBLE, 则 task 需要被唤醒, 对 nr_iowait 的减少操作也是在 task 唤醒函数来做的.
由此可见 nr_iowait 可以表明某 CPU 上是否有 task 在 iowait, 以及数量.
因为处于 iowait 的 task 是 TASK_UNINTERRUPTIBLE 状态, 其并不在就绪队列中, 所以其也没有被 CPU 负载均衡到其他 CPU 的可能, 所以 nr_iowait 也不需要处理负载均衡问题.
当累加系统 idle 时间的时候, 如果 CPU 的 nr_iowait 为真, 也就是当前这个 CPU 有 task 在等待 iowait, 则记录为 iowait 时间.
在打开 NO_HZ 的内核中, 相关代码在 update_ts_time_stats.
而没打开的则在 account_idle_time.
当相关 / proc/stat 接口被访问时, get_iowait_time 就会访问这个时间并返回.
综上所述, iowait 时间就是 CPU idle 时间, 但是这时候 CPU 上不是完全没 TASK 需要运行, 而是休眠的 task 中有一个或者若干个是 iowait 的 task.
当然 idle 和 iowait 的时候 CPU 上还有 idle task.
- + wait_event_interruptible_hrtimeout(ctx->wait,
- + aio_read_events(ctx, min_nr, nr, event, &ret), until);
- hrtimer_start_range_ns(&__t.timer, timeout,\
- current->timer_slack_ns,\
- HRTIMER_MODE_REL);\
- - wait_event_interruptible_hrtimeout(ctx->wait,
- - aio_read_events(ctx, min_nr, nr, event, &ret), until);
- + if (until.tv64 == 0)
- + aio_read_events(ctx, min_nr, nr, event, &ret);
- + else
- + wait_event_interruptible_hrtimeout(ctx->wait,
- + aio_read_events(ctx, min_nr, nr, event, &ret),
- + until);
来源: https://www.cnblogs.com/linuxdev/p/11913882.html