C++ OpenMP 和 gcc 4.8.1 - 并行化循环时的性能问题

标签 c++ gcc mingw openmp

我最近开始研究 OpenMP,因为我将从事一些计算量大的图像分析项目。我使用带有 Intel i7(8 核)和 mingw64 gcc 4.8.1 的 Windows 7。我在 Code::Blocks 中编写代码并设置所有内容以便编译和运行它。在我的代码的几个部分,我将做一些像素级的操作,我认为这将是并行处理的一个很好的候选者。令我惊讶的是,事实证明顺序处理比并行处理更快。我在两台不同的计算机上为 32 位和 64 位尝试了不同版本的 gcc (4.7 - 4.8),但我总是遇到相同的性能问题。然后我尝试使用我在这两台计算机中的一台上使用的旧 Visual Studio 2008 运行它,我得到了预期的性能提升。因此,我的问题是——为什么我无法使用 gcc 看到相同的效果。我做错了什么吗?

这是一个最小的工作示例。

#include <omp.h>
#include <cstdlib>
#include <iostream>

int main(int argc, char * argv[])
{
   /* process a stack of images - set the number to 1000 for testing */
   int imgStack = 1000;

   double start_t = omp_get_wtime();
   for (int img = 0; img < imgStack; img++)
   {
      omp_set_num_threads(8);
      #pragma omp parallel for default(none)
      for (int y = 0; y < 1000000000; y++) /* increased the number of pixels to make it worthwhile and to see a difference*/
      {
         for (int x = 0; x < 1000000000; x++)
         {
            unsigned char pixel[4];
            pixel[0] = 1;
            pixel[1] = 2;
            pixel[2] = 3;
            pixel[3] = 4;

            /* here I would do much more but removed it for testing purposes */

         }
      }
   }
   double end_t = (omp_get_wtime() - start_t) * 1000.0;
   std::cout << end_t << "ms" << std::endl;

   return 0;
}

在构建日志中我有以下内容

x86_64-w64-mingw32-g++.exe -Wall -O2 -fopenmp -c C:\Code\omptest\main.cpp -o obj\Release\main.o
x86_64-w64-mingw32-g++.exe -o bin\Release\omptest.exe obj\Release\main.o -s C:\mingw-builds\x64-4.8.1-posix-seh-rev5\mingw64\bin\libgomp-1.dll

输出如下

for 1 thread :   43ms
for 8 threads:  594ms

我还尝试关闭优化 (-O0),以防编译器展开某些循环。我读到了有关错误共享的问题,因此我将循环中的所有变量都保留为私有(private),以确保这不是问题所在。我不擅长分析,所以我无法判断底层发生了什么,例如导致所有线程等待的内部锁。

我不知道我在这里做错了什么。

- 编辑-

谢谢大家。在我的真实代码中,我有一个包含 2000 张图像的图像堆栈,每张图像的大小为 2000x2000 像素。我试图简化示例,以便每个人都可以轻松重现该问题,其中我简化了太多导致其他问题的后果。你们都完全正确。 在我的真实代码中,我使用 Qt 打开和显示我的图像,以及我自己的图像管理器,它加载和迭代堆栈以一次给我一张图像。我认为提供整个样本会太多而且会使事情复杂化(即不提供最低限度的工作示例)。

我将所有变量(imageHeight、imageWidth 等)作为 const 传递,仅作为共享图像的指针。最初它是一个指向 QImage 的指针。在循环中,我使用 qtimg->setPixel(...) 设置了最终像素值,与 gcc 编译器相比,MSVC 编译器的处理方式似乎有所不同。最后,我将 QImage 指针替换为指向无符号字符数组的指针,这如预期的那样提高了性能。

@Hristo Iliev:感谢您提供有关线程池的信息。很高兴知道这一点。

最佳答案

由于 pixels 仅被分配,然后从未使用过,整个内部循环被 GCC 的优化器用 -O2 完全删除,因为可以通过启用轻松验证树堆:

; Function <built-in> (main._omp_fn.0, funcdef_no=1036, decl_uid=21657, cgraph_uid=256)

<built-in> (void * .omp_data_i)
{
<bb 2>:
  return;

}

您所做的是有效地测量 OpenMP 运行时开销。

使用 -O0 时,所有代码都保留在原位,并且运行时间按预期随着线程数的增加而扩展,但我怀疑您是否曾使用 1000000000 x 1000000000 图像对其进行过测试。

关于C++ OpenMP 和 gcc 4.8.1 - 并行化循环时的性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19466191/

相关文章:

c++ - 为什么 Visual Studio 不将无符号值显示为 int?

c++ - 将项目添加到列表控件时 UI 卡住

c++ - 将指针数组作为空指针传递给 C++ 中的新线程

c - 如何仅从依赖库中删除符号?

c++ - 如何指定编译前默认包含的文件

c++ - 按引用和按值传递时的 gcc 程序集

c++ - 在 Windows 中执行全屏抓取

c++ - clang : warning: principal. o: 'linker' 输入未使用

c# - 意外输出打印长数字

C++ VS17 给出与 Linux 子系统中相同代码不同的输出