C 利用SSE矢量化在OpenMP中利用残差计算并行化内环
我正在尝试并行化一个程序的内部循环,该程序的数据依赖项(min)超出了循环的范围。我遇到了一个问题,剩余计算发生在内部j循环的范围之外。如果j循环中包含“#pragma omp parallel”部分,即使由于k值太低,循环根本没有运行,代码也会出错。比如说(1,2,3)C 利用SSE矢量化在OpenMP中利用残差计算并行化内环,c,openmp,sse,pragma,C,Openmp,Sse,Pragma,我正在尝试并行化一个程序的内部循环,该程序的数据依赖项(min)超出了循环的范围。我遇到了一个问题,剩余计算发生在内部j循环的范围之外。如果j循环中包含“#pragma omp parallel”部分,即使由于k值太低,循环根本没有运行,代码也会出错。比如说(1,2,3) for (i = 0; i < 10; i++) { #pragma omp parallel for shared(min) private (j, a, b, storer, arr) // fo
for (i = 0; i < 10; i++)
{
#pragma omp parallel for shared(min) private (j, a, b, storer, arr) //
for (j = 0; j < k-4; j += 4)
{
mm_a = _mm_load_ps(&x[j]);
mm_b = _mm_load_ps(&y[j]);
mm_a = _mm_add_ps(mm_a, mm_b);
_mm_store_ps(storer, mm_a);
#pragma omp critical
{
if (storer[0] < min)
{
min = storer[0];
}
if (storer[1] < min)
{
min = storer[1];
}
//etc
}
}
do
{
#pragma omp critical
{
if (x[j]+y[j] < min)
{
min = x[j]+y[j];
}
}
}
} while (j++ < (k - 1));
round_min = min
}
(i=0;i<10;i++)的
{
#pragma omp并行用于共享(最小)私有(j、a、b、storer、arr)//
对于(j=0;j
基于j
的循环是一个并行循环,因此不能在循环后使用j
。这一点尤其正确,因为您将j
显式地设置为private
,因此只能在线程中局部可见,而不能在并行区域之外。您可以在并行循环之后使用(k-4+3)/4*4
显式计算剩余j
值的位置
此外,这里有几个要点:
- 您可能真的不需要自己对代码进行矢量化:您可以使用
。OpenMP可以为您自动完成所有枯燥的剩余计算工作。此外,代码将是可移植的,并且更加简单。生成的代码也可能比您的代码快。但是请注意,有些编译器可能无法对代码进行矢量化(GCC和ICC可以,而Clang和MSVC通常需要一些帮助)omp simd reduce
- 关键部分(
)的成本非常高。在您的情况下,这将消除与并行部分相关的任何可能的改进。由于缓存线反弹,代码可能会变慢omp Critical
- 尽管某些编译器(如GCC)可能能够理解代码的逻辑并生成更快的实现(提取车道数据),但在这里读取由
编写的数据效率很低\u mm\u store\u ps
- 水平SIMD减少效率低下。使用垂直的,速度快得多,可以很容易地在这里使用
{
//假设min已在此处正确初始化
#pragma omp并行用于simd简化(最小:最小)专用(j)
对于(j=0;j
上述代码在GCC/ICC上的x86体系结构上正确矢量化(均使用
-O3-fopenmp
)、Clang(使用-O3-fopenmp-ffastmath
)和MSVC(使用/O2/fp:precise-openmp:experimental
).基于j
的循环是一个并行循环,因此不能在循环后使用j
。这一点尤其正确,因为您将j
显式地设置为private
,因此只能在线程中局部可见,而不能在并行区域之外。您可以在并行循环之后使用(k-4+3)/4*4
显式计算剩余j
值的位置
此外,这里有几个要点:
- 您可能真的不需要自己对代码进行矢量化:您可以使用
。OpenMP可以为您自动完成所有枯燥的剩余计算工作。此外,代码将是可移植的,并且更加简单。生成的代码也可能比您的代码快。但是请注意,有些编译器可能无法对代码进行矢量化(GCC和ICC可以,而Clang和MSVC通常需要一些帮助)omp simd reduce
- 关键部分(
)的成本非常高。在您的情况下,这将消除与并行部分相关的任何可能的改进。由于缓存线反弹,代码可能会变慢omp Critical
- 尽管某些编译器(如GCC)可能能够理解代码的逻辑并生成更快的实现(提取车道数据),但在这里读取由
编写的数据效率很低\u mm\u store\u ps
- 水平SIMD减少效率低下。使用垂直的,速度快得多,可以很容易地在这里使用
{
//假设min已在此处正确初始化
#pragma omp并行用于simd简化(最小:最小)专用(j)
对于(j=0;j
上述代码在GCC/ICC上的x86体系结构上被正确矢量化(均使用
-O3-fopenmp
)、Clang(使用-O3-fopenmp-ffastmath
)和MSVC(使用/O2/fp:precise-openmp:experimental
)。您能更具体地说明您遇到了什么错误吗?这些是编译时错误还是得到了错误的结果?我的第一个想法是,在min
变量上有一个竞争条件,因此显而易见的解决方案是reduce(min:min)
子句,您必须将其添加到parallel for
指令中。您只需使用\u mm\u min\u ps
获得4个最小值的向量,并将其减少到末尾的一个元素(a