OpenMP

时间:2016-07-28 08:11:54

标签: c++ multithreading parallel-processing openmp

我正在使用OpenMP来获得具有接近线性加速的算法。 不幸的是我注意到我无法获得所需的加速。

因此,为了理解我的代码中的错误,我编写了另一个代码,一个简单的代码,只是为了仔细检查加速是否原则上可以在我的硬件上获得。

这是我写的玩具示例:

#include <omp.h>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <cstdlib>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <algorithm>
#include "mkl.h"

int main () {
      int number_of_threads = 1;
      int n = 600;
      int m = 50;
      int N = n/number_of_threads;
      int time_limit = 600;
      double total_clock = omp_get_wtime();
      int time_flag = 0;

      #pragma omp parallel num_threads(number_of_threads)
       {
          int thread_id = omp_get_thread_num();
          int iteration_number_local = 0;
          double *C = new double[n]; std::fill(C, C+n, 3.0);
          double *D = new double[n]; std::fill(D, D+n, 3.0);
          double *CD = new double[n]; std::fill(CD, CD+n, 0.0);

          while (time_flag == 0){
                for (int i = 0; i < N; i++)                     
                    for(int z = 0; z < m; z++)
                        for(int x = 0; x < n; x++)
                            for(int c = 0; c < n; c++){
                                CD[c] = C[z]*D[x];
                                C[z] = CD[c] + D[x];
                            }
                iteration_number_local++;
                if ((omp_get_wtime() - total_clock) >= time_limit) 
                    time_flag = 1; 
           }
       #pragma omp critical
       std::cout<<"I am "<<thread_id<<" and I got" <<iteration_number_local<<"iterations."<<std::endl;
       }
    }

我想再次强调,这段代码只是一个试图看到加速的玩具示例:当并行线程数增加时(由于N减少),第一个for-cycle变得更短。

但是,当我从1到2-4个线程时,迭代次数会按预期加倍;但是当我使用8-10-20个线程时情况并非如此:迭代次数不随线程数线性增加。

你可以帮我解决这个问题吗?代码是否正确?我应该期待接近线性的加速吗?

  

结果

     

运行上面的代码我得到了以下结果。

     

1个帖子:23个迭代。

     

20个线程:每个线程397-401次迭代(而不是420-460)。

3 个答案:

答案 0 :(得分:1)

您的测量方法是错误的。特别是对于少量的迭代。

  

1个线程:3次迭代。

3报告的迭代实际上意味着 2次迭代在不到120秒内完成。第三个花了更长的时间。 1次迭代的时间在40到60秒之间。

  

2个线程:每个线程5次迭代(而不是6次)。

4次迭代在不到120秒内完成。 1次迭代的时间在24到30秒之间。

  

20个线程:每个线程40-44次迭代(而不是60次)。

40次迭代在不到120秒内完成。 1次迭代的时间在2.9到3秒之间。

正如您所看到的,您的结果实际上并不与线性加速相矛盾。

简单地执行和计时一个外部循环会更加简单和准确,您可能会看到几乎完美的线性加速。

为什么你没有看到线性加速的一些原因(非详尽无遗)是:

  1. 内存限制性能。使用n = 1000的玩具示例中并非如此。更一般地说:争用共享资源(主内存,缓存,I / O)。
  2. 线程之间的同步(例如关键部分)。在您的玩具示例中并非如此。
  3. 线程之间的负载不平衡。在您的玩具示例中并非如此。
  4. 当使用所有核心时,Turbo模式将使用较低的频率。这可能发生在您的玩具示例中。
  5. 从您的玩具示例中,我会说您可以通过更好地使用高级抽象来改进您的OpenMP方法,例如: for

    对于此格式,更广泛的建议过于宽泛,需要有关非玩具示例的更具体信息。

答案 1 :(得分:0)

你在并行区域内做了一些声明,这意味着你将分配记忆并填写number_of_threads次。相反,我建议你:

double *C = new double[n]; std::fill(C, C+n, 3.0);
double *D = new double[n]; std::fill(D, D+n, 3.0);
double *CD = new double[n]; std::fill(CD, CD+n, 0.0);
#pragma omp parallel firstprivate(C,D,CD) num_threads(number_of_threads)
   {
      int thread_id = omp_get_thread_num();
      int iteration_number_local = 0;  
   } 

您的硬件的线程数量有限,这取决于处理器的核心数量。你可能有2或4个核心。

并行区域不会加快代码速度。使用open openMP,您应该使用#omp parallel来加速循环或

#pragma omp parallel
{
  #pragma omp for
  {
  }
}

这种表示法相当于#pragma omp parallel for。它将使用多个线程(取决于您的硬件)来更快地继续for循环。 小心

#pragma omp parallel
{
  for
  {
  }
}

将为每个线程创建整个for循环,这不会加速你的程序。

答案 2 :(得分:0)

你应该试试

   #pragma omp parallel num_threads(number_of_threads)
   {
      int thread_id = omp_get_thread_num();
      int iteration_number_local = 0;
      double *C = new double[n]; std::fill(C, C+n, 3.0);
      double *D = new double[n]; std::fill(D, D+n, 3.0);
      double *CD = new double[n]; std::fill(CD, CD+n, 0.0);

      while (time_flag == 0){
           #pragma omp for 
            for (int i = 0; i < N; i++)                     
                for(int z = 0; z < m; z++)
                    for(int x = 0; x < n; x++)
                        for(int c = 0; c < n; c++)
                            CD[c] = C[z]*D[x];
            iteration_number_local++;
            if ((omp_get_wtime() - total_clock) >= time_limit) 
                time_flag = 1; 
       }
       if(thread_id == 0)
        iteration_number = iteration_number_local;
   }
  std::cout<<"Iterations= "<<iteration_number<<std::endl;
}