Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;OpenMP和gcc 4.8.1-并行循环时的性能问题_C++_Gcc_Mingw_Openmp - Fatal编程技术网

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

C++ C++;OpenMP和gcc 4.8.1-并行循环时的性能问题,c++,gcc,mingw,openmp,C++,Gcc,Mingw,Openmp,我最近开始研究OpenMP,因为我将从事一些计算量高、成本高的图像分析项目。我使用Windows7和Intel i7(8核)以及mingw64 gcc 4.8.1。我在code::Blocks中编写代码,并设置所有内容以编译和运行它。在我的代码的几个部分,我将做一些像素操作,我认为这将是并行处理的一个很好的候选者。令我惊讶的是,原来顺序处理比并行处理快。我在两台不同的计算机上尝试了32位和64位的不同版本的gcc(4.7-4.8),但我总是遇到相同的性能问题。然后,我试着用我的旧VisualSt

我最近开始研究OpenMP,因为我将从事一些计算量高、成本高的图像分析项目。我使用Windows7和Intel i7(8核)以及mingw64 gcc 4.8.1。我在code::Blocks中编写代码,并设置所有内容以编译和运行它。在我的代码的几个部分,我将做一些像素操作,我认为这将是并行处理的一个很好的候选者。令我惊讶的是,原来顺序处理比并行处理快。我在两台不同的计算机上尝试了32位和64位的不同版本的gcc(4.7-4.8),但我总是遇到相同的性能问题。然后,我试着用我的旧VisualStudio2008运行它,我在这两台计算机中的一台上运行了它,我得到了预期的性能提升。因此,我的问题是——为什么我不能使用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;
}
输出如下

for 1 thread :   43ms
for 8 threads:  594ms
我还尝试关闭优化(-O0),以防编译器执行一些循环展开。我读过关于虚假共享问题的文章,因此我将循环中的任何变量都保留为私有,以确保这不是问题所在。我不擅长分析,所以我无法判断下面发生了什么,比如导致所有线程等待的内部锁

我搞不清楚我做错了什么

-编辑-

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

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


@赫里斯托·伊利耶夫:谢谢你提供关于线程池的信息。知道这一点真是太好了。

给出了代码示例,我不能重复您的结果。您必须显示实际堆栈大小和图像大小。因为如果一个线程只能在5毫秒内完成工作,那么多线程并不能使它更快。启动多个线程会带来很大的开销,特别是当您启动它们
imgStack
次时。

由于
像素
仅被分配,然后从未使用过,GCC的Optimizer使用
-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;

}
;函数(main.\u omp\u fn.0,funcdef\u no=1036,decl\u uid=21657,cgraph\u uid=256)
(无效*.omp_数据i)
{
:
返回;
}
您要做的是有效地测量OpenMP运行时开销


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

您在内部循环中根本没有做任何事情。编译器应该完全优化这一点,因此您将看到的只是设置线程和向线程分发(否)工作的成本。如果
QImage::setPixel()
使用内部锁,例如,为了使操作线程安全,一次从多个线程调用它只会序列化它们的执行。多年来,GCC、MSVC、,英特尔和大多数其他公司的OpenMP运行时使用线程池实现工作线程。只有第一个平行区域是昂贵的。除非以后需要更多的线程,否则进一步进入并行区域并不像您预期的那样昂贵。
; 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;

}