C omp simd缩减无加速
我试图使用矢量化(openmp simd)来加速矩阵乘法。为了利用矢量化,我转置了第二个矩阵(使变化最快的索引遍历连续内存)。我正在3000 x 3000阵列上运行测试。因为我无法测量有和没有open-mp-pragma时的墙时间差异,所以我想确认,对于我正在乘法的单个阵列,我实际上得到了一个加速比(事实并非如此)。因此,我插入了一些大小相同的虚拟数组,以检查它们是否得到了SIMD的加速(至少在使用reduction子句时是这样) 现在我的问题是,阻碍SIMD加速的问题是什么?我唯一的猜测是,这一定是阵列的二维特性,但我不完全明白这会导致减速的原因 或者我的代码中是否存在另一个我看不到的问题C omp simd缩减无加速,c,performance,parallel-processing,openmp,simd,C,Performance,Parallel Processing,Openmp,Simd,我试图使用矢量化(openmp simd)来加速矩阵乘法。为了利用矢量化,我转置了第二个矩阵(使变化最快的索引遍历连续内存)。我正在3000 x 3000阵列上运行测试。因为我无法测量有和没有open-mp-pragma时的墙时间差异,所以我想确认,对于我正在乘法的单个阵列,我实际上得到了一个加速比(事实并非如此)。因此,我插入了一些大小相同的虚拟数组,以检查它们是否得到了SIMD的加速(至少在使用reduction子句时是这样) 现在我的问题是,阻碍SIMD加速的问题是什么?我唯一的猜测是,这
#包括
#包括
#包括
#包括
常数int N=3000;
结构timespec开始、结束;
双**创建_a(){
double*a=(double*)对齐(32,sizeof(double)*N*N);
double**a_index=(double**)aligned_alloc(32,sizeof(double*)*N);
对于(inti=0;i我已经在我的机器上测试了前两个循环,并且我可以重现相同的行为
Time simd reduce measured: 0.000006000 seconds.
time2 (simd reduction): 0.000004000 seconds.
我猜有两个问题:
第一个问题:
多版本的执行时间之间的差异似乎更多地与缓存有关,而不是与矢量化有关。因此,当您使用3000个元素(24 KB)的虚拟数组进行测试时:
通过将第一行矩阵a
和b_t
分别打包为两个新矩阵a_2
和b_2
,即:
for(int i = 0; i < N; i++){
a_2[0][i] = a[0][i];
bt_2[0][i] = b_t[0][i];
}
// problematic calculation that I can't get to speed up no matter what pragma I use
clock_gettime(CLOCK_REALTIME, &begin);
#pragma omp simd aligned(a_2, bt_2) reduction(+:cell_res)
for (int i = 0; i < N; i++) {
cell_res += a_2[0][i] * bt_2[0][i];
}
在我看来,您不应该在同一个函数中测试所有这些循环,因为编译器可能会以不同的方式优化这些循环,然后存在缓存这些值等问题。我会在单独的运行中测试它们
现在我的问题是,阻碍SIMD的问题是什么
加速我唯一的猜测是它一定是
数组但我不完全明白这会导致减速的原因
我还通过直接将第一行矩阵a
和b_t
打包到单独的1D数组(而不是矩阵)进行了测试,但结果完全相同。考虑到它的价值。现在您应该在您的环境中进行配置,即测试缓存未命中
更重要的是,测试此版本:
clock_gettime(CLOCK_REALTIME, &begin);
for (int i = 0; i < N; i++) {
cell_res += a[0][i] * b_t[0][i];
}
clock_gettime(CLOCK_REALTIME, &end);
内存受限,因此使用SIMD
获得增益的机会较少,不应使用双精度浮点积的SIMD
。解决方法是将矩阵从双精度变为浮点,从而将必要的内存带宽减少到一半,并将SIMD
操作的数量增加一倍尽管如此,前面提到的代码片段仍然是内存受限的。尽管如此,您可能会获得一些收益,主要是当值在缓存中时
在我的机器中,从双循环更改为浮动,使SIMD
版本明显比没有它的版本快,即使不使用包装。这可能也是您遇到的问题。我已经在我的机器上测试了前两个循环,我可以重现相同的行为
Time simd reduce measured: 0.000006000 seconds.
time2 (simd reduction): 0.000004000 seconds.
我猜有两个问题:
第一个问题:
多版本的执行时间之间的差异似乎更多地与缓存有关,而不是与矢量化有关。因此,当您使用3000个元素(24 KB)的虚拟数组进行测试时:
通过将第一行矩阵a
和b_t
分别打包为两个新矩阵a_2
和b_2
,即:
for(int i = 0; i < N; i++){
a_2[0][i] = a[0][i];
bt_2[0][i] = b_t[0][i];
}
// problematic calculation that I can't get to speed up no matter what pragma I use
clock_gettime(CLOCK_REALTIME, &begin);
#pragma omp simd aligned(a_2, bt_2) reduction(+:cell_res)
for (int i = 0; i < N; i++) {
cell_res += a_2[0][i] * bt_2[0][i];
}
在我看来,您不应该在同一个函数中测试所有这些循环,因为编译器可能会以不同的方式优化这些循环,然后存在缓存这些值等问题。我会在单独的运行中测试它们
现在我的问题是,阻碍SIMD的问题是什么
加速我唯一的猜测是它一定是
数组但我不完全明白这会导致减速的原因
我还通过直接将第一行矩阵a
和b_t
打包到单独的1D数组(而不是矩阵)进行了测试,但结果完全相同。考虑到它的价值。现在您应该在您的环境中进行配置,即测试缓存未命中
更重要的是,测试此版本:
clock_gettime(CLOCK_REALTIME, &begin);
for (int i = 0; i < N; i++) {
cell_res += a[0][i] * b_t[0][i];
}
clock_gettime(CLOCK_REALTIME, &end);
内存受限,因此使用SIMD
获得增益的机会较少,不应使用双精度浮点积的SIMD
。解决方法是将矩阵从双精度变为浮点,从而将必要的内存带宽减少到一半,并将SIMD
操作的数量增加一倍尽管如此,前面提到的代码片段仍然是内存受限的。尽管如此,您可能会获得一些收益,主要是当值在缓存中时
在我的机器中,从double改为float,使得SIMD
版本明显比没有它的版本快,即使没有使用包装。这也可能是您遇到的问题
clock_gettime(CLOCK_REALTIME, &begin);
for (int i = 0; i < N; i++) {
cell_res += a[0][i] * b_t[0][i];
}
clock_gettime(CLOCK_REALTIME, &end);
for (int i = 0; i < N; i++) {
cell_res += a[0][i] * b_t[0][i];
}