【发布时间】:2018-09-20 16:57:39
【问题描述】:
为什么矩阵加法比矩阵向量乘法需要更长的时间?
矩阵加法只需要 n^2 次加法,而矩阵向量乘法需要 n*(n-1) 次加法和 n^2 次乘法。
但是,在 Eigen 中,矩阵加法需要两倍的时间 矩阵向量乘法可以。是否有任何选项可以加快 Eigen 中的 Matrix Add 操作?
#include <eigen3/Eigen/Eigen>
#include <iostream>
#include <ctime>
#include <string>
#include <chrono>
#include <fstream>
#include <random>
#include <iomanip>
using namespace Eigen;
using namespace std;
int main()
{
const int l=100;
MatrixXf m=MatrixXf::Random(l,l);
MatrixXf n=MatrixXf::Random(l,l);
VectorXf v=VectorXf::Random(l,1);
MatrixXf qq=MatrixXf::Random(l,1);
MatrixXf pp=MatrixXf::Random(l,l);
auto start = chrono::steady_clock::now();
for(int j=0;j<10000;j++)
qq=m*v;
auto end = chrono::steady_clock::now();
double time_duration=chrono::duration_cast<chrono::milliseconds>(end - start).count();
std::cout << setprecision(6) << "Elapsed time in seconds : "<< time_duration/1000<< "s" << std::endl;
auto start1 = chrono::steady_clock::now();
for(int j=0;j<10000;j++)
pp=m+n;
auto end1 = chrono::steady_clock::now();
double time_duration1=chrono::duration_cast<chrono::milliseconds>(end1 - start1).count();
std::cout << setprecision(6) << "Elapsed time in seconds : "<< time_duration1/1000<< "s" << std::endl;
}
测试 1:没有任何优化:
编译命令:g++-8 -test.cpp -o test
运行命令:./test
以秒为单位的经过时间:0.323s
以秒为单位的经过时间:0.635s
测试 2:使用 -march=native 优化:
g++-8 test.cpp -march=native -o test
运行命令:./test
经过的时间(秒):0.21s
经过的时间(秒):0.372s
测试 3:使用 -O3 优化:
编译命令:g++-8 -test.cpp -O3 -o test
运行命令:./test
以秒为单位的经过时间:0.009s
经过的时间(秒):0.016s
测试 4:使用 -march=native、-O3 优化:
编译命令:g++-8 -test.cpp -march=native -O3 -o test
运行命令:./test
经过的时间,以秒为单位:0.008s
经过的时间(秒):0.016s
==============
我注意到编译器可能会作弊的 cmets,因为我没有使用上一次迭代的结果。为了解决这个问题,我改为进行一次迭代并使用更大的尺寸来获得稳定的时间统计信息。
#include <eigen3/Eigen/Eigen>
#include <iostream>
#include <ctime>
#include <string>
#include <chrono>
#include <fstream>
#include <random>
#include <iomanip>
using namespace Eigen;
using namespace std;
int main()
{
const int l=1000;
MatrixXf m=MatrixXf::Random(l,l);
MatrixXf n=MatrixXf::Random(l,l);
VectorXf v=VectorXf::Random(l,1);
MatrixXf qq=MatrixXf::Random(l,1);
MatrixXf pp=MatrixXf::Random(l,l);
auto start = chrono::steady_clock::now();
qq=m*v;
auto end = chrono::steady_clock::now();
double time_duration=chrono::duration_cast<chrono::microseconds>(end - start).count();
auto start1 = chrono::steady_clock::now();
pp=m+n;
auto end1 = chrono::steady_clock::now();
double time_duration1=chrono::duration_cast<chrono::microseconds>(end1 - start1).count();
std::cout << setprecision(6) << "Elapsed time in microseconds : "<< time_duration<< "us" << std::endl;
std::cout << setprecision(6) << "Elapsed time in microseconds : "<< time_duration1<< "us" << std::endl;
}
测试 1:没有任何优化:
编译命令:g++-8 -test.cpp -o test
运行命令:./test
以微秒为单位的经过时间:3125us
以微秒为单位的经过时间:6849us
测试 2:使用 -march=native 优化:
g++-8 test.cpp -march=native -o test
运行命令:./test
经过的时间(以微秒为单位):1776us
以微秒为单位的经过时间:3815us
测试 3:使用 -O3 优化:
编译命令:g++-8 -test.cpp -O3 -o test
运行命令:./test
以微秒为单位的经过时间:449us
以微秒为单位的经过时间:760us
测试 4:使用 -march=native、-O3 优化:
编译命令:g++-8 -test.cpp -march=native -O3 -o test
运行命令:./test
以微秒为单位的经过时间:351us
以微秒为单位的经过时间:871us
【问题讨论】:
-
你确认循环没有被优化掉吗?编译器可能会看到循环运行 10000 次和运行一次的效果是一样的……
-
是的,我做到了。请查看新的更新说明。它仍然需要更长的时间。 @MaxLanghof
-
您更改了编译标志,但您仍然没有使用结果!你可以做一些像 static float x = 0.0; x = x+qq[0][0]; x = x +pp[0] 在每次加法或乘法之后,以便编译器必须使用结果。 (最后是 cout
-
感谢@Jeffrey 的建议,我改用一次迭代来演示。
-
不是您的确切问题,但有关缓存一般如何/为何重要的文章,请参阅stackoverflow.com/questions/11413855/…
标签: c++ performance matrix eigen