C++ omp 无明显改善

Posted

技术标签:

【中文标题】C++ omp 无明显改善【英文标题】:C++ omp no significant improvement 【发布时间】:2020-02-19 01:11:36 【问题描述】:

我在 MSVC 2019 上使用默认编译器。我正在处理的代码是 Mandelbrot 图像。我的代码的相关部分如下所示:

#pragma omp parallel for
for (int y = 0; y < HEIGHT; y++)
    
       for (int x = 0; x < WIDTH; x++)
             
               unsigned int retVal = mandel(x_val + x_incr * x, y_val + y_incr * y);
               mtest.setPixels(x, y,
                        static_cast<unsigned char>(retVal / 6),
                        static_cast<unsigned char>(retVal / 5),
                        static_cast<unsigned char>(retVal / 4));

            
     

循环外的所有变量都是 constexpr,消除了任何依赖。 mandel 函数每次调用大约进行 1000 次迭代。我希望外部循环在多个线程上运行,但我的 msvc 记录每个运行大约 5-6 秒,有或没有 omp 指令。

编辑(曼德尔函数):

unsigned int mandel(long double x, long double y)

    long double z_x = 0;
    long double z_y = 0;

    for (int i = 0; i < ITER; i++)
    
        long double temp = z_x;
        z_x = (z_x * z_x) - (z_y * z_y) + x;
        z_y = 2 * temp * z_y + y;

        if ((z_x * z_x + z_y * z_y) > 4)
            return i;
    
    return ITER; //ITER is a #define macro

【问题讨论】:

setPixels 阻塞(互斥体、流、GPU 资源等)吗? mtest 是什么?探查器是怎么说的? setPixels 除了访问数组并根据 x 和 y 位置对其进行编辑之外,没有其他实现。它是一个一维数组。 我没有使用分析器(不知道如何在 msvc 中执行此操作)。但是有和没有 pragma 指令的一些观察显示没有任何改进。 更改for 循环的顺序有帮助吗?此外,您的 mandel 循环效率非常低,计算 z_x * z_xz_y * z_y 以将它们与 4 进行比较,然后在下一次迭代中重新计算这些相同的值。在第一次迭代中,您不必要地将两个零平方。 我可能会改变它,但这会改变缓存步幅。我只是想看看 omp 在不涉及太多外部元素的情况下是否具有性能优势。 【参考方案1】:

根据循环中的 if 条件是否满足,您的 mandel 函数的运行时成本会有很大差异。因此,循环的每次迭代都将在不同的时间运行。默认情况下 omp 使用静态调度 (即,将循环分成 N 个分区)。这有点糟糕,因为您没有适合静态调度的工作负载。看看使用动态调度时会发生什么。

#pragma omp parallel for schedule(dynamic, 1)
for (int y = 0; y < HEIGHT; y++)
    
       for (int x = 0; x < WIDTH; x++)
             
               unsigned int retVal = mandel(x_val + x_incr * x, y_val + y_incr * y);
               mtest.setPixels(x, y,
                        static_cast<unsigned char>(retVal / 6),
                        static_cast<unsigned char>(retVal / 5),
                        static_cast<unsigned char>(retVal / 4));

            
     

也是时候排除真正愚蠢的东西了.....

    您是否在程序中至少包含一次 omp.h? 您是否在项目设置中启用了 omp?

IIRC,如果你还没有做这两件事, omp 将在 MSVC 下被禁用。

【讨论】:

我很笨,不知道您必须包含这些标题并通过设置启用它。自从我最初编写此代码以来,情况发生了变化,我会在有机会时对其进行测试。【参考方案2】:

这不是答案,但请这样做:

unsigned int mandel(long double x, long double y)

    long double z_x = 0;
    long double z_y = 0;
    long double z_x_squared = 0;
    long double z_y_squared = 0;

    for (int i = 0; i < ITER; i++)
    
        long double temp = z_x;
        z_x = z_x_squared - z_y_squared + x;
        z_y = 2 * temp * z_y + y;

        z_x_squared = z_x * z_x;
        z_y_squared = z_y * z_u;

        if ((z_x_squared + z_y_squared) > 4)
            return i;
    
    return ITER; //ITER is a #define macro

另外,请尝试颠倒两个 for 循环的顺序。

【讨论】:

long double 真的有必要吗?

以上是关于C++ omp 无明显改善的主要内容,如果未能解决你的问题,请参考以下文章

Effective C++:改善程序与设计的55个具体做法

C11关键字&字面值改善

无明显原因的分段错误

无明显原因的方向更改后应用程序崩溃

有什么方法可以改善构建/编译时间?

改善程序与设计的55个具体做法 day2