4

신경망을 구현하는 동안 데이터 집합 배열에 대해 연속 된 단일 블록으로 메모리를 할당하면 실행 시간이 여러 번 증가한다는 것을 알게되었습니다. -march=native -Ofast (시도 GCC와 연타)로 컴파일 할 때 여기에 대용량 행렬 곱하기 연속 메모리 할당시 훨씬 느림

float** alloc_2d_float(int rows, int cols, int contiguous) 
{ 
    int i; 
    float** array = malloc(rows * sizeof(float*)); 

    if(contiguous) 
    { 
     float* data = malloc(rows*cols*sizeof(float)); 
     assert(data && "Can't allocate contiguous memory"); 

     for(i=0; i<rows; i++) 
      array[i] = &(data[cols * i]); 
    } 
    else 
     for(i=0; i<rows; i++) 
     { 
      array[i] = malloc(cols * sizeof(float)); 
      assert(array[i] && "Can't allocate memory"); 
     } 

    return array; 
} 

결과를 다음과 같습니다 : https://github.com/michaelklachko/NN/blob/master/test.c

: 여기

[email protected]:~/NN$ time ./test 300 1 0 

Multiplying (100000, 1000) and (300, 1000) arrays 1 times, noncontiguous memory allocation. 

Allocating memory: 0.2 seconds 
Initializing arrays: 0.8 seconds 
Dot product:   3.3 seconds 

real 0m4.296s 
user 0m4.108s 
sys  0m0.188s 

[email protected]:~/NN$ time ./test 300 1 1 

Multiplying (100000, 1000) and (300, 1000) arrays 1 times, contiguous memory allocation. 

Allocating memory: 0.0 seconds 
Initializing arrays: 40.3 seconds 
Dot product:   13.5 seconds  

real 0m53.817s 
user 0m4.204s 
sys  0m49.664s 

코드 것

는 메모리 할당이 두 가지 방법을 비교

초기화 및 내적 모두 연속 메모리의 경우 속도가 느립니다.

나는 반대로 예상했다. 인접한 메모리 블록은 많은 수의 분리 된 작은 블록보다 캐시 친화적이어야한다. 또는 적어도 성능면에서 유사해야합니다 (이 컴퓨터의 RAM 용량은 64GB이며 90 %는 사용되지 않습니다).

편집 : 여기에 압축 자체에 포함 된 코드는 (나는 아직도 측정 및 서식 문시킨 대신 github의 버전을 사용하는 것이 좋습니다) : 당신의 능력 또는 장애로 실행하는 것 같은

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 

float** alloc_2d_float(int rows, int cols, int contiguous){ 
    int i; 
    float** array = malloc(rows * sizeof(float*)); 
    if(contiguous){ 
     float* data = malloc(rows*cols*sizeof(float)); 
     for(i=0; i<rows; i++) 
      array[i] = &(data[cols * i]); 
    } 
    else 
    for(i=0; i<rows; i++) 
     array[i] = malloc(cols * sizeof(float)); 
    return array; 
} 

void initialize(float** array, int dim1, int dim2){ 
    srand(time(NULL)); 
    int i, j; 
    for(i=0; i<dim1; i++) 
     for(j=0; j<dim2; j++) 
      array[i][j] = rand()/RAND_MAX; 
} 

int main(){ 
    int i,j,k, dim1=100000, dim2=1000, dim3=300; 
    int contiguous=0; 
    float temp; 

    float** array1 = alloc_2d_float(dim1, dim2, contiguous); 
    float** array2 = alloc_2d_float(dim3, dim2, contiguous); 
    float** result = alloc_2d_float(dim1, dim3, contiguous); 

    initialize(array1, dim1, dim2); 
    initialize(array2, dim3, dim2); 

    for(i=0; i<dim1; i++) 
     for(k=0; k<dim3; k++){ 
      temp = 0; 
      for(j=0; j<dim2; j++) 
       temp += array1[i][j] * array2[k][j]; 
      result[i][k] = temp; 
    } 
} 
+0

더 2D 없다 0.0 초 초기화 배열 : 메모리를 할당 배열에 배열하십시오. 'float ** '과 같은 것은 2D 배열이 아니며, 하나의 배열을 가리 키지도 않습니다. 2D 배열을 사용하십시오. [ask]를보고 [mcve]를 제공하십시오. – Olaf

+0

@Olaf : 당신은 무엇을 의미합니까? 내가 배열 배열을 만드는거야, 안 그래? – MichaelSB

+0

아니, 그렇지 않다! 'float' **에 대한 포인터 배열을 만듭니다. 아주 다른 데이터 유형. 다차원 배열에 대해 배우는 것이 좋습니다.당신이 사용하는 것은 이것과는 거리가 멀고 아마도 당신의 문제 일 것입니다. – Olaf

답변

0

가 보이는 당신의 컴파일러는 코드의 벡터화를 실행합니다. 나는 어떤 성공과 실험을 반복하려고했습니다 -

믹 @의 믹 - 노트북 : 100 1 0

배가 (100000, 1000) 및 (100, 1000 ./a.out ~/Загрузки $) 배열을 1 번 연속하지 않음 메모리 할당.

초기화 배열 ...

곱 배열은 ...

실행 시간 : 0.1 초 초기화 배열 : 0.9 초 도트 제품 : 44.8 초

믹 @의 믹 메모리를 할당 -laptop : ~/$ 100 1 1

곱하기 (100000, 1000) 및 (100, 1000) 배열을 1 번 연속으로 사용 메모리 할당.

초기화 배열 ...

곱 배열은 ...

실행 시간 : 는 내적 1.0 초 : 46.3 초

+0

네, 저의 마지막 코멘트에서 알 수 있듯이 이것은 재부팅 후에 사라진 이상한 임시 결함이었습니다. 그래서 우리는 결코 알 수 없을 것입니다! – MichaelSB