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_x
和 z_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 无明显改善的主要内容,如果未能解决你的问题,请参考以下文章