C++ C++;特征库:Ref<;的性能开销&燃气轮机;

C++ C++;特征库:Ref<;的性能开销&燃气轮机;,c++,eigen,C++,Eigen,我正在使用计算力学的Egeng编写一个通用库, 主要处理6x6大小的矩阵和6x1大小的向量。 我考虑使用 EGEN::REF模板,使其也适用于片段和块,如在文件和中所记载的那样。 然而,一个小的性能比较表明, > EGEN::REF 相比于标准C++引用,这样的小函数具有相当大的开销: #include <ctime> #include <iostream> #include "Eigen/Core" Eigen::Matrix<double, 6, 6>

我正在使用计算力学的Egeng编写一个通用库, 主要处理6x6大小的矩阵和6x1大小的向量。 我考虑使用<代码> EGEN::REF模板,使其也适用于片段和块,如在文件和

中所记载的那样。

然而,一个小的性能比较表明, > EGEN::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;
}
因此,
Eigen::Ref
似乎有相当大的开销,至少在实际计算工作量较低的情况下是如此。 另一方面,如果传递了块或段,则使用
常数特征::矩阵&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;
}
因此,这种方法不适用于一般情况

或者,可以使用
Eigen::MatrixBase
制作函数模板,如文档中所述。然而,对于大型库来说,这似乎是低效的,并且不能像我的例子那样适应固定大小的矩阵(6x6,6x1)

还有其他选择吗? 大型通用图书馆的一般建议是什么

提前谢谢你

编辑:根据注释中的建议修改第一个基准示例,使用
Ref
您将付出失去两个信息的代价(与矩阵相比):

  • 您不知道输入是内存对齐的
  • 您失去了列顺序存储的编译时知识(因此两列之间用6个双精度分隔)

  • 这是泛型和最高性能之间的经典折衷。

    无法在我得到的
    Ref:0.069
    noRef:0.069
    上进行优化复制。如果没有优化的性能很重要,那么yeah Eigen通常会有巨大的开销,但这种情况在启用优化的情况下(例如,
    -O2
    )会消失吗?如果不是,你的结果是不可信的,但如果。。。您的测试功能没有副作用。这就有一种危险,
    Eigen::Matrix temp=(A*A)被优化掉了。您应该返回值,将其存储在向量中,然后打印(测量后),以防止由于优化而导致的“vanashing”。查看汇编也有助于发现您的代码实际到达二进制的部分。基准测试无效,因为一旦启用优化,编译器就可以自由地完全删除函数体。我修改了基准测试示例并启用了优化。然而,一个不同之处仍然存在。@macmallow我仍然不能可靠地使它变慢。VS2017现在让它慢了很多,但如果我继续重复测试,同一测试中的速度差异似乎高于两者之间的平均值差异。在gcc中,我现在发现Ref大部分时间都更快。我想是时候看看compilerversion、CPU和EigenVersion了。因此,我可以得出结论,我应该坚持尽可能长的C++引用(即,只要临时副本被排除),并实现功能与REF仅在必要时?
    
    #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