总线与 IO — 数据怎么在芯片之间流动

一句话:系统性能瓶颈几乎不在算力而在搬运——带宽(每秒能搬多少)与延迟(一次要等多久)由总线层次和 IO 方式决定,算清这两件事再谈优化。

🎯 这 20% 能解决哪些问题

你遇到的困惑本质原因马上能改的动作
加了两块高速 NVMe,吞吐没翻倍瓶颈在 PCIe 通道数或 DMI/芯片组上行链路查设备实际协商到的 gen × lane,别只看厂商标称
内存插满反而降频通道数与每通道 rank 数互相制约,DIMM 越多频率越低优先插满通道数而不是插满插槽;按主板支持表选型
高并发网络下 CPU 全耗在中断上硬中断 + 软中断 + 上下文切换的开销叠加开网卡多队列 + RSS、中断聚合(coalescing),必要时下沉到 DPDK/io_uring
磁盘顺序读写很快,4K 随机很慢队列深度与 IOPS 上限;机械盘还有寻道延迟压测要同时测顺序带宽与随机 IOPS,两者不可互相推断
传感器每秒中断上万次,系统卡顿每次中断有入栈/出栈与缓存冲刷代价改为 DMA + 批量完成中断,或降采样率
外设数据「读到了但总是慢一步」走了程序查询或未做缓存维护用 DMA 并在接收后 invalidate,或映射为不可缓存区
数据库 fsync 偶发几十毫秒刷盘语义 + 写缓存 + 调度合并区分 fdatasync/fsync/O_DIRECT,测 P99 而不是均值

一、总线的三组信号与带宽计算

信号组作用决定什么
地址总线指明访问哪个位置可寻址空间 = 2^地址位宽
数据总线搬运数据一次能搬多少位
控制总线读/写/中断就绪/仲裁时序、能否突发传输(burst)

[ 带宽 = 时钟频率 \times 位宽 \times 每周期传输次数 \times 通道数 ]

例子计算结果
DDR4-3200 双通道3200 MT/s × 8 B × 2(编号即每秒传输次数,每通道 8 字节宽)约 51.2 GB/s
PCIe 4.0 ×4约 2 GB/s × 4 lane(每 lane 每方向)约 8 GB/s 单向
32 位 72MHz 老式外设总线72M × 4 B约 288 MB/s
10Gbps 网卡10 Gb ÷ 8约 1.25 GB/s(还要扣协议开销)

易错点:PCIe 每 lane 双工(各方向独立),带宽要按方向计;DDR 的「MT/s」与「MHz 时钟」不是一回事;标称带宽是理论峰值,实测 70–85% 才正常。


二、总线层次:从片内到机箱外

graph TB
    A["内核 + L1/L2"] --> B["片内互连 AXI/AHB/总线矩阵"]
    B --> C["内存控制器 DDR 通道"]
    B --> D["芯片组 / PCIe Root Complex"]
    D --> E["GPU / NVMe / 网卡(PCIe)"]
    D --> F["低速外设 SPI I2C UART USB"]
层次典型协议数量级关注点
内核与缓存内部总线、MESI 探测纳秒内命中率、伪共享
片内互连AXI(ARM)、AHB/APB 挂低速外设几十 ns突发长度、仲裁、并发主设备
内存总线DDR4/DDR5约 100 ns通道数、rank、页命中
扩展总线PCIe Gen3/4/5微秒级lane 数、TLP 开销、DMA
外部互连USB/以太/SATA/NVMe-oF数十微秒起协议栈开销、拥塞

判据:任何「换硬件没变快」的问题,先定位瓶颈在哪一层——只有最窄那一层的带宽提升才有意义。


三、DMA:把搬运从 CPU 手里拿走

IO 方式流程CPU 代价适用
程序查询(轮询)CPU 反复读状态寄存器100% 占用,无法处理别的事极短事务、启动早期、裸机简单场景
中断驱动每字节/每包打断 CPU每次中断约 1–2µs 系统开销事件稀疏(按键、串口命令)
DMA外设/内存批量搬运,传完一次中断只在开始与结束介入大块数据:网卡、磁盘、ADC 采样、显示刷屏
内核旁路(DPDK/io_uring/RDMA)用户态直接收发,轮询或批量提交减少中断与拷贝、系统调用高 PPS 网络、高 IOPS 存储、超低延迟

DMA 的三件必修事:

  1. 缓冲区生命周期:传输期间内存不能被释放/复用,通常要加锁或双缓冲。
  2. Cache 一致性:带 D-Cache 的系统必须发送前 clean、接收后 invalidate,或用不可缓存区。
  3. 地址约束:32 位 DMA 控制器看不到超过 4GB 的地址;跨页/分散-聚集需要 scatter-gather 描述符链。

四、中断在 IO 路径上的成本

阶段做的事成本点
硬中断确认设备、读状态、收数据入队尽量极短,不做协议处理
软中断 / tasklet / 工作队列协议解析、上送可被高负载挤压,注意延迟上限
唤醒线程通知等待的处理任务上下文切换 + 缓存冷启动
中断聚合N 次事件合并为 1 次中断延迟换吞吐,实时场景要设上限
技术解决什么注意
MSI/MSI-X线中断改为内存写消息,支持多向量依赖 PCIe 与内核支持
多队列 + RSS按流哈希把包分到不同 CPU 核单流仍受单核限制,别指望多核加速一条 TCP
NAPI / 轮询混合高压时收中断、低压回中断模式空闲时延迟略增,用 gro_flush_timeout 类参数调节
CPU 亲和与隔离把中断固定到指定核与 RT 任务的优先级设计要一起规划

一句结论:中断风暴的本质是「用高成本路径处理高频事件」。要么批量(聚合/DMA),要么绕过(轮询/旁路)。


五、存储 IO:带宽与 IOPS 是两条独立曲线

介质顺序带宽4K 随机 IOPS延迟量级关键限制
HDD(7200rpm)150–250 MB/s约 100–200约 10 ms寻道 + 旋转
SATA SSD约 550 MB/s数万约 100µsSATA 队列与协议
NVMe Gen4 ×4约 7 GB/s数十万至百万约 10–100µsPCIe 带宽 + 闪存页大小
内存(DRAM)数十 GB/s—约 100 ns通道与页命中
概念含义工程影响
队列深度(QD)同时在途的请求数QD=1 只能测出单请求延迟对应的吞吐,必须并发压测
页/擦除块SSD 以页写、以块擦写放大明显;随机写性能与剩余空间强相关
写放大实际写入闪存量 / 主机写入量影响寿命与稳态性能,稳态比瞬时差很多
合并与调度内核把相邻请求合并顺序写能跑满带宽的原因之一
fsync 语义数据 + 元数据落盘(含设备缓存刷)有 volatile 写缓存的盘上 fsync 可能很慢
预读顺序读时多读若干页随机读场景预读反而浪费带宽,可用 posix_fadvise 关闭

六、把总线与 IO 用于容量规划

我要估估算式例子
网络能否跑满PPS × 平均包字节 × 814.88 Mpps @64B 就是万兆满载,小包先撞 PPS 而非带宽
磁盘够不够QPS × 平均读块大小 与 随机 IOPS 分别核算数据库 5k QPS × 16KB ≈ 80MB/s,但随机读要看 IOPS
采集/日志能否跟上单次 IO 大小 × 频率 × 设备数4kHz × 12ch × 4B ≈ 192 KB/s,远低于任何总线,问题多半在 CPU 侧
显存/内存够不够张量元素数 × 字节数 + 激活 + 梯度大模型推理常受带宽约束:时间 ≈ 参数字节 ÷ 内存带宽

统一方法:先算「每秒要搬多少字节」和「每次搬运等多久」,再和上表各层的真实能力对比——瓶颈立刻显形。


🎓 实战场景(TIL)

  • 场景:给视频剪辑机换了两块 Gen4 NVMe,吞吐只涨 20%。本质:主板 PCIe 通道经芯片组共享,实际协商为 Gen3 ×2。要点:用 lspci -vv 查 LNKSTA 的实测速率与宽度,再看 CPU 直连通道预算。
  • 场景:网关设备开启网卡多队列后 P99 反而变差。本质:包被分到不同核,单流被打乱顺序且跨核同步增加。要点:按流哈希保证同流同核;关注连接数而非核数是否够用。
  • 场景:单片机 SPI 接 Flash 写入正常、读取偶发校验失败。本质:读操作走轮询且未做 CS 建立时间,高速时采样沿偏移。要点:先用逻辑分析仪确认 CPOL/CPHA 与时序裕量,再提频;大块传输改 DMA。

📋 一页速查

我要判断照着做
峰值带宽频率 × 位宽 × 通道数,实测按 70–85% 折算
PCIe 实际能力lspci -vv 看 LNKSTA 协商到的 gen × lane
内存带宽通道数 × 每通道带宽;插满通道优先于插满插槽
小包网络瓶颈先算 PPS(线速 ÷ (包长+帧开销)),再看字节带宽
该用哪种 IO大块 → DMA;稀疏事件 → 中断;超高 PPS → 聚合或旁路
中断太多次批量/聚合优先,其次降频,最后换 DMA 描述符链
DMA 数据不对检查 cache 维护、缓冲区生命周期、地址是否越界
磁盘压测可信吗同时测顺序带宽与 4K 随机 IOPS,并发跑够队列深度,看稳态
刷盘语义fsync(数据+元数据)vs fdatasync(必要元数据)vs O_DIRECT(绕过页缓存)

🔗 相关链接

主题链接
上级 Hub计算机体系结构
同域上一课体系结构核心 20% — 性能公式、存储层次与流水线
同域参考嵌入式与单片机 — 总线与 IO 在 MCU 外设上的形态
操作系统操作系统与进程模型 — 页缓存、IO 调度与中断处理
性能优化性能优化 — 把带宽与延迟用于容量规划
消息队列消息队列 — 批量与背压的同构问题