CS61C – 9 – I/O Devices

这一讲的内容对应于讲座的 lec 31 (b 大上的参考课程为 [Summer 20]),这一部分的主要针对 I/O 设备进行展开,重点阐述了计算机时如何与外部设备进行通信以及与此相关的三种技术:程序控制I/O(轮询)中断驱动I/O直接内存访问(DMA)

在前文我们提及了 Cache 这一重要概念,并说它是为了缓解 CPU 与主存间巨大的性能鸿沟而设计的中间件。事实上,同样的问题也出现在 CPU 与 I/O 设备之间,而且更加严重,例如,1GHz的CPU一个周期是1纳秒,而机械硬盘的寻道时间是5-10毫秒,相当于500万到1000万个CPU时钟周期。而且 I/O 设备极低的时间局部性和空间局部性(比如你打字不会只反复敲几个字母)导致在这种情况下,类似于 Cache 的组件已经失去了存在的意义(但这不意味着 I/O 的设计不涉及类似思想!),我们在这要面对的不再是 Cache 中“如何快速访问数据”的问题,而是“如何让CPU摆脱漫长的等待过程”

I/O 设备与内存映射 I/O (Memory-Mapped I/O)

CPU与设备通信的本质可以理解为对设备上的寄存器进行读写,通过将 I/O 设备的寄存器映射到处理器的物理地址空间的一部分。CPU使用普通的加载(lw)和存储(sw)指令来读取或写入相关地址来与设备通信,就像访问内存一样。这也是 RISC – V 等现代体系结构采用的主流方式

但 x86 的方式与此不同, CISC 拥有独立的指令来访问一个独立的 I/O 地址空间,我们称之为端口映射。

了解了基本的通信方式,我们便可以开始考虑如何进行通信。前文提及,I/O 的设备速度远低于 CPU 的处理速度,直接读取会造成大量空转,这显然是不明智的,为此有三种方法可以进行缓解

程序控制I/O / 轮询 (Programmed I/O / Polling)

所谓轮询,顾名思义,轮着问询,CPU会反复读取设备的状态控制寄存器,检查“就绪”位是否被设置

  • 如果未就绪,问询下一个
  • 如果就绪,CPU从设备的数据寄存器读取数据(输入)或向其中写入数据(输出)。

这种方式很简单,硬件支持要求也低,但问题也是显而易见的:CPU利用率极低。在等待设备就绪期间,CPU处于“忙等待”状态,无法执行其他有用工作。

但也不是说这种方式毫无用处,某些低速设备(鼠标,键盘等)的检查间隔长,CPU不介意浪费一些时间进行轮询(因为耗时所占比例小)

中断驱动I/O (Interrupt-Driven I/O)

与上一种方式不同,这一种策略,主动的是 I/O 而不是 CPU。具体而言,CPU 在启动 I/O 操作后,不再轮询,而是继续执行其他进程,当 I/O 设备完成操作并准备好后,它主动向CPU发送一个硬件中断信号。CPU保存当前上下文,陷入(Trap) 到操作系统内核中对应的中断服务程序(ISR).

显然这在大部分情况下能显著提高 CPU 的运行效率,但有时为了中断进行的保存和恢复上下文操作也会成为不可忽视的开销(尤其是小批量多批次)。因此,这种策略更适用于中低速设备,或者作为高速设备数据传输的启动和结束信号

直接内存访问 (Direct Memory Access, DMA)

这种策略的方式相当直接:引入一个专门的DMA控制器(一个简单的处理器),作为 I/O 设备与主内存之间的代理,绕过 CPU 直接进行大规模数据传输。 CPU 只需要对 DMA 控制器进行编程(设置内存起始地址传输字节数目标设备等),然后就不再管具体的数据传输过程。之后 DMA 控制器接管总线,直接在 I/O 设备(如磁盘控制器、网卡)和主内存之间传输数据。最终当整个数据块传输完成后, DMA 控制器向 CPU 发送一个中断,通知其操作已完成。

这种策略的高明之处便在于其彻底解放了 CPU,CPU 不再关心具体的执行情况,通信过程全程可以处理计算任务,因此特别适合大批量高速的数据传输过程。

但该策略也不是万无一失的,事实上,如果DMA将数据直接写入内存,而该数据的一个旧副本还存在于CPU缓存中,就会导致数据不一致。现代系统通常通过让DMA操作绕过缓存(Cache Bypassing) 或由硬件自动无效化(Invalidate) 相关缓存行来解决。此外, DMA 控制器有时占用内存总线也可能引发潜在冲突

Cache 在 I/O 系统中的正确打开方式

我们在一开始提及说 Cache 的部件不适用于 CPU 与 I/O 设备间的通信,但缓冲(Buffering) 的概念在I/O系统中无处不在,而且是至关重要的,将两者做个对比,我们有:

特性硬件Cache I/O 缓冲区 (Buffer)
主要目标加速访问,弥补CPU-内存速度差流量整形,解决生产者-消费者速度不匹配
数据特性期望被重复访问(有局部性)通常只访问一次(流数据)
所处位置硬件(在CPU和主存之间)主要在软件/驱动(内存中划出一块区域)
管理方式硬件自动管理,对软件透明由操作系统、驱动程序或应用程序显式管理

缓存区的主要作用包括但不限于:

  • 批处理(Batching)将小的写操作可以在内存缓冲区中合并成一个大的写操作,再一次性写入磁盘,极大减少了昂贵的寻道开销
  • 解耦(Decoupling):缓冲区分隔了生产者和消费者,使两者运行时感受到的速度是统一的

但其实上 I/O 系统中有没有 Cache 呢?我们注意到有这样一个术语:磁盘缓存(Disk Caching)

但它不是位于磁盘控制器上的硬件Cache,而是操作系统利用主内存的一部分来实现的软件功能。它将操作系统将最近读写的磁盘扇区内容保留在内存的一个特定区域中。

之所以这么干,是因为磁盘访问太慢了ㅇㅅㅇ 虽然磁盘数据也可能缺乏时间局部性,但从内存提供数据的速度(~100ns)和从磁盘提供的速度(~10ms)之间有高达10万倍的差距。因此,即使命中率只有1%,只要有一次命中,其带来的性能收益也是巨大的。它利用了内存远比磁盘快这一事实,而不是局部性原理。

Computer Network

在讲座的最后,还提及了计算机网络,事实上,讲座将计网视为最重要的 I/O 设备。发送和接收数据的过程涉及大量内存拷贝(从用户空间到内核空间,再到网络接口),这正是DMA技术大显身手的地方,可以显著降低CPU在网络I/O中的开销,此处不做额外展开,后面大概会基于 USTC 的计网写个笔记,到时候再看(

写在最后

总而言之,这一讲再次深刻体现了计算机架构中无处不在的权衡(Trade-off):

  • 从轮询到 DMA,方式在变复杂,但效率也在变高。不同的部件适用于不同的策略,但我们的目标是一致的:即让操作系统通过中断DMA等机制,协调着速度差异巨大的各个部件(CPU、内存、I/O设备),让它们高效、并行地工作,并最终提供流畅无缝的计算体验。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注