Page 47 - 《软件学报》2025年第9期
P. 47

3958                                                       软件学报  2025  年第  36  卷第  9  期


                 能. 缓存端口是通信事务处理的主体, 一致性协议则规定了通信处理的状态机, 缓存结构负责缓存的数据如何存储
                 并且将缓存底层通用的应用编程接口             (application programming interface, API) 暴露给端口, 供端口上的事务通信
                 调用. 由于本文的目标是设计一个支持多种一致性协议和缓存结构并且可配置、易修改的缓存模拟器, 因此将以
                 上  3 部分进行了功能抽象并把它们打包为不同的模块, 之后便可以通过模块间的堆叠组成最终的缓存模块. 如图                                1
                 所示, 一个支持一致性协议的缓存           (coherent cache) 由通信内侧端口  (inner)、通信外侧端口    (outer)、一致性协议
                 (policy) 和缓存存储结构   (cache) 这  4  个模块组成, 其中内侧端口和外侧端口负责传递、处理和转发消息. 此外, 内
                 存作为最底层的“缓存”, 同样包含一个内侧端口.



                                                Coherent
                                                 cache    Inner

                                                                   Policy
                                                  Cache


                                                          Outer



                                                  图 1 Coherent cache 结构图

                 2.1   通信端口

                    内侧端口和外侧端口是上下级缓存              (内存) 进行通信的端口以及通信事务的处理者. 上级缓存作为主节点
                 (master), 它的外侧端口与作为从节点       (slave) 的下级缓存的内侧端口相连接并进行通信. 在一致性缓存内部, 内侧
                 端口还会向外侧端口发起事务请求并由其转发给下级缓存的内侧端口. 内侧端口和外侧端口在处理通信事务时会
                 根据事务的类型查询一致性协议, 以决定如何和上/下级缓存进行交互                      (如是否向下级缓存发起请求), 以及如何操
                 作底层的缓存存储结构        (如是否将指定的元数据失效). 后文图           2  完整展示了一个包含两个处理器核和三级缓存的
                 系统, 每个处理器核都有一个专有的指令缓存和数据缓存. 由于指令缓存只读不写, 因此指令缓存被简化为不参与
                 缓存一致性的缓存, 其与下级缓存的通信也只支持基本的读操作. 为了准确模拟指令缓存的这一行为, FlexiCAS
                 可将对应的缓存外侧端口设置为不支持一致性的模式, 即不接受从下级缓存发出的探测请求, 不参与整个系统的
                 一致性通信.

                 2.1.1    通信协议
                    本文参考开源      RISC-V  处理器  Rocket-Chip  [30] 和片上系统  Chipyard [31] 中所使用的  TileLink  一致性协议的端口
                 设计以及命名格式       [32] , 详细阐述了上下级缓存    (内存) 的内外侧端口通信时使用的消息类型、通信的方向以及它
                 们的功能   (表  3). 获取  (acquire) 请求用于上级缓存发生不命中或者想升级缓存块的权限时使用                 (如从共享   (S) 状态
                 升级为修改状态      (M)), 授予  (grant) 则将请求的缓存块的数据返回给上级缓存. 探测            (probe) 可以用于维持上下级
                 缓存的包含性关系. 以包含性的缓存为例, 下级缓存的缓存块被驱逐出缓存时, 需要向上级缓存发起探测请求将对
                 应地址的缓存块无效掉. 写回         (writeback) 用于将上级缓存中发生了写请求的脏数据块写回到下级缓存                   (内存) 中.
                 冲刷  (flush) 会将对应的缓存块无效掉并将冲刷的消息传递给下级缓存. 但对于指令缓存这一类不参与一致性的
                 缓存, 它不会向下级缓存发起写回和冲刷请求, 也接受不到下级缓存的探测请求. 完成                          (finish) 被上级缓存用于通
                 知下级缓存获取请求事务的结束. 末级缓存              (last level cache, LLC) 和内存间只需支持读写操作.
                    除了上下级缓存       (内存) 需要通信外, 一级缓存还需要与处理器核进行通信. 表                4  详细阐述了处理器核和一级
                 缓存通信的消息类型、携带的参数以及它们对应的功能. 其中冲刷操作对应                         x86-64  指令集中的  clflush  指令. 指令
                 缓存无需支持写和写回操作. 在处理冲刷缓存请求时, 指令缓存采用选择性冲刷策略, 仅清除指令数据而非整个缓
                 存内容. 这为实现内存屏障        (memory fence) 等同步指令提供了支持.
   42   43   44   45   46   47   48   49   50   51   52