将OpenMP应用于C++中的特定嵌套循环

CIV*_*I89 2 c++ parallel-processing multithreading nested openmp

我在使用openmp并行化一段代码时遇到了问题,我认为某些操作存在概念性问题,必须按顺序进行.

else if (PERF_ROWS <= MAX_ROWS && function_switch == true)
{
    int array_dist_perf[PERF_ROWS];
    int array_dist[MAX_ROWS];

    #pragma omp parallel for collapse(2)
    for (int i = 0; i < MAX_COLUMNS;
                    i = i + 1 + (i % PERF_CLMN == 0 ? 1:0))
    {
        for (int j = 0; j < PERF_ROWS; j++) //truncation perforation
        {
            array_dist_perf[j] = abs(input[j] - input_matrix[j][i]);
        }

        float av = mean(PERF_ROWS, array_dist_perf);

        float score = score_func(av);

        if (score > THRESHOLD_SCORE)
        {
            for (int k = 0; k < MAX_ROWS; k++)
            {
                array_dist[k] = abs(input[k] - input_matrix[k][i]);
            }

            float av_real = mean(MAX_ROWS, array_dist);

            float score_real = score_func(av_real);

            rank_function(score_real, i);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

错误是"折叠的循环没有完全嵌套".我在g ++ - 5上使用Clion.提前致谢

Hri*_*iev 5

首先,完美嵌套的循环具有以下形式:

for (init1; cond1; inc1)
{
   for (init2; cond2; inc2)
   {
      ...
   }
}
Run Code Online (Sandbox Code Playgroud)

请注意,外环的主体仅由内环组成,而不包含任何其他内容.对于你的代码来说绝对不是这样 - 你在内循环之后还有很多其他语句.

其次,您的外部循环不是OpenMP所需的规范形式.Canonical是循环,其迭代次数和迭代步骤可以容易地预先确定.既然你在做什么是跳过迭代,每次i是的倍数PERF_CLMN,你可以重写循环为:

for (int i = 0; i < MAX_COLUMNS; i++)
{
    if (i % PERF_CLMN == 1) continue;
    ...
}
Run Code Online (Sandbox Code Playgroud)

这将根据是否MAX_COLUMNS是线程数的倍数来创建工作不平衡.但还有另一个来源或不平衡,即有条件的评估rank_function().因此,您应该使用动态调度.

现在,显然两个array_dist*循环都是私有的,它们不在你的情况下,这将导致数据竞争.在循环体内移动数组的定义或使用该private()子句.

#pragma omp parallel for schedule(dynamic) private(array_dist_perf,array_dist)
for (int i = 0; i < MAX_COLUMNS; i++)
{
    if (i % PERF_CLMN == 1) continue;
    ...
}
Run Code Online (Sandbox Code Playgroud)

现在,对于一些未经请求的优化建议:两个内部循环是冗余的,因为第一个循环基本上是第二个工作的子集.您可以通过仅使用单个数组来优化计算并节省内存,并让第二个循环从第一个循环结束的位置继续.代码的最终版本应如下所示:

else if (PERF_ROWS <= MAX_ROWS && function_switch == true)
{
    int array_dist[MAX_ROWS];

    #pragma omp parallel for schedule(dynamic) private(array_dist)
    for (int i = 0; i < MAX_COLUMNS; i++)
    {
        if (i % PERF_CLMN == 1) continue;

        for (int j = 0; j < PERF_ROWS; j++) //truncation perforation
        {
            array_dist[j] = abs(input[j] - input_matrix[j][i]);
        }

        float av = mean(PERF_ROWS, array_dist);

        float score = score_func(av);

        if (score > THRESHOLD_SCORE)
        {
            for (int k = PERF_ROWS; k < MAX_ROWS; k++)
            {
                array_dist[k] = abs(input[k] - input_matrix[k][i]);
            }

            float av_real = mean(MAX_ROWS, array_dist);

            float score_real = score_func(av_real);

            rank_function(score_real, i);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

优化的另一个潜力在于input_matrix不能以缓存友好的方式访问.转置它将导致列数据连续存储在内存中并改善内存访问位置.