一、PIO 和 DMA 的定义与区别
1. PIO (Programmed I/O,程序控制 I/O)
定义: CPU 直接负责数据传输。当设备需要读/写时,CPU 用普通的 load/store 指令访问设备寄存器,把数据一个字节(或一批字)搬进搬出。
特点
- 实现简单,硬件便宜。
- CPU 开销大:CPU 忙于数据搬运,几乎是“苦力活”,占用大量指令周期。
- 适合低速设备(如键盘、鼠标、串口 9600bps)。
- 响应延迟低:CPU 直接参与搬运,不需要复杂控制,适合实时性要求高但数据量小的场景。
引入缓冲区(FIFO buffer)
很多 PIO 设备(如 UART、早期硬盘控制器)内部会带一个 FIFO 缓冲区(几字节到几十字节不等):
- CPU 一次可以写多个字节到 FIFO,硬件再慢慢从 FIFO 里把数据发送出去。
- 这样减少了 CPU 与设备交互的次数,性能比“单字节 PIO”要好得多。
- 例如:UART 16550 芯片有 16 字节 FIFO,可以一次性写多个字符,而不是每个字节都要等硬件发完。
即使有缓冲区,仍然存在的问题
- CPU 仍然是主动的:CPU 依然要一批批把数据搬到 FIFO,直到整个数据块写完。
- 例如要传 4KB 数据,FIFO 只有 16 字节 → CPU 要循环写 256 次寄存器。
- 吞吐量受限:CPU 时间被消耗在 I/O 搬运上,无法并行处理别的计算。
- 扩展性差:当数据量非常大(如磁盘、网卡、显卡内存传输),即使有 FIFO,CPU 也会很快成为瓶颈。
举例
uartputc()在 xv6 里就是典型的 PIO:CPU 把要发的字节写入 UART 的数据寄存器。UART 硬件再去发送,可能带一个小 FIFO。- 嵌入式系统的 GPIO、低速串口、简单 I²C/SPI 外设,大多还是 PIO 方式。
🔑 一句话总结: 带缓冲区的 PIO = “批量版 PIO”,能减少一些 CPU 的负担,但本质问题(CPU 仍然负责搬运)没变;一旦数据量大,就会拖慢系统性能 → 这时必须用 DMA 来解放 CPU。
2. DMA (Direct Memory Access,直接内存访问)
定义:由 DMA 控制器(硬件)负责在 内存 ↔ 设备 之间搬运数据,CPU 只需要设置好“任务参数”(源地址、目标地址、传输大小等),然后让 DMA 去跑。
传输完成后,DMA 控制器通常会给 CPU 发一个中断,告诉它“任务完成”。
特点:
- CPU 负担小:CPU 不需要每个字节都搬,只需要发命令、然后处理结果。
- 适合高速、大批量数据传输(例如网卡收发包、硬盘读写、显卡纹理传输)。
- 需要额外的 DMA 硬件。
- 支持异步传输,CPU 可以并行处理其他任务,提高系统整体效率。
- 某些 DMA 控制器还支持 scatter-gather(分散-聚集)模式,能处理非连续内存块。
举例:
- 网卡(NIC):收到一个以太网帧时,DMA 会把数据直接写进内存里的缓冲区,CPU 只在包到达后被中断唤醒。
- GPU 上传纹理时,也会走 DMA。
- 现代硬盘(如 SATA、NVMe)数据传输基本都依赖 DMA。
3. 核心区别总结
| 特性 | PIO | DMA |
|---|---|---|
| 数据搬运者 | CPU | DMA 控制器 |
| CPU 开销 | 高,需要循环读写 | 低,只需设置参数和处理中断 |
| 适合设备 | 低速、简单设备 | 高速、大数据吞吐设备 |
| 硬件需求 | 简单,寄存器就行 | 需要 DMA 控制器支持 |
| 延迟 | 小数据可快(少配置) | 初始配置略复杂,但适合大批传输 |
| 并发能力 | 差,CPU被占用 | 好,CPU可并行做其他任务 |
补充说明:
- 在现代操作系统和硬件中,DMA 已成为主流,尤其是在数据吞吐量要求高的场景(如磁盘、网络、显卡等)。
- 某些嵌入式或实时系统,仍然会用 PIO 以获得更低的延迟和更高的可控性。
- DMA 的使用需要注意内存一致性和安全性(如防止 DMA 攻击),通常操作系统会对 DMA 访问做严格管理。