2009-12-02 8 views
2

J'ai des problèmes avec allouer tableau de tableaux dans CUDA.CUDA allouer un tableau de tableaux

void ** data; 
cudaMalloc(&data, sizeof(void**)*N); // allocates without problems 
for(int i = 0; i < N; i++) { 
    cudaMalloc(data + i, getSize(i) * sizeof(void*)); // seg fault is thrown 
} 

Qu'est-ce que je me suis trompé?

+0

Le point principal de cela est que tous ces tableaux ont des tailles différentes. –

Répondre

4

Je ne crois pas que cela soit pris en charge. cudaMalloc() alloue la mémoire de l'appareil, mais stocke l'adresse dans une variable sur l'hôte. Dans votre boucle for, vous lui transmettez des adresses dans la mémoire de l'appareil.

En fonction de ce que vous essayez d'accomplir, vous pouvez affecter data à l'hôte normal malloc() avant d'appeler la boucle for comme vous l'avez actuellement. Ou allouez un seul gros bloc de mémoire de périphérique et calculez les décalages manuellement.

Examinez les sections 2.4, 3.2.1 et B.2.5 (en bas) du CUDA Programming Guide pour plus d'informations à ce sujet. Plus précisément, sur le bas de la page 108:

L'adresse obtenue en prenant l'adresse d'une variable __device__, ou __shared__ __constant__ ne peut être utilisé dans le code de l'appareil.

+1

Ceci est correct. Le pointeur alloué par cudaMalloc doit résider dans la mémoire de l'hôte et vous essayez de stocker ces pointeurs dans la mémoire de l'appareil. Au lieu de cela, vous devez créer un tableau de pointeurs sur l'hôte, puis le copier sur l'appareil à la fin, ou simplement calculer des décalages comme le suggère Gabriel. – Tom

8

Vous devez allouer les pointeurs à une mémoire hôte, puis allouer de la mémoire de périphérique pour chaque baie et stocker son pointeur dans la mémoire hôte. Ensuite, allouez la mémoire pour stocker les pointeurs dans l'appareil , puis copiez la mémoire de l'hôte dans la mémoire de l'appareil. Un exemple vaut 1000 mots:

__global__ void multi_array_kernel(int N, void** arrays){ 
    // stuff 
} 


int main(){ 

    const int N_ARRAYS = 20; 
    void *h_array = malloc(sizeof(void*) * N_ARRAYS); 
    for(int i = 0; i < N_ARRAYS; i++){ 
     cudaMalloc(&h_array[i], i * sizeof(void*)); 
     //TODO: check error 
    } 
    void *d_array = cudaMalloc(sizeof(void*) * N_ARRAYS); 

    // Copy to device Memory 
    cudaMemcpy(d_array, h_array, sizeof(void*) * N_ARRAYS, cudaMemcpyHostToDevice); 

    multi_array_kernel<1,1>(N_ARRAYS, d_array); 
    cudaThreadSynchronize(); 

    for(int i = 0; i < N_ARRAYS; i++){ 
     cudaFree(h_array[i]); //host not device memory 
     //TODO: check error 
    } 
    cudaFree(d_array); 
    free(h_array); 
} 
+0

fabrizioM, pouvez-vous expliquer comment travailler sur chaque tableau une fois qu'il est copié sur l'appareil? Je fais quelque chose de mal quand j'essaie d'accéder à chaque tableau. – braviato

+0

@braviato Poster une nouvelle question à SO – fabrizioM

+1

Je suppose que vous voulez dire N_ARRAYS au lieu de N dans votre fonction principale –

2

Je pense que dans la première boucle, il devrait être &h_array[i] pas &d_array[i].

1

vous ne pouvez pas utiliser

cudaMalloc(&h_array[i], i * sizeof(void*)); 

pour tableau déclaré que void *

utilisation type de données

CUdeviceptr *h_array = malloc(sizeof(CUdeviceptr *) * N); 

ou

int *h_array = malloc(sizeof(int *) * N); 

et de le jeter à void *

cudaMalloc((void *)&h_array[i], i * sizeof(void*)); 
0

J'ai eu le même problème et a réussi à le résoudre.

La réponse de FabrizioM a été un bon point de départ pour moi et m'a beaucoup aidé. Mais néanmoins j'ai rencontré quelques problèmes quand j'ai essayé de transférer le code à mon projet. En utilisant les commentaires et les messages supplémentaires j'ai pu écrire un exemple de travail (VS2012, CUDA7.5). Ainsi, je vais poster mon code comme réponse supplémentaire et comme point de départ pour les autres.

Pour comprendre la dénomination: J'utilise un vecteur d'OpenCV cv :: Mat en entrée qui est capturé à partir de plusieurs caméras et je suis en train de traiter ces images dans le noyau.

 void TransferCameraImageToCuda(const std::vector<cv::Mat*>* Images) 
{ 

    int NumberCams  = Images->size(); 
    int imageSize  = Images->at(0)->cols*Images->at(0)->rows; 

    CUdeviceptr*   CamArraysAdressOnDevice_H; 
    CUdeviceptr*   CamArraysAdressOnDevice_D; 


     //allocate memory on host to store the device-address of each array 
     CamArraysAdressOnDevice_H = new CUdeviceptr[NumberCams]; 

     // allocate memory on the device and store the arrays on the device 
     for (int i = 0; i < NumberCams; i++){ 
      cudaMalloc((void**)&(CamArraysAdressOnDevice_H[i]), imageSize * sizeof(unsigned short)); 
      cudaMemcpy((void*)CamArraysAdressOnDevice_H[i], Images->at(i)->data, imageSize * sizeof(unsigned short), cudaMemcpyHostToDevice); 
     } 

     // allocate memory on the device to store the device-adresses of the arrays 
     cudaMalloc((void**)&CamArraysAdressOnDevice_D, sizeof(CUdeviceptr*)* NumberCams); 

     // Copy the adress of each device array to the device 
     cudaMemcpy(CamArraysAdressOnDevice_D, CamArraysAdressOnDevice_H, sizeof(CUdeviceptr*)* NumberCams, cudaMemcpyHostToDevice); 




} 

Dans le lancement du noyau que je suis coulée le pointeur de l'appareil au pointeur de type de données (unsigned short **)

DummyKernel<<<gridDim,blockDim>>>(NumberCams, (unsigned short**) CamArraysAdressOnDevice_D) 

et la définition du noyau est par exemple:

__global__ void DummyKernel(int NumberImages, unsigned short** CamImages) 
{ 
    int someIndex = 3458; 
    printf("Value Image 0 : %d \n", CamImages[0][someIndex]); 
    printf("Value Image 1 : %d \n", CamImages[1][someIndex]); 
    printf("Value Image 2 : %d \n", CamImages[2][someIndex]); 
} 
Questions connexes