在OpenMP C ++中使用并行块时没有看到任何重大改进

时间:2018-05-13 09:20:19

标签: c++ multithreading openmp eigen

我实时收到Eigen::MatrixXfEigen::Matrix4f的数组。这两个阵列都具有相同数量的元素。我所要做的就是将两个数组的元素相乘,并将结果存储在同一索引的另一个数组中。

请参阅下面的代码段 -

#define COUNT 4

while (all_ok())
{
    Eigen::Matrix4f    trans[COUNT];
    Eigen::MatrixXf  in_data[COUNT];
    Eigen::MatrixXf out_data[COUNT];

    // at each iteration, new data is filled
    // in 'trans' and 'in_data' variables

    #pragma omp parallel num_threads(COUNT)
    {
        #pragma omp for
        for (int i = 0; i < COUNT; i++)
            out_data[i] = trans[i] * in_clouds[i];
    }
}

请注意COUNT是常数。 transin_data的大小分别为(4 x 4)(4 x n),其中n大约为500,000。为了并行化for循环,我尝试了OpenMP,如上所示。但是,我认为for循环的经过时间没有任何显着改善。

有什么建议吗?有什么替代方法可以执行相同的操作吗?

编辑:我的想法是定义4个(=COUNT)个帖子,其中每个人都在处理乘法。通过这种方式,我想每次都不需要创建线程!

2 个答案:

答案 0 :(得分:1)

您需要在编译和链接期间指定-fopenmp。但是你很快就会达到极限,RAM访问正在停止进一步加速。你真的应该看看矢量内在函数。根据您的CPU,您可以将操作加速到寄存器的大小除以变量的大小(float = 4)。因此,如果你的处理器支持说AVX,你一次只能处理8个浮点数。如果您需要一些灵感,欢迎您从我的医学影像重建库中窃取代码: https://github.com/kvahed/codeare/blob/master/src/matrix/SIMDTraits.hpp 代码完成整个shebang浮动/双重真实和复杂。

答案 1 :(得分:1)

使用以下自包含示例为我工作,也就是说,在启用openmp时我获得了x4加速:

#include <iostream>
#include <bench/BenchTimer.h>
using namespace Eigen;

const int COUNT = 4;

EIGEN_DONT_INLINE
void foo(const Matrix4f *trans, const MatrixXf *in_data, MatrixXf *out_data)
{
  #pragma omp parallel for num_threads(COUNT)
  for (int i = 0; i < COUNT; i++)
    out_data[i] = trans[i] * in_data[i];
}

int main()
{
  Eigen::Matrix4f    trans[COUNT];
  Eigen::MatrixXf  in_data[COUNT];
  Eigen::MatrixXf out_data[COUNT];
  int n = 500000;
  for (int i = 0; i < COUNT; i++)
  {
    trans[i].setRandom();
    in_data[i].setRandom(4,n);
    out_data[i].setRandom(4,n);
  }

  int tries = 3;
  int rep = 1;

  BenchTimer t;

  BENCH(t, tries, rep, foo(trans, in_data, out_data));

  std::cout << " " << t.best(Eigen::REAL_TIMER) << " (" << double(n)*4.*4.*4.*2.e-9/t.best() << " GFlops)\n";

  return 0;
}

所以1)确保你测量的是挂钟时间而不是CPU时间,2)确保产品是瓶颈而不是填充in_data

最后,为了获得最佳性能,请不要忘记启用AVX / FMA(例如,使用-march=native),当然也要确保以编译器的优化开启基准。

对于记录,在我的计算机上,上面的例子在没有openmp的情况下需要0.25秒,在使用0.065秒时需要。