深入剖析Perfetto性能优化之睡眠sleep的几个状态

Perfetto中认识sleep的几个状态

最普通的sleep
在这里插入图片描述
State为Uninterruptible Sleep(non io)

在这里插入图片描述
State为Uninterruptible Sleep
在这里插入图片描述

D 状态 vs S 状态的差别

**S 状态(Interruptible Sleep)**可以被信号唤醒/打断;
**D 状态(Uninterruptible Sleep)**不能被任何信号打断,包括SIGKILL。

二者区别:
在这里插入图片描述

为什么要有 D 状态

主要是为了保证数据完整性和文件系统一致性:

  • 在写磁盘时如果被 kill -9 打断,可能导致写了一半的脏数据留在内存中、文件系统元数据不一致
  • 在持有内核 mutex/spinlock 等关键锁时,必须等待操作完成并释放锁,否则整个系统可能死锁
  • 本质上是一种保护机制:宁可单个进程挂死,也不让内核状态被破坏

与 stop、zombie 的区别

R- 正在运行或在运行队列上

S- 可中断睡眠 (Interruptible Sleep)

D- 不可中断睡眠 (Uninterruptible Sleep)

T- 被 SIGSTOP/TSTP 暂停 (stopped by job control)

Z- 僵尸 (zombie, 已退出但父进程未 wait)

D 状态non-IO和IO是啥意思?

先剖析Uninterruptible Sleep(non io)中的block方法__fdget_pos

在这里插入图片描述

源码中查看__fdget_pos 为什么是 non-IO

// fs/file.c:832 
mutex_lock(&file->f_pos_lock);// → schedule() ,不是 io_schedule() 
//in_iowait = 0 → non-IO 
 

它卡在 mutex 竞争上,不是在等磁盘 I/O 完成。等的是一个锁,不是一块数据从硬盘读上来。

mutex_lock() 内部调用 __mutex_lock_common(),使用的是 TASK_UNINTERRUPTIBLE。原因是:f_pos_lock 这个 mutex 保护的只是文件位置 (f_pos) 的一致性,虽然它本身不会直接涉及磁盘

I/O,但它的锁持有者(另一个线程)正在持有它做 I/O 操作。如果用 mutex_lock_interruptible(),被信号打断后需要处理回滚逻辑,而 VFS 层选择简单处理——宁可让等待者进 D 状态。

这是内核在 D 状态内部的一个细分,区分标志位是 task_struct->in_iowait。

核心区别

 
mutex_lock()schedule()→ in_iowait = 0D (non-IO)

read()vfs_read()...io_schedule()→ in_iowait = 1D (IO)
  • IO D 状态:通过 io_schedule() 进入睡眠,设置了 current->in_iowait = 1,表明线程在等磁盘/存储设备完成 I/O,CPU 本可以干别的活,这段时间被计入 iowait%
  • non-IO D 状态:通过普通的 schedule() 睡眠(如 mutex_lock),in_iowait = 0,表明线程在等内核同步对象(锁、waitqueue),不计入 iowait%

内核源码中:

// kernel/sched/core.c:5328

long __sched io_schedule_timeout(long timeout) 
{
int old_iowait = current->in_iowait; 
current->in_iowait = 1; // ← 标记为 IO 等
...
schedule_timeout(timeout); 
...
current->in_iowait = old_iowait; 
}
 

只有调用 io_schedule() / io_schedule_timeout() 的路径才会标记为 IO wait。

实际意义
在这里插入图片描述

你看到的 D (non-IO) 意味着线程既杀不掉,也不会在 iowait 指标上体现出来——它在纯粹地等另一个线程释放 f_pos_lock 这个 mutex。

总结三个状态的场景

一、D (IO) — 不可中断 I/O 等待

内核路径:io_schedule() → in_iowait = 1

触发条件是同步等待磁盘/存储完成读写。
经典场景:
FileInputStream.read()------------- read() → io_schedule()
FileOutputStream.write() -------------write() → io_schedule()
二、D (non-IO) — 不可中断非 I/O 等待

内核路径:mutex_lock() / wait_event() → schedule() → in_iowait = 0

本质是等内核同步对象(mutex、waitqueue for non-IO condition)。

经典场景:
多个线程操作同一个 FileInputStream / RandomAccessFile ---- __fdget_pos() → mutex_lock(f_pos_lock)
三、S — 可中断睡眠

内核路径:wait_event_interruptible() / schedule_timeout() / futex → TASK_INTERRUPTIBLE

绝大多数日常操作都属于 S 状态。
经典场景:
Looper.loop()---- epoll_wait() — 等待输入事件
Thread.sleep() -----nanosleep()

**S 状态(Interruptible Sleep)**可以被信号唤醒/打断;
**D 状态(Uninterruptible Sleep)**不能被任何信号打断,包括SIGKILL。
原文地址:
https://mp.weixin.qq.com/s/dowcSg_HVVSMvNSHqXkgoA

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值