我正在学习Apple的Metal尝试进行GPU计算。
我检查了Apple提供的matrix multiplication example。我无法理解这一点。
中// Number of rows in matrices A and C.
@property (nonatomic) uint16_t m;
// Number of columns in matrix A; number of rows in matrix B.
@property (nonatomic) uint16_t n;
// Number of columns in matrices B and C.
@property (nonatomic) uint16_t k;
// Output matrix (padded) C row count
@property (nonatomic, readonly) uint16_t M;
// Output matrix (padded) C column count
@property (nonatomic, readonly) uint16_t K;
// Output matrix C = A x B
@property (nonatomic, readonly) float* output;
它说Matrix C是填充的。我不清楚pad
在这里的含义。它是某种对齐方式吗?因为我知道Metal的着色器语言规范中有类型对齐,但我不知道为什么我们需要填充缓冲区。
感谢。
答案 0 :(得分:4)
它与优化内存访问有关。您的GPU有许多线程组,每个线程组包含相对少量的专用内存(几KB),可以非常快速地访问。这与GPU的主内存是分开的,后者可能是几GB相对较慢的内存。
由于所有3个矩阵(A
,B
和C
)不太可能适合单个线程组的内存,并且回归到主内部循环中的内存非常慢,我们将计算分为" blocks"或部门。想象一下将结果矩阵C
划分为一个网格,其中每个扇区是8 x 8个元素的集合:然后我们可以指示Threadgroup 1计算左上角扇区的结果,而其他线程组同时计算其他扇区。在这种情况下,线程组1只需要A
的前8行和B
的前8列来计算C
的部分。这意味着我们可以向Threadgroup 1发送更少量的数据,使其保持在缓存限制之内。
Metal要求我们填充矩阵的原因是它可以将C
划分为完美的网格。如果您的真实结果矩阵为12 x 18,扇区大小为8 x 8,则表示C
为1.5 x 2.25扇区。 GPU无法在部分扇区上高效运行,因此您必须用零填充矩阵以达到整数 - 在这种情况下为2 x 3扇区或16 x 24个元素。您牺牲了一点存储空间和更多的时钟周期来进行高度优化的并行处理。