[英]Parallelizing for-loop and merging the thread private variables
我对如何使用 OpenMP 多线程来并行化我正在使用的这个 for 循环有点困惑。 在程序的这个程序部分中,我尝试从 arrays x 和 y 接收数据; 定义为:
x = (float*)aligned_alloc(32, sizeof(float) * n);
y = (float*)aligned_alloc(32, sizeof(float) * n);
其中 n 是大于 0 且可除以 16 的整数,然后将最大/最小 x/y 值保存在向量 maxX、minX、minY 和 maxY 中。 n 可以尽可能大,但在测试时我将 n 设为 360000000。
我试图与多线程并行化的 for 循环是
for(int i = 8; i < n; i+= 8 ){
__m256 vx = _mm256_load_ps(&x[i]);
__m256 vy = _mm256_load_ps(&y[i]);
minX = _mm256_min_ps(minX, vx);
maxX = _mm256_max_ps(maxX, vx);
minY = _mm256_min_ps(minY, vy);
maxY = _mm256_max_ps(maxY, vy);
}
其中 minX、maxX、minY 和 maxY 是用零填充的 _m256 个向量。
到目前为止,我的尝试让我让每个线程都有自己的私有临时变量,用于 minX、maxX、minY 和 maxY,在 for 循环中处理,然后尝试将私有变量合并到共享变量中在程序的rest中使用,像这样:
#pragma omp parallel num_threads(4)
{
__m256 TempMinX = _mm256_load_ps(&x[0]); //creaing private variables for each thread
__m256 TempMaxX = _mm256_load_ps(&x[0]);
__m256 TempMinY = _mm256_load_ps(&x[0]);
__m256 TempMaxY = _mm256_load_ps(&x[0]);
#pragma omp for
for (int i = 8; i < n; i += 8) {
__m256 vx = _mm256_load_ps(&x[i]); //loads the values from the x array
__m256 vy = _mm256_load_ps(&y[i]); //loads the values from the y array
TempMinX = _mm256_min_ps(TempMinX, vx);
TempMaxX = _mm256_max_ps(TempMaxX, vx);
TempMinY = _mm256_min_ps(TempMinY, vy);
TempMaxY = _mm256_max_ps(TempMaxY, vy);
}
/*section to merge thread private variables into
the shared variables by comparing the
values in vector minX with the threads private
vector Temp and saving the smalles/largest
values in the shared vector: */
#pragma omp critical
minX = _mm256_min_ps(minX, TempMinX);
#pragma omp critical
maxX = _mm256_max_ps(maxX, TempMaxX);
#pragma omp critical
minY = _mm256_min_ps(minY, TempMinY);
#pragma omp critical
maxY = _mm256_max_ps(maxY, TempMaxY);
运行此程序并将其与“未并行化”程序进行比较时,“未并行化”程序比我的“并行化”程序运行得更快。 我怀疑这可能与“合并”部分有关,其中不同的线程必须等待其他线程访问共享变量才能写入它,但到目前为止我还没有找到/想出任何好的解决方案关于如何解决这个问题并让它运行得更快......
最有可能的问题是关键区域的开销。
#pragma omp critical
minX = _mm256_min_ps(minX, TempMinX);
#pragma omp critical
maxX = _mm256_max_ps(maxX, TempMaxX);
#pragma omp critical
minY = _mm256_min_ps(minY, TempMinY);
#pragma omp critical
maxY = _mm256_max_ps(maxY, TempMaxY);
哪一个可以减少整个块的一个关键区域:
#pragma omp critical
{
minX = _mm256_min_ps(minX, TempMinX);
maxX = _mm256_max_ps(maxX, TempMaxX);
minY = _mm256_min_ps(minY, TempMinY);
maxY = _mm256_max_ps(maxY, TempMaxY);
}
或通过命名关键区域,即:
#pragma omp critical(region1)
minX = _mm256_min_ps(minX, TempMinX);
#pragma omp critical(region2)
maxX = _mm256_max_ps(maxX, TempMaxX);
#pragma omp critical(region3)
minY = _mm256_min_ps(minY, TempMinY);
#pragma omp critical(region4)
maxY = _mm256_max_ps(maxY, TempMaxY);
以这种方式,可以有多个线程同时执行不同的命名关键区域。
试试这两个版本,看看哪个版本的开销最小。
另一种方法,可能是性能更好的方法,您可以将这些私有变量添加到一个数组中,该数组将由并行区域外的主线程获取:
// create a arrays of size equal to the number of threads
#pragma omp parallel num_threads(4)
{
#pragma omp for
for (int i = 8; i < n; i += 8) {
...
}
int threadID = omp_get_thread_num();
array_minX[threadID] = TempMinX;
array_maxX[threadID] = TempMaxX;
array_minY[threadID] = TempMinY;
array_maxY[threadID] = TempMaxY;
}
// the master thread calculate the _mm256_min_ps of the array array_minX, and so on.
最后,您可以使用 OpenMP 4.0 用户定义的缩减来创建自己的缩减,这基本上是上述方法所做的,但不使用 OpenMP 内置功能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.