【发布时间】:2019-11-23 16:15:44
【问题描述】:
我编写了以下 C 函数,用于使用平铺/分块和 AVX 向量将两个 NxN 矩阵相乘以加快计算速度。现在,当我尝试将 AVX 内在函数与平铺结合时,我遇到了分段错误。知道为什么会这样吗?
另外,矩阵 B 是否有更好的内存访问模式?也许先转置它,甚至改变 k 和 j 循环?因为现在,我正在逐列遍历它,这在空间局部性和缓存行方面可能不是很有效。
1 void mmult(double A[SIZE_M][SIZE_N], double B[SIZE_N][SIZE_K], double C[SIZE_M][SIZE_K])
2 {
3 int i, j, k, i0, j0, k0;
4 // double sum;
5 __m256d sum;
6 for(i0 = 0; i0 < SIZE_M; i0 += BLOCKSIZE) {
7 for(k0 = 0; k0 < SIZE_N; k0 += BLOCKSIZE) {
8 for(j0 = 0; j0 < SIZE_K; j0 += BLOCKSIZE) {
9 for (i = i0; i < MIN(i0+BLOCKSIZE, SIZE_M); i++) {
10 for (j = j0; j < MIN(j0+BLOCKSIZE, SIZE_K); j++) {
11 // sum = C[i][j];
12 sum = _mm256_load_pd(&C[i][j]);
13 for (k = k0; k < MIN(k0+BLOCKSIZE, SIZE_N); k++) {
14 // sum += A[i][k] * B[k][j];
15 sum = _mm256_add_pd(sum, _mm256_mul_pd(_mm256_load_pd(&A[i][k]), _mm256_broadcast_sd(&B[k][j])));
16 }
17 // C[i][j] = sum;
18 _mm256_store_pd(&C[i][j], sum);
19 }
20 }
21 }
22 }
23 }
24 }
【问题讨论】:
-
@zx485:嗯?注意循环边界:内部循环在整个矩阵的 BLOCKSIZE 切片上,允许在 L1d 缓存中仍然很热的情况下重用数据。外部循环使用
+=BLOCKSIZE。但是,IIRC 应该只有 5 个嵌套循环,而不是 6 个,而且细节可能是错误的。 -
@zx485 好吧,
BLOCKSIZE有一个固定的(小)值,比如 8 或 16,而 N 可能要大得多。所以,它并不是真正的 O(N^6),但它应该是“通常的”O(N^3)。
标签: c performance matrix-multiplication simd avx