繁体   English   中英

并行化for循环并合并线程私有变量

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM