上回我们讲了Linux程序分为用户态和内核态,我们日常使用的,比如用户界面,命令行等等,都是用户态,大部分驱动程序都是在内核态。本文来探讨为什么PCIe SSD开始使用Pooling模式来响应硬件,而不是传统的中断方式。
内核态NVMe驱动三大缺点
- 内核的通用性。为了照顾各种各样的硬件驱动,内核设计的比较通用,所以程序员很难发挥天赋去做个性化的设计。其实就是体制内条条框框太强大了,有想法,不安分的个体很难创新。
- 内核的公平性。内核有一大堆孩子,为了保证公平,不能把资源都集中到一个特殊设备上。我们这个社会也是一样,人民群众对特权很不满。排队的时候有人插队,肯定会惹众怒,阿呆会第一个跑出去把插队的人揪出来。
- 内核更新太勤快。Linus大叔和Linux大牛们真的是太敬业了,经常发布新版,差不多两三个月就有新版发布,如下图。这就导致要对内核驱动进行长期支持,因为有些接口到新版本就需要更新了。改了就需要测试,重新发布新驱动,程序员是很爽,饭碗永远在,但是老板就不满意了。
为了提升PCIe SSD驱动的性能,大牛程序员们做了各种尝试,比如放弃中断模式,改用轮询模式。另一个就是减少进程切换,我们之前讲过的多队列也是一种方法。
中断模式 vs 轮询模式
如下图,传统SSD的IO是下面4个步骤:
- 应用程序发读写给块设备队列;
- 驱动程序把命令发到SSD;
- SSD完成读写任务后发中断给CPU;
- CPU的中断处理函数响应中断,料理后事,结束任务。
那轮询模式是怎么弄的?
如下图,也分4步,只是第三步从中断变成了轮询。其实就是中断模式下,秘书有事了向领导汇报,领导抽空处理一下。轮询模式下,比如抗洪救灾,事情太多了,一件件通过秘书汇报效率太低,领导就亲自到指挥大厅现场指挥,实时处理各种情况,正所谓运筹帷幄之中,决胜千里之外。
性能比较
我们来比较两者的延迟情况。如下图,Async就是中断模式,Sync是轮询模式,C-State是低功耗中断模式。很明显,轮询模式下延迟相当短。
为什么会这样?下面两幅图剖析了两种模式下的延迟时间线,先看中断模式下。User线程1发System Call给内核,内核驱动发命令给硬件,接着系统搞别的去了,处理User线程2的事情。等硬件中断来了,又回来处理原来的任务。
- Td (4.1us), Ta (4.9us), Tb (1.4us), Tu (2.7us)
- 操作系统时间 = Ta + Tb = 6.3us
轮询模式下:轮询时间Td (2.9us), 总共在OS层消耗(4.4us)
中断模式的其他缺点
所谓帮人帮到底,踩人踩到底,再来细数中断模式的其他缺点:
- SSD性能很高,中断太多了之后,CPU就扛不住了,那么多中断要处理,忙不过来啊,搞不好撂挑子死个机给你看看。
- Cache的损失。发命令下去,中断还没回来,CPU处理别的任务了,这段时间有可能Cache里面攒的数据被别人给踢掉了。
- CPU电源模式切换。如果发了命令没其他任务,CPU有可能切换到休眠模式,再被中断唤醒,这样又带来了2us的延迟。轮训模式下,CPU就不休眠了。
引用
http://camelab.org/uploads/Main/When%20Poll%20is%20better%20than%20Interrupt.pdf