当我用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序列:
gsl_vector结构是malloc'd (x86_64上大约有40个字节)。gsl_block结构是malloc'd (16字节),gsl_vector的block指针被设置为刚刚分配的gsl_block的内存地址。malloc'd,它的内存地址被分配给两个data指针( gsl_block中的和gsl_vector中的)。通过删除两个malloc,我获得了40%的性能增益。我创建了自定义的gsl_vector创建例程,该例程分配一个3倍的数组,并将gsl_vector的data指针设置为该数组的地址。然后返回一个gsl_vector (不是指针)。
但是这样做,我仍然得到了数百万的malloc(3 * sizeof(double))操作。
我没有设法将3的数组“嵌入”到gsl_vector结构中,因为如果data指针指向结构本身内的某个东西(hacky!),那么当向量被复制到其他地方时,指针就不再有效了!
你有什么想法(除了切换到C++或滚动我自己的线性代数库)?我愿意接受任何建议。
发布于 2013-04-13 16:42:14
在我看来,您似乎误解了gls_block数据结构的用途。在我看来,您应该使用它在gsl_block数据结构中分配一大块数据,然后将该块分割成多个gsl_vector。如果通过分配一个数组来一次分配所有的gsl_vector,那么您就快到了。在初始化过程中,您只需要对malloc进行两次调用,并进行一些簿记。
这会给你带来什么影响,那就是你必须事先精确地考虑你需要哪一个gsl_vector。但是,当您使用一种没有内置垃圾收集的语言时,这就是要付出的“代价”。如果您对此进行投资,大多数情况下,它具有构造代码的优点,您可能会了解到如何组织计算。
发布于 2013-04-13 16:43:07
C太原始了,不能很好地做到这一点。
如果您需要使用GSL的函数,您可能仍然可以使用C++ Armadillo向量和矩阵。
例如,您可以通过.memptr()成员函数获得指向向量或矩阵使用的内存的指针。这也适用于固定大小的矩阵/向量。
或者,您可以告诉Armadillo使用已经分配的内存块,方法是在向量或矩阵施工期间给它一个指针。
https://stackoverflow.com/questions/15988836
复制相似问题