2013-02-09 3 views
1

Чтобы быть более ясным, я хочу передать указатели и все данные, которые они указали на устройство. Для того, чтобы проверить, как я могу достичь этой цели, я написал простой класс:Как передать класс C++ с массивом указателей на CUDA?

class vecarray{ 
    public: 
     int * vecptr[N];    //array of pointers pointing to array 
     int dim[N];      //store length of each array pointed to 
     __device__ __host__ vecarray(); //constructor 
     __device__ __host__ int sum(); //sum up all the elements in the array being    
             //pointed to 
} 

vecarray::vecarray(){ 
    for(int i = 0; i<N; i++) 
    { 
     vecptr[i] = NULL; 
     dim[i] = 0; 
    } 
} 

int vecarray::sum(){ 
    int i=0, j=0, s=0; 
    for (i=0; i<N; i++) 
     for(j=0; j < dim[i]; j++) 
      s += vecptr[i][j]; 
    return s; 
} 

Затем я использую этот класс в следующем коде:

#define N 2 
__global__ void addvecarray(vecarray * v, int *s){ 
    *s = v->sum(); 
} 

int main(){         //copy *V to device, do sum() and pass back 
    vecarray *v, *dev_v;     //the result by dev_v 
    v = new vecarray; 
    dev_v = new vecarray; 
    int a[3] = {1,2,3};      //initialize v manually 
    int b[4] = {4,5,6,7}; 
    int result = 0; 
    int * dev_result; 
    v->vecptr[0] = a; 
    v->vecptr[1] = b; 
    v->dim[0] = 3; v->dim[1] = 4; 


    cudaMalloc((void**)&dev_v, sizeof(vecarray));  

    cudaMemcpy(dev_v, v, sizeof(vecarray),cudaMemcpyHostToDevice); //copy class object 

    for(int i = 0; i < N; i++){ 
     cudaMalloc((void**)&(dev_v->vecptr[i]), v->dim[i]*sizeof(int)); 
    } 

    for(int i = 0; i<N; i++){     //copy arrays 
    cudaMemcpy(dev_v->vecptr[i], v->vecptr[i], v->dim[i]*sizeof(int), cudaMemcpyHostToDevice)); 
    } 
    addvecarray<<<1,1>>>(dev_v, dev_result); 

    cudaMemcpy(&result, dev_result, sizeof(int), cudaMemcpyDeviceToHost); 
    printf("the result is %d\n", result); 
} 

коде, переданном NVCC компилятором, но потерпел неудачу с ошибкой сегментации при запуске. Я проверил проблему в двух операциях cudaMalloc и cudaMemcpy в for-loop. Итак, мой вопрос: как передать этот объект в CUDA? Заранее спасибо.

+0

Я считаю, что этот вопрос является дубликатом [этот] (http://stackoverflow.com/ вопросы/14284964/CUDA-хау к ассигновать-память-для-данных члена-оф-а-класс/14286341 # 14286341). В строке кода, где у вас есть цикл for, выполняющий операцию cudaMalloc, вы передаете в качестве указателя на cudaMalloc указатель, который * уже живет в памяти устройства *. Вместо этого вам нужно создать отдельный набор указателей int на хосте, cudaMalloc, затем cudaMemcpy их на устройство в соответствующих местах вашего объекта vecarray, созданного на 'dev_v'. –

ответ

3

В вашем коде было несколько ошибок. Как я уже упоминал в комментариях, одна из ключевых ошибок заключается в том, как вы распределяете память для областей данных, на которые ссылаются указатели внутри класса. Основная ошибка заключается в том, что вы передаете указатель на cudaMalloc, который уже живет в памяти устройства. Мы можем исправить это, создав дополнительный набор указателей, которые мы будем использовать для выделения необходимого хранилища устройств для массивов, на которые указывает класс. Кроме того, было еще несколько ошибок, например, тот факт, что у вас не было должным образом распределенного хранилища устройств для dev_result. Следующий код исправляет все ошибки, которые я могу найти, и я считаю, что дает правильный результат. Я также добавил ссылку форму Cuda проверки ошибок, которые могут оказаться полезными для использования в ваших проектах:

#include <stdio.h> 

#define N 2 
#define cudaCheckErrors(msg) \ 
    do { \ 
     cudaError_t __err = cudaGetLastError(); \ 
     if (__err != cudaSuccess) { \ 
      fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \ 
       msg, cudaGetErrorString(__err), \ 
       __FILE__, __LINE__); \ 
      fprintf(stderr, "*** FAILED - ABORTING\n"); \ 
      exit(1); \ 
     } \ 
    } while (0) 

using namespace std; 

class vecarray{ 
    public: 
     int *vecptr[N];    //array of pointers pointing to array 
     int dim[N];      //store length of each array pointed to 

     __device__ __host__ vecarray(); //constructor 
     __device__ __host__ int sum(); //sum up all the elements in the array being 
             //pointed to 
}; 

vecarray::vecarray(){ 
    for(int i = 0; i<N; i++) 
    { 
     vecptr[i] = NULL; 
     dim[i] = 0; 
    } 
} 

__device__ __host__ int vecarray::sum(){ 
    int i=0, j=0, s=0; 
    for (i=0; i<N; i++) 
     for(j=0; j < dim[i]; j++) 
      s += vecptr[i][j]; 
    return s; 
} 

__global__ void addvecarray(vecarray * v, int *s){ 
    *s = v->sum(); 
} 

int main(){         //copy *V to device, do sum() and pass back 
    vecarray *v, *dev_v;     //the result by dev_v 
    v = new vecarray; 
    int a[3] = {1,2,3};      //initialize v manually 
    int b[4] = {4,5,6,7}; 
    int result = 0; 
    int *dev_result; 
    v->vecptr[0] = a; 
    v->vecptr[1] = b; 
    v->dim[0] = 3; v->dim[1] = 4; 
    int *vptr[N]; 

    cudaMalloc((void**)&dev_v, sizeof(vecarray)); 
    cudaCheckErrors("cudaMalloc1 fail"); 
    cudaMemcpy(dev_v, v, sizeof(vecarray),cudaMemcpyHostToDevice); //copy class object 
    cudaCheckErrors("cudaMemcpy1 fail"); 

    for(int i = 0; i < N; i++){ 
     cudaMalloc((void**)&(vptr[i]), v->dim[i]*sizeof(int)); 
     cudaCheckErrors("cudaMalloc2 fail"); 
     cudaMemcpy(&(dev_v->vecptr[i]), &vptr[i], sizeof(int*), cudaMemcpyHostToDevice); 
     cudaCheckErrors("cudaMemcpy2 fail"); 
    } 

    for(int i = 0; i<N; i++){     //copy arrays 
     cudaMemcpy(vptr[i], v->vecptr[i], v->dim[i]*sizeof(int), cudaMemcpyHostToDevice); 
     cudaCheckErrors("cudaMemcpy3 fail"); 
    } 
    cudaMalloc((void **)&dev_result, sizeof(int)); 
    cudaCheckErrors("cudaMalloc3 fail"); 
    addvecarray<<<1,1>>>(dev_v, dev_result); 

    cudaMemcpy(&result, dev_result, sizeof(int), cudaMemcpyDeviceToHost); 
    cudaCheckErrors("cudaMemcpy4 fail"); 
    printf("the result is %d\n", result); 
    return 0; 
} 
+0

Большое спасибо. Код работает. Я заметил, что в теме дублированного вопроса, упомянутой выше, Эрик упомянул в первом комментарии, что причиной такого рода ошибок является то, что мы пытаемся разыменовать указатель, указывающий на адрес устройства на хосте, что также я слышал в некоторых других местах. Но здесь, в первом для цикла кода выше, первый параметр cudaMemcpy, & (dev_v-> vecptr [i]) также выполняет операцию разыменования сначала внутри скобки, так как она равна & ((* dev) .vecptr [я]). Если это так, не существует конфликта между заявлением и кодом? – Stone

+0

Кроме того, могу ли я спросить, почему мы не можем передать указатель на cudaMalloc() указатель, который уже указал на адрес? Я имею в виду, что это предотвращает утечку памяти. Поскольку, если мы перемещаем указатель, указывая на новый адрес, возвращаемый cudaMalloc(), мы теряем отслеживание переменных, находящихся в предыдущем адресе, указанном одним и тем же указателем, и мы больше не можем больше обращаться к этой памяти. Это верно? Еще раз спасибо. – Stone

+0

О, просьба игнорировать второй вопрос выше. Я просто понял, почему, как вы сказали в другой теме. Прошу прещения за это. – Stone