C++ arm上openMP的矩阵向量乘法

C++ arm上openMP的矩阵向量乘法,c++,multithreading,arm,openmp,C++,Multithreading,Arm,Openmp,我对OpenMP的性能非常失望(尤其是在我的arm设备上) 在我计划的项目中,我需要做很多简单的矩阵向量乘法(一些人可能称之为仿射变换) 所以我开始做一些测试,看看最快的方法是什么 我所说的矩阵的维数约为1000x1000 首先我想展示我的代码,也许你会发现它有明显的错误 1) 时间测量 auto start_time = std::chrono::system_clock::now(); std::time_t ttp = std::chrono::system_clock::to_time_

我对OpenMP的性能非常失望(尤其是在我的arm设备上)

在我计划的项目中,我需要做很多简单的矩阵向量乘法(一些人可能称之为仿射变换)

所以我开始做一些测试,看看最快的方法是什么

我所说的矩阵的维数约为1000x1000

首先我想展示我的代码,也许你会发现它有明显的错误

1) 时间测量

auto start_time = std::chrono::system_clock::now();
std::time_t ttp = std::chrono::system_clock::to_time_t(start_time);
std::cout << std::ctime(&ttp) << std::endl;
while((std::chrono::system_clock::now() - start_time) < std::chrono::seconds(time_span)) {
    const Vector& calc_vec = in_vecs[distr(eng)];
    const Matrix& calc_mat = in_mats[distr(eng)];
    calc_mat.mulVec(calc_vec, o);
    i++;
}
std::cout << "Performed : " << i << " Matrix-Vector multiplications in " << time_span << " sec's with naiv impl" << std::endl;
i=0;
start_time = std::chrono::system_clock::now();
ttp = std::chrono::system_clock::to_time_t(start_time);
std::cout << std::ctime(&ttp) << std::endl;
while((std::chrono::system_clock::now() - start_time) < std::chrono::seconds(time_span)) {
    const Vector& calc_vec = in_vecs[distr(eng)];
    const Matrix& calc_mat = in_mats[distr(eng)];
    calc_mat.mulVec(calc_vec, o, ParallelMode::OpenMP);
    i++;
}
std::cout << "Performed : " << i << " Matrix-Vector multiplications in " << time_span << " sec's with openmp impl" << std::endl;
auto start_time=std::chrono::system_clock::now();
std::time\u t ttp=std::chrono::system\u clock::to\u time\u t(开始时间);

std::cout对于足够大的矩阵,
mat vec mul
是一种内存带宽受限的操作,而不是cpu受限的操作,这意味着您的速度受到从RAM读取/写入矩阵数据的限制。在这种情况下,使用多线程不会获得预期的加速

显示当矩阵足够大(大于缓存)时,
mat vec mul
的性能会下降很多

由于ARM上的缓存大小和RAM带宽通常比桌面CPU低得多,因此多线程可能会受到更多的惩罚

另一方面,当你不知道里面的技巧/理论时,你自己实现基本的矩阵/向量运算通常是非常糟糕的做法。好的方法是使用现有的高性能BLAS库,如OpenBLAS、MKL、cuBLAS、Eigen

因为你在ARM上使用了现代C++,我建议你使用。与OpenBLAS相比,它有更友好的API,OpenBLAS也有ARM优化的代码路径。您可以控制多线程,以便很容易地将性能与Eigen进行比较。您需要做的就是:

int len = 1000;
Eigen::MatrixXf mat = Eigen::MatrixXf::Random(len,len);
Eigen::VectorXf in = Eigen::VectorXf::Random(len);
Eigen::VectorXf out(len);

int num_threads = 4;
Eigen::setNbThreads(num_threads);

out = mat * in;

如果不使用
openmp
,那么单线程性能度量呢?为什么不使用
mtune
-mfpu=neon
?使用现有的高性能线性代数库(如或实现线性代数的标准api)可能会更容易。这两个(可能还有其他)都支持ARM的多线程处理。-mtune和-mfpu没有效果,打开-fopenmp达到了预期效果(在两个测试用例中的性能相同),因为现在我不想为此使用i高级lib,因为我想在使用libs之前了解事情是如何工作的(通常针对一般情况进行优化)。但我将在明天对blas进行基准测试当在ht或numa平台上使用openmp时,您将需要openmp关联设置,除非使用像mkl这样的库来设置它们。
int len = 1000;
Eigen::MatrixXf mat = Eigen::MatrixXf::Random(len,len);
Eigen::VectorXf in = Eigen::VectorXf::Random(len);
Eigen::VectorXf out(len);

int num_threads = 4;
Eigen::setNbThreads(num_threads);

out = mat * in;