【发布时间】:2016-09-15 16:55:58
【问题描述】:
似乎自己通过在 mm256 调用中键入 cij2 指针来修复它
所以_mm256_storeu_pd((double *)cij2,vecC);
我不知道为什么这会改变任何东西......
我正在编写一些代码并尝试利用英特尔手动矢量化。但是每当我运行代码时,我都会在尝试使用我的双 *cij2 时遇到分段错误。
if( q == 0)
{
__m256d vecA;
__m256d vecB;
__m256d vecC;
for (int i = 0; i < M; ++i)
for (int j = 0; j < N; ++j)
{
double cij = C[i+j*lda];
double *cij2 = (double *)malloc(4*sizeof(double));
for (int k = 0; k < K; k+=4)
{
vecA = _mm256_load_pd(&A[i+k*lda]);
vecB = _mm256_load_pd(&B[k+j*lda]);
vecC = _mm256_mul_pd(vecA,vecB);
_mm256_storeu_pd(cij2, vecC);
for (int x = 0; x < 4; x++)
{
cij += cij2[x];
}
}
C[i+j*lda] = cij;
}
我已将问题定位到 cij2 指针。如果我注释掉包含该指针的 2 行代码运行良好,它不会像它应该的那样工作,但它实际上会运行。
我的问题是为什么我会在这里遇到分段错误?我知道我已经正确分配了内存,并且内存是 256 个双精度向量,大小为 64 位。
在阅读了 cmets 之后,我来补充一些说明。 我做的第一件事是使用 malloc 将 _mm_malloc 更改为普通分配。不应该影响任何一种方式,但理论上会给我更多的喘息空间。
第二个问题不是来自分配的空返回,我添加了几个循环来增加数组并确保我可以修改内存而不会崩溃,所以我相对确定这不是问题。问题似乎源于将数据从 vecC 加载到数组。
最后我不能使用 BLAS 调用。这是一个并行类。我知道调用比我更聪明的方法会简单得多,但不幸的是,如果我尝试这样做,我会得到 0。
【问题讨论】:
-
我不确定
_mm_malloc(),但标准malloc()和calloc()在分配失败的情况下返回NULL。假设_mm_malloc()做同样的事情,您将无法检查这种可能性。如果发生这种情况,当您随后尝试使用指针时出现分段错误也就不足为奇了。 -
另一方面,我观察到
_mm256_storeu_pd()似乎需要一个 256 位对齐的指针,但您的分配只确保 64 位对齐。仅从文档来看,您似乎想使用_mm_malloc(4*sizeof(double), 256)进行分配。 -
@JohnBollinger:storeu_pd 是未对齐的存储。 store_pd 是对齐存储。 _mm_malloc 以字节而不是位为单位进行对齐 arg,因此 64 是 64 字节对齐的。 _mm_malloc 可能会失败,因为
cij2从未被释放。使用自动存储会更明智。 -
@PeterCordes, ... 这就是为什么我没有从我以前不熟悉的文档(显然不够充分)的阅读中做出答案。
-
此代码即使在您开始工作后也不会正常运行。在矩阵乘法的内部循环内的向量元素上编写标量循环绝对是可怕的。内部循环内的水平添加已经够糟糕了,但这样做很讨厌。特别是使用动态分配的缓冲区。使用 BLAS 库中经过良好调整的 DGEMM 函数,您将获得更好的结果。现代 CPU 的最佳矩阵乘法需要具有缓存感知能力,并且有很多技巧(例如,根据需要将一个数组部分转置)。我不建议你自己写。
标签: c pointers intrinsics