在 OpenMP C++ 中使用并行块时没有看到任何显着改进
Doesn't see any significant improvement while using parallel block in OpenMP C++
我正在实时接收 Eigen::MatrixXf
和 Eigen::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
是一个常量。 trans
和in_data
的大小分别为(4 x 4)
和(4 x n)
,其中n
约为500,000。为了并行化 for
循环,我尝试了 OpenMP
,如上所示。但是,我没有看到 for
循环的运行时间有任何显着改善。
有什么建议吗?请问还有其他方法可以执行相同的操作吗?
编辑: 我的想法是定义 4 (=COUNT
) 个线程,其中每个线程都负责乘法。这样一来,我们就不用每次都创建线程了,我猜!
您需要在编译和链接时指定-fopenmp
。但是您很快就会达到极限,RAM 访问停止进一步加速。你真的应该看看向量内在函数。取决于您 CPU,您可以将操作加速到寄存器大小除以变量大小 (float = 4)。因此,如果您的处理器支持 AVX,您将同时处理 8 个浮点数。如果您需要一些灵感,欢迎您在这里从我的医学图像重建库中窃取代码:
https://github.com/kvahed/codeare/blob/master/src/matrix/SIMDTraits.hpp
该代码完成了 float/double 真实而复杂的整个 shebang。
使用以下独立示例对我有用,也就是说,启用 openmp 时我的速度提高了 4 倍:
#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 秒,而在有 openmp 的情况下需要 0.065 秒。
我正在实时接收 Eigen::MatrixXf
和 Eigen::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
是一个常量。 trans
和in_data
的大小分别为(4 x 4)
和(4 x n)
,其中n
约为500,000。为了并行化 for
循环,我尝试了 OpenMP
,如上所示。但是,我没有看到 for
循环的运行时间有任何显着改善。
有什么建议吗?请问还有其他方法可以执行相同的操作吗?
编辑: 我的想法是定义 4 (=COUNT
) 个线程,其中每个线程都负责乘法。这样一来,我们就不用每次都创建线程了,我猜!
您需要在编译和链接时指定-fopenmp
。但是您很快就会达到极限,RAM 访问停止进一步加速。你真的应该看看向量内在函数。取决于您 CPU,您可以将操作加速到寄存器大小除以变量大小 (float = 4)。因此,如果您的处理器支持 AVX,您将同时处理 8 个浮点数。如果您需要一些灵感,欢迎您在这里从我的医学图像重建库中窃取代码:
https://github.com/kvahed/codeare/blob/master/src/matrix/SIMDTraits.hpp
该代码完成了 float/double 真实而复杂的整个 shebang。
使用以下独立示例对我有用,也就是说,启用 openmp 时我的速度提高了 4 倍:
#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 秒,而在有 openmp 的情况下需要 0.065 秒。