更好的GSL gsl_vector内存管理

时间:2013-04-13 14:25:05

标签: c performance optimization memory-management gsl

当我用C ++编写线性代数程序时,我使用的是Armadillo库。它基于模板,它为我提供了一种定义任何长度的向量的方法,这些向量不一定需要额外的内存分配,因为它们在编译时被静态分配了适当的内存缓冲区。当我使用arma::Col<double>::fixed<3>时,编译器会动态创建一个“新类型”,以便向量包含一个恰好3个双精度的缓冲区。

现在我正在研究C中的线性代数程序,我正在使用GNU科学库(GSL)。为了实例化3D矢量,我执行:gsl_vector_alloc(3),返回gsl_vector*。问题是这个操作会导致一小部分内存的动态分配,这在程序运行时会发生数百万次。我的程序浪费了大量资源来执行数千万malloc / free次操作。

我检查过gsl_vector的内部结构:

typedef struct
{
   size_t size;
   size_t stride;
   double * data;
   gsl_block * block;
   int owner;
} gsl_vector;

为使库正常工作,data应指向向量的第一个元素,通常位于gsl_block结构中,如下所示:

typedef struct
{
   size_t size;
   double * data;
} gsl_block;

包含另一个data指针。因此,为了实例化一个简单的3D向量,malloc s的这个序列发生了:

  1. gsl_vector结构为malloc'd(x86_64上大约40个字节)。
  2. gsl_block结构为malloc'd(16字节),gsl_vector的block指针设置为刚刚分配的gsl_block的内存地址
  3. 3个双打的数组是malloc'd,其内存地址分配给data个指针(gsl_block中的一个和gsl_vector中的一个)。
  4. 通过删除两个malloc,我获得了40%的性能提升。我创建了自定义gsl_vector创建例程,它分配了一个3个双精度数组,并将data的{​​{1}}指针设置为该数组的地址。然后我返回gsl_vector(不是指针) 但这样做,我仍然可以获得数百万次gsl_vector次操作。

    我没有设法在malloc(3 * sizeof(double))结构中“嵌入”3个双精度数组,因为如果gsl_vector指针指向 in 结构中的某些内容本身(hacky!),当向量被复制到别处时,指针不再有效!

    你有什么想法(除了转换到C ++或滚动我自己的线性代数库)?我对任何建议持开放态度。

2 个答案:

答案 0 :(得分:4)

我认为你好像误解了gls_block数据结构的目的。在我看来,您应该只使用它在gsl_block数据结构中分配大块数据,然后将该块拆分以供多个gsl_vector使用。如果您通过分配一组数组来一次性分配所有gsl_vector,那么您几乎就在那里。您只需要两次调用malloc,并在初始化期间进行一些簿记。

这对你造成的影响是,你必须事先准确地考虑你需要的gsl_vector。但是,当您使用没有内置垃圾收集的语言时,这就是支付的“价格”。如果您投资于此,大多数时候它都具有构建代码的优势,您可能会学到如何组织计算。

答案 1 :(得分:0)

C有点过于原始,不能正确地做到这一点。

如果您需要使用GSL中的函数,您可能仍然可以使用C ++ Armadillo向量和矩阵。

例如,您可以通过.memptr()成员函数获取指向矢量或矩阵使用的内存的指针。这也适用于固定大小的矩阵/向量。

或者,您可以告诉Armadillo使用已经分配的内存块,方法是在向量​​或矩阵construction期间给它一个指针。