Я пишу библиотеку общего назначения, использующую Eigen для вычислительной механики, которая в основном работает с матрицами размером 6x6 и векторами размером 6x1.Я рекомендую использовать шаблон Eigen::Ref<>
, чтобы его можно было использовать также для сегментов и блоков, как описано в http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html и Правильное использование класса Eigen :: Ref <>
Однако небольшое сравнение производительности показывает, что Eigen::Ref
имеет значительные издержки для таких небольших функций по сравнению со стандартными ссылками на c ++:
#include <ctime>
#include <iostream>
#include "Eigen/Core"
Eigen::Matrix<double, 6, 6> testRef(const Eigen::Ref<const Eigen::Matrix<double, 6, 6>>& A)
{
Eigen::Matrix<double, 6, 6> temp = (A * A) * A;
temp.diagonal().setOnes();
return temp;
}
Eigen::Matrix<double, 6, 6> testNoRef(const Eigen::Matrix<double, 6, 6>& A)
{
Eigen::Matrix<double, 6, 6> temp = (A * A) * A;
temp.diagonal().setOnes();
return temp;
}
int main(){
using namespace std;
int cycles = 10000000;
Eigen::Matrix<double, 6, 6> testMat;
testMat = Eigen::Matrix<double, 6, 6>::Ones();
clock_t begin = clock();
for(int i = 0; i < cycles; i++)
testMat = testRef(testMat);
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
std::cout << "Ref: " << elapsed_secs << std::endl;
begin = clock();
for(int i = 0; i < cycles; i++)
testMat = testNoRef(testMat);
end = clock();
elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
std::cout << "noRef : " << elapsed_secs << std::endl;
return 0;
}
Вывод с gcc -O3
:
Ref: 1.64066
noRef : 1.1281
Таким образом, кажется, что Eigen::Ref
имеет значительные накладные расходы, по крайней мере, в случаях с низким фактическим вычислительным усилием.С другой стороны, подход с использованием const Eigen::Matrix<double, 6, 6>& A
приводит к ненужным копиям, если переданы блоки или сегменты:
#include <Eigen/Core>
#include <iostream>
void test( const Eigen::Vector3d& a)
{
std::cout << "addr in function " << &a << std::endl;
}
int main () {
Eigen::Vector3d aa;
aa << 1,2,3;
std::cout << "addr outside function " << &aa << std::endl;
test ( aa ) ;
test ( aa.head(3) ) ;
return 0;
}
Вывод:
addr outside function 0x7fff85d75960
addr in function 0x7fff85d75960
addr in function 0x7fff85d75980
Таким образом, этот подход исключен для общегоcase.
В качестве альтернативы можно создать шаблоны функций, используя Eigen::MatrixBase
, как описано в документации.Однако это кажется неэффективным для больших библиотек, и его нельзя адаптировать к матрицам фиксированного размера (6x6, 6x1), как в моем случае.
Есть ли другая альтернатива?Какова общая рекомендация для больших библиотек общего назначения?
Заранее спасибо!
edit: Изменен первый пример эталонного теста в соответствии с рекомендациями в комментариях