参考:
9.8. Scratch Space (Private)
Scratch (thread-private memory) is an area of memory defined by the aperture registers. When an address falls in scratch space, additional address computation is automatically performed by the hardware. The kernel must provide additional information for this computation to occur in the form of the FLAT_SCRATCH register.
The FLAT_SCRATCH address is automatically sent with every FLAT request.
FLAT_SCRATCH is a 64-bit, byte address. The shader composes the value by adding together two separate values: the base address, which can be passed in via an initialized SGPR, or perhaps through a constant buffer, and the per-wave allocation offset (also initialized in an SGPR).
Scratch 内存是一个在GPU编程,特别是AMD GCN/Vega架构中非常关键的概念。Scratch 内存 ,也常被称为私有内存 ,是一种基于片上SRAM的高效可编程暂存式内存 。它的核心作用是解决GPU大量并行线程在处理复杂计算任务时,面临的私有数据暂存与局部性优化问题。
为了更好地理解,我们可以将其与CPU架构和GPU的其他内存类型进行类比:
| 内存类型 | 在GPU架构中的角色 | 最接近的CPU概念 | 特性与用途 |
|---|---|---|---|
| Scratch 内存 | 线程私有内存 | CPU的L1缓存/栈 | 为单个线程 私有,用于存储该线程的局部变量、临时数组、寄存器溢出数据。低延迟、高带宽。 |
| LDS | 线程组共享内存 | CPU的手动管理SRAM | 被一个线程组(CU)内所有线程共享,用于线程间的通信和数据交换。 |
| 全局内存 | 设备全局内存 | CPU的主内存(DRAM) | 所有线程组都可访问,容量大但延迟高。用于存储输入、输出和大型全局数据。 |
Scratch 内存的技术原理详解
-
定位与归属
-
地址空间 :在AMD GCN架构中,Scratch内存拥有独立的地址空间。编程时,可以使用特定的指令(如
scratch_load、scratch_store)来访问它。 -
物理介质 :它的物理载体是每个计算单元内部的片上SRAM。这决定了其访问速度远快于在片外的全局内存(如HBM或GDDR)。
-
-
工作原理与地址映射
-
Wavefront私有 :在GCN架构中,线程以Wavefront(波前,通常包含64个线程)为单位进行调度和执行。
-
基地址+偏移 :每个Wavefront在Scratch内存中都会被分配一块连续的地址区域 。当一个线程(例如,Wavefront中的第5个线程)要访问Scratch时,其访问的物理地址是由该Wavefront的Scratch基地址 加上一个线程ID相关的偏移量构成的。
-
目的 :这种映射方式确保了同一个Wavefront内不同线程的Scratch内存访问是互不干扰的,完美实现了数据的私有化。
-
-
核心功能与用途
-
寄存器溢出
-
问题:每个GPU线程都有大量的寄存器。但当程序非常复杂(例如,有很深的循环嵌套或许多局部变量),所需的寄存器数量超过硬件物理寄存器上限时,编译器会选择将一些不常用的变量"溢出"到内存中。
-
解决方案 :Scratch内存是存放这些"溢出"变量的首选之地。因为与溢出到全局内存相比,使用Scratch内存的性能损失要小得多。
-
-
大型栈帧或私有数组
-
当线程的函数调用栈很深,或者需要分配一个私有的大数组(例如,用于计算的临时缓冲区)时,这些数据无法全部放入有限的寄存器中。
-
Scratch内存为这些数据提供了高速的暂存空间。
-
-
动态索引的局部变量
-
如果线程有一个局部数组,并且其索引是在运行时动态计算(非编译时常量)的,编译器通常无法使用寄存器来存储它。
-
这种情况下,该数组也会被分配到Scratch内存中。
-
-
为什么Scratch内存至关重要?
-
性能关键
- 避免了将线程的私有数据(尤其是寄存器溢出的数据)直接写入高延迟的全局内存,从而极大地提升了程序的执行效率。
-
正确性保证
- 它确保了线程的私有数据不会被其他线程意外修改,这是编写正确、可靠的并行程序的基础。
-
编程模型支持
- 在高级编程模型(如OpenCL或HIP)中,当你在内核函数中声明一个大的私有数组(例如
int temp[100];)时,编译器在背后自动将其映射到Scratch内存空间进行分配和访问。
- 在高级编程模型(如OpenCL或HIP)中,当你在内核函数中声明一个大的私有数组(例如
总结
Scratch内存是AMD GPU架构中一种专为单个线程设计的高速、私有、片上暂存内存。 它主要解决了寄存器溢出和大型线程私有变量的存储问题,通过将这些数据保留在片上的SRAM中,而不是抛向缓慢的全局内存,从而在维持GPU大规模并行计算能力的同时,有效提升了单个线程的执行效率和整体程序的性能。
gpu 文档中看到的"Scratch load/store"等指令,就是GPU在汇编级别直接操作这片关键内存区域的体现。