2013-04-13 3 views
0

C++에서 선형 대수 프로그램을 작성할 때 Armadillo 라이브러리를 사용합니다. 템플릿을 기반으로하고 있기 때문에 컴파일 타임에 적절한 메모리 버퍼가 정적으로 할당되므로 추가 메모리 할당이 필요하지 않은 길이의 벡터를 정의하는 방법을 제공합니다. arma::Col<double>::fixed<3>을 사용할 때 컴파일러는 "새로운 유형"을 즉석에서 생성하여 벡터에 정확히 3 배의 버퍼가 포함됩니다.GSL gsl_vector에 대한 더 나은 메모리 관리

이제 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이 순서의 일이 :

  1. gsl_vector 구조는 malloc 'D (뭔가 x86_64의에 약 40 바이트)입니다.
  2. gsl_block 구조 malloc된다
  3. D '(D) (16 바이트)와 gsl_vector의 block 포인터 단지
  4. 를 할당 gsl_block의 메모리 어드레스로 설정된 3 루타의 배열 malloc이다'와 메모리 어드레스가 할당되고 data 포인터 (모두 gsl_block이고 하나는 gsl_vector).

2 개의 코드를 제거하여 40 %의 성능 향상을 얻었습니다. 내 사용자 정의 gsl_vector 작성 루틴을 작성하여 3 개의 double 형 배열을 할당하고 gsl_vectordata 포인터를이 배열의 주소로 설정합니다. 그런 다음 gsl_vector (포인터가 아님)을 반환합니다.
그러나 이렇게해도 나는 여전히 수백만 개의 작업을 수행하고 있습니다.

내가 관리하지 않은 구조체 자체 (해키!) 내부 무언가에 data 포인터 점, 다음 포인터가 더 이상없는 경우 때문에 "삽입"를 gsl_vector 구조체 내부 3 복식의 배열에 벡터가 다른 곳에 복사 될 때 유효합니다!

아이디어가 있습니까? (C++로 전환하거나 선형 대수학 라이브러리를 사용하고 있습니까?) 나는 어떤 제안이든 열려 있습니다.

답변

3

마치 gls_block 데이터 구조의 목적을 오해하고있는 것처럼 보입니다. 그것은 단지 데이터 구조에서 큰 덩어리의 데이터를 할당 한 다음 그 덩어리를 다중 gsl_vector에 사용하기 위해 분할하는 데 사용해야한다고 생각합니다.배열을 할당하여 한 번에 모든 gsl_vector을 할당하면 거의 다 있습니다. malloc에 대한 두 번의 호출과 초기화 중 일부 부기가 있습니다.

이것은 당신에게 당신이 필요로하는 정확히 미리 생각해야 할 것입니다. gsl_vector. 그러나 이것은 가비지 콜렉션이 내장되어 있지 않은 언어를 사용할 때 지불해야하는 "가격"입니다. 그것에 투자한다면 대부분의 경우 코드를 구조화하는 이점이 있습니다. 계산을 구성하는 방법에 대해 많은 것을 배울 것입니다.

+0

안녕하세요 젠스, gsl_vectorFlex의 문제는 유연한 배열 멤버가 마지막 멤버 여야하며 (미리 컴파일 된) GSL 구현은 결국 구조체의 다른 멤버에 도달한다는 것입니다. 구조체. gsl_block에 관해서, 나는 왜 그곳이 존재하는지 완벽하게 알고 있으며 적절한 길이의 블록을 미리 할당하기위한 GSL 함수조차있다. 그러나 필요한 모든 벡터에 대해 메모리를 미리 할당 할 수 있다면이 질문을하지 않을 것입니다. – gd1

+0

또한, 가변 길이 배열을 끝에 추가 할 수 없습니다 * (같은 구조체 내에서) * 데이터를 가리키면 개체가 복사됩니다 (그리고 내가 그것에 대한 제어권이 없기 때문에) 포인터가 더 이상 유효하지 않기 때문에. – gd1

+0

@ gd1, 나는 쉽지 않다고 말하지 않았다. 그리고 두 번째 부분에서는'gsl_vector'에서 유연한 멤버 (가변 길이 배열이 다른 것입니다!)를 가지는 것을 의미하지 않았습니다. 'gsl_block'에 유연한 배열 멤버가 있다면 그럴 필요가 없습니다. –

0

C는이 작업을 제대로 수행하기에 너무 원시적입니다.

GSL에서 함수를 사용해야하는 경우에도 C++ Armadillo 벡터와 행렬을 사용할 수 있습니다.

예를 들어 .memptr() 멤버 함수를 통해 벡터 나 행렬에서 사용하는 메모리에 대한 포인터를 얻을 수 있습니다. 고정 크기 행렬/벡터에도 적용됩니다.

또는 벡터 또는 행렬 construction 동안 포인터를 할당하여 이미 할당 된 메모리 블록을 사용하도록 Armadillo에 알릴 수 있습니다.

+0

그러나 고맙습니다. 나는 C를 써야 해. – gd1