Мне нужно использовать матричную структуру данных в моей программе, в то время как C++ имеет 2d массивы, это очень низкий уровень, в то время как некоторые библиотеки, такие как Eigen, обеспечивают более высокий уровень структуры матричных данных. Но, на мой взгляд, независимо от того, насколько хорошо библиотека работает в некоторых высококвалифицированных операциях, таких как svd, быстрая скорость для основных операций, включая чтение (доступ), запись, суммирование, точку, должна быть предварительным требованием к таким библиотекам , Поскольку в реальных приложениях такие базовые операции могут быть гораздо более частыми, чем те, которые являются высококвалифицированными, если библиотека работает на таких операциях, она может оказаться бременем или даже узким местом системы.Что я должен ожидать, когда я использую структуру данных с плотной матрицей Eigen?
Итак, я пишу некоторые очень простые программы, используя как 2d-массив, так и плотную матрицу Eigen3 (MatrixXd), и сравниваю их характеристики с четырьмя основными операциями, получается, что большую часть времени 2d-массив выигрывает Eigen3, что весьма неутешительно , Я перечислю некоторые из моих результатов теста ниже (код в конце приложения):
10000X10000 матрица, компилировать команду: г ++ -o test.o test.cpp -O0 -msse2
Эйген :
[! COST] init: 6.8 сек.
[! COST] читать: 14.85 сек.
[! COST] написать письмо: 23.02 сек.
[! COST] сумма: 3.28 сек.
[! COST] dot: 3,12 sec.
CPP:
INIT [COST]: 1,81 сек.
[! COST] читать: 2.4 сек.
[! COST] запись: 3.4 сек.
[! COST] сумма: 0.63 сек.
[! COST] dot: 0.52 sec.
10000X10000 матрица, компилировать команду: г ++ -o test.o test.cpp -O3 -msse2
Эйген:
INIT [COST]: 2,44 сек.
[! COST] читать: 2.16 сек.
[! COST] запись: 2.18 сек.
[! COST] сумма: 0.26 секунд.
[! COST] dot: 0.26 sec.
CPP:
INIT [COST]: 1,71 сек.
[! COST] читать: 2.06 сек.
[! COST] написать письмо: 2.24 сек.
[! COST] сумма: 0.15 sec.
[! COST] dot: 0.06 sec.
Однако я до сих пор есть некоторые сомнения по этому поводу, может быть, я не должен ожидать более высокий уровень абстракции матричной структуры должны работать так же быстро, как его сырой вариант, если да, то следует ожидать использования библиотеки, такие как Эйген? Обратите внимание, что в моей программе есть несколько высококвалифицированных операций как SVD, тогда как есть более основные операции, такие как доступ к матрице и запись матрицы.
Приложение, test.cpp:
#include <iostream>
#include <Eigen/Dense>
#include <ctime>
using Eigen::MatrixXf;
inline int cpp_testor_read(float **m, const int M, const int N)
{
float randomTmp = 0;
for (int i = 0; i < M; i ++)
for (int j = 0; j < N; j ++)
{
randomTmp += m[i][j];
randomTmp -= m[j][i];
}
return randomTmp;
}
inline int eigen_testor_read(MatrixXf m, const int M, const int N)
{
float randomTmp = 0;
for (int i = 0; i < M; i ++)
for (int j = 0; j < N; j ++)
{
randomTmp += m(i, j);
randomTmp -= m(j, i);
}
return randomTmp;
}
inline int cpp_testor_write(float **m, const int M, const int N)
{
for (int i = 0; i < M; i ++)
for (int j = 0; j < N; j ++)
{
m[i][j] += m[j][i];
m[j][i] -= m[i][j];
}
return m[rand()%10000][rand()%10000];
}
inline int eigen_testor_write(MatrixXf m, const int M, const int N)
{
for (int i = 0; i < M; i ++)
for (int j = 0; j < N; j ++)
{
m(i, j) += m(j, i);
m(j, i) -= m(i, j);
}
return m(rand()%10000, rand()%10000);
}
inline int cpp_testor_sum(float **m, const int M, const int N, float val)
{
for (int i = 0; i < M; i ++)
for (int j = 0; j < N; j ++)
{
m[i][i] += m[i][j];
}
return m[rand()%1000][rand()%1000];
}
inline int eigen_testor_sum(MatrixXf m, const int M, const int N, float val)
{
m += m;
return m(0, 0);
}
inline int cpp_testor_dot(float **m, const int M, const int N, float val)
{
float randomTmp = 0;
for (int i = 0; i < M; i ++)
for (int j = 0; j < N; j ++)
{
m[i][j] *= val;
}
return m[rand()%1000][rand()%1000];
}
inline int eigen_testor_dot(MatrixXf m, const int M, const int N, float val)
{
m *= val;
return m(0, 0);
}
float** cpp_generator_mtarix(const int M, const int N)
{
float **m = new float*[M];
for (int i = 0; i < M; i ++)
m[i] = new float[N];
return m;
}
MatrixXf& eigen_generator_matrix(const int M, const int N)
{
static MatrixXf m(M,N);
return m;
}
int main()
{
const int M = 10000;
const int N = M;
int antiopt = 0;
srand(time(NULL));
float val1 = rand()%10000 + 1;
float val2 = rand()%10000 + 1;
std::cout<< M << " " << N << std::endl;
std::cout<<"Eigen:" << std::endl;
size_t t = clock();
//MatrixXf m = eigen_generator_matrix(M, N);
MatrixXf m(M,N);
for (int i = 0; i < M; i ++)
for (int j = 0; j < N; j ++)
m(i,j) = rand()%1000 + 1;
t = clock() - t;
std::cout<< "[!COST] init: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
t = clock();
antiopt += eigen_testor_read(m,M,N);
t = clock() - t;
std::cout<< "[!COST] read: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
t = clock();
antiopt += eigen_testor_write(m,M,N);
t = clock() - t;
std::cout<< "[!COST] write: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
t = clock();
antiopt += eigen_testor_sum(m,M,N, val1);
t = clock() - t;
std::cout<< "[!COST] sum: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
t = clock();
antiopt += eigen_testor_dot(m,M,N, val2);
t = clock() - t;
std::cout<< "[!COST] dot: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
std::cout<<"CPP:" << std::endl;
t = clock();
//float **mm = cpp_generator_mtarix(M, N);
float **mm = new float*[M];
for (int i = 0; i < M; i ++)
mm[i] = new float[N];
for (int i = 0; i < M; i ++)
for (int j = 0; j < N; j ++)
mm[i][j] = rand()%1000 + 1;
t = clock() - t;
std::cout<< "[!COST] init: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
t = clock();
antiopt += cpp_testor_read(mm,M,N);
t = clock() - t;
std::cout<< "[!COST] read: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
t = clock();
antiopt += cpp_testor_write(mm,M,N);
t = clock() - t;
std::cout<< "[!COST] write: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
t = clock();
antiopt += cpp_testor_sum(mm,M,N, val1);
t = clock() - t;
std::cout<< "[!COST] sum: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
t = clock();
antiopt += cpp_testor_dot(mm,M,N, val2);
t = clock() - t;
std::cout<< "[!COST] dot: " << t/float(CLOCKS_PER_SEC) << " sec." <<std::endl;
std::cout<<antiopt<<std::endl;
}
Да , это [как и мои результаты] (http://i.stack.imgur.com/h8fdt.png) Я только что получил, когда я изменил все (хотя и встроенные) вызовы функций, чтобы принять «MatrixXf &» вместо «MatrixXf» – bobobobo
Да! Спасибо, я не могу поверить, что я проигнорировал это ... но кажется, что при последовательном доступе массив 2d все еще несколько раз быстрее, чем собственный, я добавляю как m [i] [j], так и m [j] [i] в мой тестовый код, но если только использовать m [i] [j] в массиве 2d и m (j, i) в собственном, 2d-массив выполняется в 3 раза быстрее. Не знаю, почему – chentingpc
@chentingpc Из-за того, как память кеша компьютеров, итерация по столбцам или строкам сначала будет иметь разную производительность в зависимости от того, будет ли ваша матрица [основной или основной строки] (http://en.wikipedia.org/wiki/ Строка-major_order). –