跳转至

GPGPU存储架构

CPU的层次化存储回顾

 CPU 存储系统中广泛采用的层次化存储结构如上图所示,该结构呈现出典型的 “正三角”金字塔结构 。不同存储介质有着不同的存储特性: 顶部的存储介质离运算器近,速度快,但电路开销大,所以数量少,容量小;而底部的存储介质离运算器远,速度慢,但电路开销低,所以具有更大的容量。正是借助层次化的结构,通过合理的数据布局管理,为编程人员制造出存储系统容量又大速度又快的“假象”, 并在实际应用中成功地起到了加速数据访问的效果。

GPGPU 的存储层次

与 CPU 存储系统结构类似, GPGPU 的存储系统也采用了层次化的结构设计,通过充分利用数据的局部性来降低片外存储器的访问开销。但为了满足 GPGPU 核心的 SIMT 大规模线程并行, GPGPU 遵循吞吐率优先的原则,因此其存储系统也与 CPU 有着明显区别。二者的差异主要体现在存储器容量、结构组成和访问管理上。

 CUDA 和 OpenCL 的编程模型将 GPGPU 的存储大致分为寄存器文件、 L1 数据缓存/共享存储器、 L2 缓存和全局存储器等。 虽然各个层次与 CPU 中对应层次所采用的器件类型大体相同,但 GPGPU 中存储层次的设计与 CPU 却明显不同。 从上图中可以看到, GPGPU 每个可编程多处理器中寄存器文件的容量显著高于 L1 缓存和共享存储器,呈现出与 CPU 截然相反的“倒三角”结构,这种 “倒三角”结构 是 GPGPU 存储系统的一个显著特点。

 GPGPU 的寄存器文件采用如此大容量的设计,主要是为了满足线程束的零开销切换。由于每个流多处理器能够同时支持的线程束数量很多,为了支持线程束的灵活切换以掩藏如缓存缺失等长延时操作,需要将活跃线程束的上下文信息,尤其是寄存器的内容都保存在寄存器文件中。 如果寄存器资源减少,当线程的寄存器需求超过寄存器文件的物理容量时,则需要在全局存储器中分配一些局部存储空间给这些额外的寄存器使用, 这种现象被称为“寄存器溢出”。寄存器溢出操作往往会导致显著的性能下降, 因此从性能方面考虑, GPGPU 不得不采取大容量的寄存器文件设计。

 除了容量上的差别, GPGPU 的访存操作呈现出高度并行化的特点。由于 GPGPU 以线程束为粒度执行,因此对每一个线程束的数据访问操作都会尽可能利用空间并行性来合并请求或者广播所需要的数据,从而提高访问的效率。例如 L1 数据缓存和全局存储器的访问都有各自的地址合并访问规则,这往往需要硬件上配备专门的访问合并单元来支持线程访问请求的在线合并。

 GPGPU 的访存行为还体现出更为精细的片上存储管理特点。 GPGPU 可以选择共享存储器、 L1 数据缓存、纹理缓存、常量缓存等不同的存储空间来存储数据, 还可以在保证总容量不变的情况下灵活地调节共享存储器和 L1 数据缓存的大小。很多 GPGPU 还可以指定数据在 L1 数据缓存中的缓存策略。这些都让程序员可以根据不同应用的特点实施更加精细化的存储管理。

 随着每代 GPGPU 硬件的迭代, 存储系统的架构也随之不断演变,因此很难给出一个具体的硬件结构描述,但大都符合 CUDA 和 OpenCL 编程模型中多种存储空间的抽象。