中断、DMA 与缓存层次¶
CPU 可以逐字节搬运设备数据,但这样会浪费大量指令并把计算核心变成昂贵的数据搬运工。DMA 让设备控制器直接在设备与内存之间传输数据,中断或轮询则用于报告完成和回收资源。
三种基本传输方式¶
程序控制 I/O¶
CPU 反复读写设备寄存器并搬运数据。实现简单,适合极少量控制信息;大块传输会占用大量 CPU。
中断驱动 I/O¶
CPU 启动操作后去执行其他任务,设备准备好时中断。减少空等,但若每个极小事件都中断,高事件率会形成中断风暴。
DMA¶
CPU/驱动准备内存缓冲和描述符,设备控制器成为总线主设备,在设备与内存间搬运。完成后通过中断或完成队列通知。
DMA 减少按字节 CPU 搬运,但设置描述符、映射内存、处理中断和协议仍消耗 CPU。
描述符环¶
网卡和高速存储常使用环形队列:
- 驱动在提交环放入缓冲地址、长度和标志。
- 设备消费描述符并执行 DMA。
- 设备在完成环或描述符状态中写结果。
- 驱动批量回收并补充新缓冲。
生产者和消费者索引必须按内存序发布。若先更新可见尾指针,再把描述符内容写完整,设备可能读取半初始化请求。
中断入口与延后处理¶
设备发出中断后,快速处理通常:
- 识别和确认中断来源。
- 读取必要状态或屏蔽进一步通知。
- 安排延后处理。
- 尽快返回。
延后部分批量处理完成队列、协议栈、唤醒等待线程并重新启用通知。这样缩短高优先级路径,却增加少量排队延迟。
中断合并¶
若每完成一个包都中断,事件率 \(r\) 等于中断率,固定处理开销为 \(c_i\),仅入口开销就约为:
设备可按数量或定时器合并多个完成再中断。吞吐提高,但第一个完成要等待批次形成,增加延迟。自适应合并会根据负载调整。
轮询与混合模式¶
低负载时中断节能且避免空转;高负载时轮询可以批量处理并避免中断风暴。网络子系统常采用混合方式:中断通知有工作后,暂时关闭或抑制中断并轮询一批数据,队列清空再恢复中断。
这不是“中断和轮询谁更先进”,而是根据事件率选择固定开销更低的一方。
DMA 缓冲区的要求¶
设备看到的是总线地址或 I/O 虚拟地址,不一定等于 CPU 虚拟地址。驱动需要通过 DMA 映射接口获得设备可用地址,并满足:
- 生命周期覆盖整个设备访问期间。
- 对齐和长度符合设备要求。
- 页面被固定或以系统允许方式映射,不能在传输时被随意回收。
- 方向和缓存同步操作正确。
- 设备只访问授权范围。
把普通栈指针直接交给设备通常错误:栈对象可能提前失效,虚拟地址也不是设备能理解的地址。
缓存一致性问题¶
在硬件缓存一致的系统中,DMA 与 CPU 缓存由平台保证基本一致,但仍需正确内存屏障和 DMA API 来排序描述符与完成状态。
在非一致平台上:
- CPU 写给设备前,可能需要把脏缓存行写回内存。
- 设备写入后,CPU 读取前可能需要使旧缓存行失效。
否则 CPU 和设备会看到同一缓冲的不同版本。
IOMMU¶
IOMMU 为设备 DMA 提供地址翻译与权限检查,类似 CPU MMU:
- 设备使用 I/O 虚拟地址。
- 内核配置映射到允许的物理页。
- 越界 DMA 可被阻止和报告。
它提高隔离、支持设备直通和非连续缓冲映射,但增加映射管理、IOTLB 和失效成本。高性能系统会批量映射、复用缓冲或使用大页降低开销。
页缓存、设备缓存与 CPU 缓存¶
“缓存”一词对应不同层:
| 层次 | 缓存什么 | 由谁管理 |
|---|---|---|
| CPU cache | 最近内存缓存行 | 硬件 |
| TLB | 地址翻译 | 硬件与内核 |
| 页缓存 | 文件数据页 | 操作系统 |
| 设备控制器缓存 | 待写/常用块 | 控制器固件 |
| 介质内部缓存 | 闪存映射与数据 | 设备 |
应用的 write 返回时,数据可能只到页缓存;内核发出写后,可能只到易失设备缓存。持久化协议必须跨越所有相关层。
双缓冲与流水线¶
若只有一个缓冲,设备传输时 CPU 不能安全复用它。双缓冲允许:
理想稳定吞吐受较慢阶段限制:
更多缓冲可以吸收抖动,却增加排队延迟和内存占用。最终仍需要背压。
Scatter-Gather I/O¶
逻辑数据可能分散在多个非连续页。scatter-gather 描述符让设备在一次请求中遍历多个片段,避免先复制到一块连续缓冲。
代价是描述符更多、设备段数有限、IOMMU 映射成本和边界条件更复杂。上层仍可能因协议头、校验和或加密需要访问数据。
错误恢复¶
设备可能:
- 超时且不产生中断。
- 返回校验、介质或总线错误。
- 在热拔出时仍有未完成 DMA。
- 固件失去响应,需要重置队列或设备。
驱动必须停止新请求、取消或等待 DMA、回收描述符、避免重复完成,并向上层传播可理解错误。重置路径和正常路径并发,是驱动最容易出错的区域之一。
安全风险¶
没有 IOMMU 或映射错误时,恶意/故障设备可 DMA 到任意物理内存,绕过 CPU 页表。设备直通给虚拟机时尤其要精确配置隔离。
驱动解析设备提供的长度、索引和状态时也不能盲目信任;设备固件、外设或虚拟设备都可能返回异常数据。
性能权衡¶
- 小批次:低延迟,高中断和门铃开销。
- 大批次:高吞吐,排队延迟更大。
- 复制缓冲:生命周期简单,消耗内存带宽。
- 零拷贝/固定页:减少复制,固定内存与回收更复杂。
- 中断:空闲效率高,高负载开销大。
- 轮询:低延迟可控,空闲时浪费 CPU 和能量。
性能优化应同时看吞吐、尾延迟、CPU 占用和功耗。
自测¶
- DMA 减少了哪类 CPU 工作,哪些工作仍存在?
- 为什么设备看到的地址不能直接使用用户虚拟地址?
- 中断合并怎样影响吞吐和延迟?
- IOMMU 与 CPU MMU 的共同点和对象区别是什么?
write返回后,数据可能停在哪些缓存层?
参考思路
DMA 避免逐字节搬运,提交、映射、协议和完成处理仍需 CPU。设备使用总线/I/O 地址。合并摊薄中断成本但等待成批。两者都翻译并检查权限,MMU 服务 CPU,IOMMU 服务设备。数据可能仍在用户库缓冲、页缓存、控制器缓存或介质内部缓存,取决于接口和时刻。