LabHub
学习 学习路径 课程

计算机组成

输入输出与总线 — 中断、DMA,以及 PCIe

在 LabHub 中继续学习

一句话总结

与设备通信可分为三层:何时通知(轮询或中断)、由谁搬运(CPU 或 DMA)、经过哪里(总线与互连)。

概念图: 轮询与中断。 · 开始用中断、繁忙时转为轮询 · DMA。 · MMIO 与端口 I/O。

为什么需要了解这些

CPU 以纳秒运行,磁盘与网卡则以微秒到毫秒运行。若不隐藏这种速度差,CPU 会把时间都花在等待设备上。I/O 设计史就是不断回答如何隐藏这段差距。

工作原理

轮询与中断。 轮询让 CPU 不断读取设备状态寄存器,简单且延迟低,但 CPU 无法做其他工作。中断则由设备就绪时通知 CPU,CPU 可先做别的事,但每次中断都要保存上下文并跳转到处理程序。每秒数十万数据包时,中断反而会使系统瘫痪(中断风暴),因此 Linux NAPI 等开始用中断、繁忙时转为轮询的混合方式已成为标准。

DMA。 若数据逐字经过 CPU 寄存器搬运,CPU 会沦为搬运工。DMA 控制器直接在设备和内存之间移动数据,全部完成后只触发一次中断。现代系统的大批量传输无一例外使用 DMA。

MMIO 与端口 I/O。 把设备寄存器映射进内存地址空间后,可用普通加载/存储访问(MMIO)。语法虽与内存相同,成本却完全不同。 MMIO 读取属于必须等待响应的非发布事务,PCIe 往返时间会直接成为执行时间,且不能缓存。驱动若在循环中读取设备寄存器,该循环并非计算,而是在反复进行 I/O 往返。

PCIe。 带宽由通道数和代际决定。每代每通道速度大约翻倍,并可组合成 x1/x4/x8/x16。GPU 插在 x4 而非 x16 插槽中时,计算能力不变,但数据供给降为四分之一。多 GPU 训练使用 NVLink 等专用互连也是因为卡间 PCIe 通信会成为瓶颈。

实际工作中的表现

家庭实验室搭建 GPU 节点时,最常见错误是忽略插槽带宽。主板第二、第三插槽常只有电气 x4;插三张卡后,两张会悄悄以四分之一带宽运行。训练仍能进行,但每步耗时异常。养成用 lspci -vv 检查协商链路宽度的习惯可以节省大量时间。

用数字定位瓶颈

记住带宽的数量级即可建立直觉。

路径 大致带宽
CPU ↔ L1 缓存 1 TB/s 以上
CPU ↔ 内存(DDR5) 50~100 GB/s
PCIe 4.0 ×16 32 GB/s
PCIe 4.0 ×4(单块 NVMe) 8 GB/s
10 GbE 网络 1.25 GB/s
SATA III 0.6 GB/s

使用多块 GPU 时,PCIe 会成为瓶颈。 32GB/s 甚至不到内存带宽的一半,因此频繁在卡间传输数据的模型并行会很慢,这正是 NVLink 存在的原因。

还要检查通道数。即使插入 ×16 插槽,主板若只连接 ×4,带宽仍只有四分之一。

lspci -vv -s <슬롯> | grep -E 'LnkCap|LnkSta'
LnkCap: Speed 16GT/s, Width x16      ← 장치가 할 수 있는 것
LnkSta: Speed 16GT/s, Width x8       ← 실제로 연결된 것   ← 절반이다

两行不同时,说明插槽或分叉(bifurcation)配置有问题。GPU 性能只有预期的一半时,应先查这里。

中断与轮询

设备完成工作后通知 CPU 有两种方式。

高速网络和 NVMe 会混合使用两者。 Linux NAPI 在数据包激增时关闭中断并切换为轮询,因此 si(softirq) 使用率高通常表示网络繁忙。

ethtool -c eth0 的中断合并(coalescing)设置可调节这种平衡。增大该值会提高吞吐量,也会增加延迟。

DMA 的作用

设备不经过 CPU,直接读写内存。否则从磁盘读取 1GB 时,CPU 必须亲自搬运全部 1GB。

由此产生了零拷贝。把文件发到套接字时,普通路径是磁盘 → 内核缓冲区 → 用户缓冲区 → 内核套接字缓冲区 → NIC,共复制四次;sendfile()splice() 会绕过用户空间。这是静态文件服务器速度快的原因,也是 nginx 的 sendfile on 所做的事。

后续测验将确认什么

确认你能解释同一条 mov 指令为何访问某些地址只需纳秒,而访问另一些地址却可能耗费毫秒。