CUDA - Почему данные моего устройства не передаются на хост? - PullRequest
1 голос
/ 15 ноября 2011

В настоящее время у меня исключительные трудности с программированием на CUDA, в частности, с копированием и чтением массива, который устройство отправляет обратно на хост.Когда я пытаюсь прочитать данные, которые я должен был вернуть мне, я получаю только ненужные данные.Может ли кто-нибудь взглянуть на мои фрагменты кода и сказать, что я делаю неправильно?Большое спасибо!

struct intss {
u_int32_t one;
u_int32_t two;
};



int main()
{
    int block_size = 3;             
    int grid_size = 1;

    intss *device_fb = 0;
    intss *host_fb = 0;


    int num_bytes_fb = (block_size*grid_size)*sizeof(intss);


host_fb = (intss*)malloc(num_bytes_fb); 
cudaMalloc((void **)&device_fb, num_bytes_fb);

    ....

    render2<<<block_size,grid_size>>>(device_fb, device_pixelspercore, samples, obj_list_flat_dev, numOpsPerCore, lnumdev, camdev, lightsdev, uranddev, iranddev);


    ....

   cudaMemcpy(host_fb, device_fb, num_bytes_fb, cudaMemcpyDeviceToHost);


   printf("output %d ", host_fb[0].one);

   printf("output %d ", host_fb[1].one);

   printf("output %d ", host_fb[2].one);   
   //Note that I'm only looking at elements the 3 elements 0-2 from host_fb. I am   doing this because block_size*grid_size = 3. Is this wrong?

    cudaFree(device_fb);
    free(host_fb);
}


__global__ void render2(intss *device_fb, struct parallelPixels *pixelsPerCore, int     samples, double *obj_list_flat_dev, int numOpsPerCore, int lnumdev, struct camera camdev, struct vec3 *lightsdev, struct vec3 *uranddev, int *iranddev)            //SPECIFY ARGUMENTS!!!
{
int index = blockIdx.x * blockDim.x + threadIdx.x; //DETERMINING INDEX BASED ON WHICH THREAD IS CURRENTLY RUNNING

....

//computing data...


device_fb[index].one = (((u_int32_t)(MIN(r, 1.0) * 255.0) & 0xff) << RSHIFT |   
                  ((u_int32_t)(MIN(g, 1.0) * 255.0) & 0xff) << GSHIFT |
                  ((u_int32_t)(MIN(b, 1.0) * 255.0) & 0xff) << BSHIFT);
}

РЕДАКТИРОВАТЬ:

Благодаря предложению я реализовал функцию CudaErrorCheck в моей программе, и, кажется, существует шаблон, в котором функции дают мнеошибки.

В моей программе у меня есть несколько глобальных хост-массивов (obj_list, lights, urand, irand).Всякий раз, когда я пытаюсь использовать cudaMemCpy для копирования этих хост-массивов в массивы устройств, я получаю следующую ошибку: «Ошибка Cuda в файле 'cudatrace.cu' в строке x: неверный аргумент."

obj_list и огни заполненыв следующей функции load_scene ():

void load_scene (FILE * fp) {char line [256], * ptr, type;

obj_list = (sphere *)malloc(sizeof(struct sphere));
obj_list->next = 0;
objCounter = 0;

while((ptr = fgets(line, 256, fp))) {
    int i;
    struct vec3 pos, col;
    double rad, spow, refl;

    while(*ptr == ' ' || *ptr == '\t') ptr++;
    if(*ptr == '#' || *ptr == '\n') continue;

    if(!(ptr = strtok(line, DELIM))) continue;
    type = *ptr;

    for(i=0; i<3; i++) {
        if(!(ptr = strtok(0, DELIM))) break;
        *((double*)&pos.x + i) = atof(ptr);
    }

    if(type == 'l') {
        lights[lnum++] = pos;
        continue;
    }

    if(!(ptr = strtok(0, DELIM))) continue;
    rad = atof(ptr);

    for(i=0; i<3; i++) {
        if(!(ptr = strtok(0, DELIM))) break;
        *((double*)&col.x + i) = atof(ptr);
    }

    if(type == 'c') {
        cam.pos = pos;
        cam.targ = col;
        cam.fov = rad;
        continue;
    }

    if(!(ptr = strtok(0, DELIM))) continue;
    spow = atof(ptr);

    if(!(ptr = strtok(0, DELIM))) continue;
    refl = atof(ptr);

    if(type == 's') { 
        objCounter++;
        struct sphere *sph = (sphere *)malloc(sizeof(*sph));
        sph->next = obj_list->next;
        obj_list->next = sph;

        sph->pos = pos;
        sph->rad = rad;
        sph->mat.col = col;
        sph->mat.spow = spow;
        sph->mat.refl = refl;

    } else {
        fprintf(stderr, "unknown type: %c\n", type);
    }
}

}

urand и irand заполняются в main следующим образом:

/* initialize the random number tables for the jitter */
for(i=0; i<NRAN; i++) urand[i].x = (double)rand() / RAND_MAX - 0.5;
for(i=0; i<NRAN; i++) urand[i].y = (double)rand() / RAND_MAX - 0.5;
for(i=0; i<NRAN; i++) irand[i] = (int)(NRAN * ((double)rand() / RAND_MAX));

Я не думаю, что недопустимый аргумент мог быть вызван массивом устройств, поскольку вызов cudaMalloc, создающий массив устройств до вызова cudaMemcpy, не имелсообщение CudaError.Например, в следующих строках кода:

cudaErrorCheck(cudaMalloc((void **)&lightsdev, MAX_LIGHTS*sizeof(struct vec3)) );

cudaErrorCheck( cudaMemcpy(&lightsdev, &lights, sizeof(struct vec3) * MAX_LIGHTS, cudaMemcpyHostToDevice) );

cudaMalloc не выдал ошибку, но cudaMemcpy сделал.

Если я не предоставил достаточно информации о своем коде, я вставилвесь код: http://pastebin.com/UgzABPgH

(Обратите внимание, что в версии pastebin я удалил функции CudaErrorCheck на CudaMemcpy, которые вызывали ошибки.)

Большое спасибо!

РЕДАКТИРОВАТЬ: На самом деле, я просто пытался увидеть, что произойдет, если urand и irand не являются глобальными, и если они были инициализированы вместе с массивами устройств uranddev и iranddev.Я все еще получаю ту же ошибку «неверный аргумент», поэтому вопрос о том, является ли переменная глобальной или нет, не должен относиться к проблеме.

Ответы [ 2 ]

4 голосов
/ 15 ноября 2011

Абсолютно невозможно что-либо сказать, если вы разместили неполный, некомпилируемый код без надлежащего описания фактической проблемы. Вы получите лучшие ответы, задавая лучшие вопросы в StackOverflow.

Сказав это. наиболее вероятная проблема не в том, что данные не копируются на устройство или с него, а в том, что само ядро ​​не работает. Каждый вызов API среды выполнения CUDA возвращает код состояния, и вы должны проверять их все. Вы можете определить макрос проверки ошибок следующим образом:

#include <stdio.h>

#define cudaErrorCheck(call) { cudaAssert(call,__FILE__,__LINE__) }

void cudaAssert(const cudaError err, const char *file, const int line)
{ 
    if( cudaSuccess != err) {                                                
        fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n",        
                file, line, cudaGetErrorString(err) );
        exit(1);
    } 
}

и добавьте в него каждый вызов API, например:

cudaErrorCheck( cudaMemcpy(host_fb, device_fb, num_bytes_fb, cudaMemcpyDeviceToHost) );

Для запуска ядра вы можете самостоятельно проверить наличие ошибки запуска или ошибки времени выполнения:

kernel<<<....>>>();
cudaErrorCheck( cudaPeekAtLastError() ); // Checks for launch error
cudaErrorCheck( cudaThreadSynchronize() ); // Checks for execution error

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

0 голосов
/ 15 ноября 2011

Я думаю, вы неправильно используете синтаксис <<< >>>.

Вот вызов ядра из Руководства по программированию CUDA :

MatAdd<<<numBlocks, threadsPerBlock>>>(A, B, C);

, что означает, что размер сетки должен идти первым.

Существует также ограничение на максимальный размер аргументов ядра. Смотрите это . Если вы пойдете выше этого, я не уверен, жалуется ли компилятор или просто продолжает делать неприятные вещи.

Если я уберу все аргументы, кроме device_fb, и просто установлю device_fb[index]=index в ядре, я смогу успешно прочитать значения.

...