2. 内存带宽与延迟分析:DDR带宽计算、延迟模型、实际吞吐量测试方法

好,咱们进入第二章。内存带宽和延迟,这俩词儿做嵌入式的人天天挂嘴边。但说实话,真正能把它算清楚、测明白的人,不多。

我个人习惯,拿到一块新板子,第一件事不是跑应用,而是先把DDR的带宽和延迟摸透。为什么?因为后面所有性能优化的天花板,就在这里。你CPU再快,内存喂不饱数据,全是白搭。

2.1 DDR带宽计算:别光看理论峰值

先说说理论带宽怎么算。公式其实很简单:

带宽 = 时钟频率 × 数据位宽 × 每时钟传输次数 × 通道数

举个例子,DDR4-3200,64位总线,双通道:

  • 时钟频率:1600 MHz(DDR是双倍速率,等效频率3200 MHz)
  • 数据位宽:64 bit = 8 Byte
  • 每时钟传输次数:2(上升沿和下降沿各一次)
  • 通道数:2

算一下:1600 MHz × 8 Byte × 2 × 2 = 51.2 GB/s。这是理论峰值。

重点来了:理论峰值你永远跑不到。我在海思项目上实测,能跑到理论值的70%-80%就算优化得不错了。为什么?因为还有协议开销、刷新周期、bank冲突这些乱七八糟的东西。

实际有效带宽,我一般用这个经验公式:

有效带宽 ≈ 理论峰值 × 0.7 ~ 0.85

嗯,具体系数取决于你的访问模式。顺序读写能接近0.85,随机访问可能掉到0.5以下。

2.2 延迟模型:别被数据手册骗了

带宽重要,延迟更重要。尤其是对实时性要求高的场景,比如视频处理、音频流。

DDR的延迟,说白了由三部分组成:

  1. 命令延迟(tRCD):从发出行激活命令到列选通命令的时间
  2. CAS延迟(CL):从列选通到数据开始输出的时间
  3. 传输延迟:数据在总线上传输的时间

数据手册上给的CL值,比如CL=22,那是多少个时钟周期。换算成实际时间:

延迟时间 = CL × 时钟周期

DDR4-3200的时钟周期是0.625 ns,CL=22的话,CAS延迟就是13.75 ns。看着不高对吧?

注意:这只是芯片内部的延迟。实际系统延迟还要加上PCB走线延迟、片内互联延迟、缓存缺失惩罚。我在一个项目中遇到过,实际测量出来的延迟比数据手册大了3倍,查了半天发现是PCB走线等长没做好。

我建议你建立自己的延迟模型,至少包含这几项:

  • DDR芯片内部延迟(来自数据手册)
  • PCB走线延迟(约0.15 ns/inch)
  • SoC内部内存控制器延迟(这个得问芯片厂商)
  • 缓存缺失惩罚(取决于你的缓存策略)

2.3 实际吞吐量测试方法:动手测才是硬道理

理论算完了,模型建好了,最后还得动手测。我常用的测试方法有三种:

2.3.1 软件微基准测试

用memcpy或者自定义的读写循环,测量不同访问模式下的吞吐量。代码很简单:

// 顺序读测试示例
volatile uint32_t *buf = (uint32_t *)0x80000000;
uint64_t start = get_cycle_count();
for (int i = 0; i < 1024*1024; i++) {
    temp = buf[i];
}
uint64_t end = get_cycle_count();
printf("顺序读带宽: %f MB/s\n", (4*1024*1024) / ((end-start)/freq));

我个人习惯测这么几种模式:

  • 顺序读
  • 顺序写
  • 随机读(步长64字节、128字节、4KB)
  • 随机写
  • 混合读写(7:3比例)

小技巧:测之前一定要先预热缓存,不然第一次访问全是cache miss,测出来的数据不准。我一般先跑一遍同样的循环,再开始计时。

2.3.2 硬件性能计数器

海思芯片内部有性能监视单元(PMU),可以直接读出DDR控制器的实际带宽和延迟。这比软件测量准得多。

我记得在海思3559A上,通过读取PMU寄存器,能看到实时的DDR利用率、读带宽、写带宽、平均延迟。这些数据对调优太有用了。

// 伪代码:读取DDR性能计数器
uint32_t ddr_read_bw = read_pmu(PMU_DDR_READ_BW);
uint32_t ddr_write_bw = read_pmu(PMU_DDR_WRITE_BW);
uint32_t ddr_avg_lat = read_pmu(PMU_DDR_AVG_LATENCY);

2.3.3 实际应用场景测试

微基准测试只能反映理想情况。真正的问题,往往出现在实际应用中。

我曾经做一个4K视频解码的项目,微基准测试显示DDR带宽还有30%余量,但实际解码就是掉帧。后来用硬件计数器一看,发现是DDR的bank冲突太严重,导致有效带宽骤降。

所以我的建议是:

  1. 先用微基准测试摸清DDR的底
  2. 再用硬件计数器监控实际运行时的数据
  3. 最后针对瓶颈做优化

2.4 避坑指南

我曾经踩过的坑:

  • 别信数据手册上的理想延迟,实际测出来可能翻倍
  • DDR频率不是越高越好,频率高了延迟反而可能变大
  • 多通道DDR要小心地址映射,不然带宽根本发挥不出来
  • 测带宽时记得关掉DMA和其他外设,不然测的是共享带宽

好了,这一章就到这里。记住一句话:内存性能,测了才知道。下一章咱们聊聊DDR的调优实战,包括时序参数调整和地址映射优化。

公众号:蓝海资料掘金营,微信deep3321