C++ 如何避免特征值稀疏表达式中的内存分配

C++ 如何避免特征值稀疏表达式中的内存分配,c++,eigen,C++,Eigen,我有一个应用程序,其中稀疏模式是常量。假设我的计算是 sm3 = sm1 + sm2 然而,即使我在所有这些操作数中都设置了相同的稀疏模式,我的探查器显示大部分时间都花在分配和取消分配结果矩阵上 这是我的MWE: #include <eigen3/Eigen/Sparse> #include <iostream> int main(int argc, char *argv[]) { using namespace Eigen; SparseMatrix<

我有一个应用程序,其中稀疏模式是常量。假设我的计算是

sm3 = sm1 + sm2
然而,即使我在所有这些操作数中都设置了相同的稀疏模式,我的探查器显示大部分时间都花在分配和取消分配结果矩阵上

这是我的MWE:

#include <eigen3/Eigen/Sparse>
#include <iostream>

int main(int argc, char *argv[])
{
  using namespace Eigen;

  SparseMatrix<double> sm1(2, 2), sm2(2, 2), sm3(2, 2);

  // Populate sm1 and sm2
  sm1.insert(0,0) = 2.0;

  sm2.insert(1,1) = 3.0;

  // Compute the result pattern
  sm3 = sm1 + sm2;

  // Copy the augmented pattern into the operands
  sm1 = sm2 = sm3;

  // This loop triggers a lot of new[] and delete[] calls
  for(int i = 0; i < 1000; i++)
    sm3 = sm2 + sm1;
}
#包括
#包括
int main(int argc,char*argv[])
{
使用名称空间特征;
SparseMatrix sm1(2,2),sm2(2,2),sm3(2,2);
//填充sm1和sm2
sm1.插入(0,0)=2.0;
sm2.插入(1,1)=3.0;
//计算结果模式
sm3=sm1+sm2;
//将扩充模式复制到操作数中
sm1=sm2=sm3;
//此循环触发许多新[]和删除[]调用
对于(int i=0;i<1000;i++)
sm3=sm2+sm1;
}

可以避免这些分配操作吗?

这目前是不可能的,因为默认情况下稀疏矩阵被假定为别名。例如,如果您这样做:

m3 = m3 + m1;
由于
m1
模式未完全包含在
m3
模式中,因此无法直接在
m3
中计算表达式。在未来中,我们可以使用如下语法强制重新使用目标内存:

m3.noalias() = m1 + m2;
同时,由于矩阵很小,通过添加一些明确的零,您可以通过强制执行
m1
m2
的模式与
m3
的模式相同来解决问题,甚至获得更高的性能。然后,使用Eigen 3.3,可以将稀疏加法转换为密集向量加法:

m3.coeffs() = m1.coeffs() + m2.coeffs();

即使
m1
m2
之间的交集很小,您也会获得非常高的加速比(可能是一个数量级),因为您摆脱了内存间接寻址,并从矢量化中获益(不要忘了启用AVX,例如
-mavx
)。

sm3=sm2+sm1
将生成一个临时文件(
sm2+sm1
),销毁
sm3
,然后将临时文件复制到
sm3
。不
sm3=sm2;sm3+=sm1略微改进?
SparseMatrix
预计将用于10000x1000或更大的大型矩阵。对于这样的矩阵,new和delete的开销可以忽略不计。那么,你在研究什么样的矩阵尺寸?你有没有用分析器来衡量这种内存分配的成本?@RichardCriten:不幸的是,分配的数量是相同的。@ggael:我使用的矩阵要小得多,从100x100到700x700不等。在求解线性代数系统时,我通常使用稀疏技术来提高性能,但在整个程序中,我必须依靠这样的预处理技巧来保持模式。是的,我从一开始就分析了这个程序,因此我发现90%以上的时间都花在了new、calloc、free和delete上。我这样问是因为我已经看到,本征模式并不总是在分配时被丢弃,但我不知道如何强制执行。根据您的系统,您可以通过自己处理内存分配来获得良好的性能增益。如果您知道内存分配总是相同的大小,或者线程安全不是一个问题,等等,那么这些事情确实会对内存管理器的性能产生很大的影响。