Странное поведение C / CUDA с большими массивами

#c #algorithm #cuda #large-data

#c #алгоритм #cuda #большие данные

Вопрос:

Я пытаюсь реализовать какой-то алгоритм Якоби и измерить время, затраченное на разные размеры сетки.

Для того, чтобы иметь одинаковое количество итераций, независимо от того, насколько велика сетка, я не использую какой-то остаток, но пусть алгоритм всегда выполняет 4000 итераций (но с разным размером массивов). Это работает точно так, как должно, до тех пор, пока я не превыслю сетку 510×510 (двойную). 510×510 занимает около 2763498 микросекунд, а затем 520×520 занимает 1778 микросекунд.

Я уже пытался перейти с двойных массивов на плавающие, чтобы убедиться, что это не какая-то нехватка памяти, но я не могу понять, где на самом деле скрыта моя проблема.

 __global__ void Jacobi(double *a, double *b, double *c, int L){
int row = blockIdx.y * blockDim.y   threadIdx.y;
int col = blockIdx.x * blockDim.x   threadIdx.x;

if(row > 0 amp;amp; col > 0 amp;amp; row < L-1 amp;amp; col < L-1){
    a[row * L   col] = 1.0/4.0 * (b[col 1   row*L]   b[col - 1   row*L]   b[col   (row 1)*L]   b[col   (row-1)*L] - c[col   row*L]);
    __syncthreads();
    b[row*L   col] = a[row*L col];
    }
}

int main(){
int L;
int Iterations;
double *h_phi1;
double *h_phi2;

double *h_f;
FILE * temp = fopen("Timings.out", "w");
for (L=10;L<10000;L =10){
    long long int size = L*L*sizeof(double);
    h_f = (double*) malloc(size);
    h_phi1 = (double*) malloc(size);
    h_phi2 = (double*) malloc(size);


    for(int i=0;i<L;i  ){
        for(int j=0;j<L;j  ){
            h_f[j i*L] = (pow(1.0/float(L),2.0))*exp(-100.0*(pow((float(i)/float(L) - float(1.0/3.0) ),2.0)   pow(( float(j)/float(L) - float(1.0/3.0) ),2.0))) - 
            (pow(1.0/ float(L),2.0))*exp(- 100.0*(pow(( float(i)/ float(L) -(1.0- 1.0/3.0)),2.0)   pow(( float(j)/float(L)-(1.0-float(1.0/3.0))),2.0)));
            h_phi1[j i*L] = 0;
            h_phi2[j i*L] = 0;
        }
    }

    //allocate memory on GPU
    double *d_phi1;
    cudaMalloc(amp;d_phi1, size);
    double *d_phi2;
    cudaMalloc(amp;d_phi2, size);
    double *d_f;
    cudaMalloc(amp;d_f, size);
    
    //set CTA
    int threads = 16;
    int blocks = (L threads-1)/threads;
    double epsCalc;

    //Setup Kernel launch parameters
    dim3 dimBlock(threads, threads);
    dim3 dimGrid(blocks, blocks);

    //Setup timing and Cpy Memory from Host to Device
    Iterations = 0;
    auto t1 = std::chrono::high_resolution_clock::now();
    cudaMemcpy(d_phi2, h_phi2, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_f, h_f, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_phi1, h_phi2, size, cudaMemcpyHostToDevice);

    //Launch Kernel
    for (int j=0;j<4000;j  ){
        Iterations  = 1;
        Jacobi<<<dimBlock, dimGrid>>>(d_phi2,d_phi1,d_f,L);

    }
    auto t2 = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
    
    fprintf(temp, "%lf % %d n", L, duration);
    printf("I reached the end of Jacobi after %d Iterations!n Time taken was %d in milliseconds", Iterations, duration);
    cudaFree(d_f); cudaFree(d_phi2), cudaFree(d_phi1);
    free(h_f); free(h_phi2); free(h_phi1);
}

return 0;
}
  

Я надеюсь, что кто-нибудь может указать мне, где допущена моя ошибка.

Комментарии:

1. Если вас беспокоит, является ли это проблемой с памятью, вам действительно следует проверить, malloc возвращает ли 0.

2. Измерение времени в вашем коде нарушено.

3. Я не думаю, что измерение времени нарушено. Выполнение действительно намного быстрее .. и время для итераций из (520,530 ….) снова увеличивается. Проверка Cuda-Memcheck приводит к «»»попаданию программы в cudaErrorInvalidConfiguration (ошибка 9) из-за «недопустимого аргумента конфигурации» при вызове CUDA API для cudaLaunchKernel. «»»» на 520. После этого он запускается снова, без проблем. Я этого не понимаю

4. Ошибочно были написаны миллисекунды вместо микросекунд. Извините @molbdnilo

5. Я также придерживаюсь мнения, что ваше измерение времени нарушено, и, кроме того, вы можете захотеть понять природу асинхронных запусков ядра, потому что это также влияет на ваше измерение времени. Согласно моему тестированию, у вас есть как минимум 2 отдельные проблемы с вашим временным измерением. Я понимаю, что вы, вероятно, не согласны; делайте, как хотите.

Ответ №1:

В CUDA при указании аргументов конфигурации выполнения ядра на первом месте стоит конфигурация сетки, за которой следует конфигурация блока.

Следовательно, учитывая определение и использование переменных dimGrid и dimBlock , это неверно:

     Jacobi<<<dimBlock, dimGrid>>>
  

это должно быть:

     Jacobi<<<dimGrid, dimBlock>>>
  

Переменные конфигурации сетки и блока имеют разные ограничения, поэтому, как оказалось, первый сбой запуска, который произошел из-за путаницы, нарушающей аппаратный предел, произошел при размерах проблемы 520 520