2.2 存储器层次结构:从寄存器到片外存储


2.2 存储器层次结构:从寄存器到片外存储

上一节把计算单元排了兵布了阵,本节回答它们最关心的问题:数据住在哪。存储层次是三大件里数字最多的一层——每级的容量、延迟、带宽都是要在架构阶段写死的参数。读完本节,你应当能画出一颗 SoC 的存储金字塔,给每层填上说得出口的数字,并且能裁断工程里最常吵架的问题:这块缓冲区该放在哪、归谁管。

为什么快的存储一定小

存储器有个绕不开的物理事实:越快,越贵,越难做大。寄存器一个比特的代价能买片外存储几千上百万个比特;反过来,大容量存储的速度又慢出几个数量级。既然两头都不肯让步,工程就发明了折中术——把数据按"被用到的可能性"分层摆放:越可能马上被用到的,放得离计算单元越近。程序访问数据有很强的局部性:刚用过的数据大概率马上再用,用过它旁边的数据大概率马上用旁边。 locality 在,金字塔就成立:绝大多数请求被顶层拦下,少数穿透到底层,整体表现得又快又大。

CK770 的存储层次从上到下六层,先把每层的量级和角色钉死。

层级 典型容量(CK770) 访问量级 归属与角色
处理器寄存器 每核几十个 零周期 指令的操作数暂存,编译器分配
一级缓存 每核几十 KB 一到几个周期 私有,拆分指令与数据两块
二级缓存 每簇几百 KB 十来个周期 簇内共享,一致性的中枢
片上紧耦合存储 数百 KB 十来个周期 物理地址直挂,无一致性逻辑
片外存储控制器 外接 GB 级 几十到上百周期 DDR 控制器统一调度
外部存储介质 更大 更慢 固件与文件系统,不属于运行层次

表里有个 newcomer 值得单独说:片上紧耦合存储。它长得像缓存,本质却是普通物理地址的静态存储器——没有命中判断、没有一致性协议、软件说了算。代价是软件要自己管放什么进去;好处是行为完全可预测,访问延迟是常数。实时任务(中断处理、采集循环)把工作数据钉在紧耦合存储里,就躲开了缓存未命中的不确定性。CK770 给小核簇配了一块紧耦合存储,专门安置采集循环的热数据,这个决定在第五章的实时性排错里立了大功。

图:存储金字塔与数据通路的解剖

图:存储金字塔与数据通路的解剖

容量怎么估:工作集方法

架构评审常出现这样的对话:"缓存多大合适?""越大越好。""多大是够?"然后冷场。够不够有个可操作的定义:工作集能装下,就是够。工作集指程序在一个调度周期内活跃读写的数据总量。估法是拿负载分类逐项列:采集循环的输入缓冲加输出缓冲、协议栈的套接字缓冲、推理模型的权重切片,按簇汇总,再乘一点二到一点五的安全系数。

CK770 的实际估算走一遍:采集循环的原始帧缓冲与处理缓冲合计百余 KB,钉在小核簇的紧耦合存储;协议栈套接字缓冲几十 KB 加推理权重切片,落在大核二级缓存;采集到推理的交接缓冲因为要跨簇交换,放片外存储,由 2.3 节的带宽账本管。三层答案对应三种归属,这就是容量估算的完整输出——不是一个数字,是一张带归属的清单

归属是比容量更重要的输出。缓冲区有三个属性必须写进架构文档:谁分配(决定它落在哪层)、谁独占(决定要不要一致性)、谁回收(决定生命周期边界)。上一节的加速器三件套里,描述符指向的缓冲区就要写明"加速器独占写、CPU 只读交接区",归属不清的缓冲区是多核系统最难查的一类故障——第五章的 CDC 排错案例里会见到它的变体。

片外存储控制器:带宽总闸

数据终究要落到片外大容量存储,从这层往上的每一级都只是它的缓存。片外存储控制器因此是全芯片带宽的总闸,它做三件事:把各主设备的读写请求排队调度、维护动态存储介质的刷新与预充电节拍、决定突发传输怎么切分。控制器调度策略对性能的影响不亚于互连——同样的请求流,好的调度能省下可观的等待时间。

架构阶段对控制器要做两个决定。一是位宽与速率,从带宽预算倒推:预算表(2.3 节)算出峰值带宽需求,加上三成余量,对照介质规格选型。二是服务质量配置:给实时域(采集、显示这类不能等的)留保障带宽,给尽力而为域(推理批处理这类慢点无妨的)吃剩余。CK770 就在这里栽过跟头——2.3 节的超支案例里,正是"推理批处理把实时采集的保障带宽挤掉"引发了第一次架构级返工,这里先按下不表。

容量之外还有一本带宽账:金字塔自上而下,各层的带宽也应逐级放大——底层若比上层还窄,未命中的代价就不再是延迟,而是整个通路的拥堵。核算方法与 2.3 节的预算表合流:每层的进出租户流量对齐该层的供给能力,任何一层"进水快于出水",堵的就是那一层。容量与带宽两本账对照着记,存储层次才算真正设计过,而不是照抄教科书画了个金字塔。

常见问题辨析

问:缓存行是什么,为什么对齐讨论都绕着它转?

缓存行是缓存与下层交换数据的最小单位,常见几十个字节。层次之间搬运不以变量为单位、而以缓存行为单位,这个粒度决定了一堆现象:相邻变量会被顺手一起装进缓存(空间局部性的物理载体);一个变量横跨两行会带来两次搬运;上一节说的假共享,本质是两个无关变量共享了同一行,作废粒度被迫扩大。软件侧的对策因此都很朴素——热数据按缓存行对齐、频繁写的量各自成行、跨核交接的结构体按行边界补齐。

问:数据写了缓存,什么时候真正落到内存?软件需要关心吗?

分写穿与写回两种策略。写穿是写操作同时更新缓存与下层,简单但占用带宽;写回是只改缓存、给该行记一个"脏"标记,等行被逐出时才落盘——带宽省了,代价是多一层不一致的窗口与更复杂的逐出逻辑。软件需要关心它,主要在两个场合:多核共享数据时要靠显式的同步指令强制可见,不能指望"写了就该看得见";对持久性有要求的场景(掉电保数据),要显式把脏数据刷到真正非易失的介质,缓存与片外存储控制器里的排队写都不算数。

问:紧耦合存储和缓存能不能并存各管一摊?

能,而且这正是 CK770 的用法。物理地址空间划分两条路:实时数据段直挂紧耦合存储,访问常数延迟、不参与一致性;其余地址走缓存层次。代价是软件要维护这张"什么放哪"的地图——链接脚本与运行时分配都要遵守。收益在第五章那个实时性案例里兑现:采集循环的数据从不受缓存未命中抖动,延迟可预测。判断准则依然是可预测性值不值软件管理成本,实时性要求越高答案越倾向值。

问:能不能把片外存储做快到取消中间层次?

物理上做不到,因为层次不是设计惰性的产物,而是距离与引脚的物理妥协。片外存储与处理器隔着封装、走线与连接器,信号要驱动大电容负载,速度上限比片内低一两个数量级;引脚数也封死了带宽天花板——3.2 节的串行化能把速率抬上去,但抬不掉访问延迟里的往返路程。缓存层次的全部意义,是把"绝大多数访问"留在近处完成,只让"必须出远门"的少数请求承担路途代价。层次会随工艺演化增减层数,但"快而小在近处、慢而大在远处"的骨架不会翻篇。

本节要点回顾

  • 存储层次的成立依赖访问局部性:按"被用到的可能性"分层摆放,顶层拦截绝大多数请求。
  • 六层结构的量级要背下来:寄存器、一级缓存、二级缓存、紧耦合存储、片外控制器、外部介质,逐层慢一个台阶、大一个台阶。
  • 容量估算输出的是带归属的清单,不是单一数字;归属三属性——谁分配、谁独占、谁回收——必须写进架构文档。
  • 紧耦合存储用可预测性换自动化,是实时任务的钉子户;片外控制器是带宽总闸,其服务质量配置在 2.3 节成为案例主角。

数据住址定好了,下一节看它们怎么在路上跑:互连、仲裁与那次著名的带宽超支。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U