2012-08-08 4 views
4

J'ai ces struct:CUDA: l'attribution d'un tableau de struct dans une struct

typedef struct neuron 
{ 
float* weights; 
int n_weights; 
}Neuron; 


typedef struct neurallayer 
{ 
Neuron *neurons; 
int n_neurons; 
int act_function; 
}NLayer; 

« nLayer » struct peut contenir un nombre arbitraire de « Neuron »

J'ai essayé de allouent une struct « nLayer » avec 5 « neurones » de l'hôte de cette façon:

NLayer* nL; 
int i; 
int tmp=9; 
cudaMalloc((void**)&nL,sizeof(NLayer)); 
cudaMalloc((void**)&nL->neurons,6*sizeof(Neuron)); 
for(i=0;i<5;i++) 
    cudaMemcpy(&nL->neurons[i].n_weights,&tmp,sizeof(int),cudaMemcpyHostToDevice); 

... alors j'ai essayé de modifier les « NL-> neurones [0] .n_weights » variable que le noyau :

__global__ void test(NLayer* n) 
      { 
       n->neurons[0].n_weights=121; 
      } 

mais le temps de compilation revient FPUNV que « avertissement » lié à la seule ligne du noyau:

Warning: Cannot tell what pointer points to, assuming global memory space 

et lorsque le noyau terminé son travail inatteignable commencer la struct.

C'est très probablement que je fais quelque chose de mal lors de l'allocation .... quelqu'un peut m'aider ?? Merci beaucoup, et désolé pour mon anglais! :)

MISE À JOUR:

Merci à Aland J'ai modifié mon code la création de cette fonction qui doit allouer une instance de la struct "nLayer":

NLayer* setNLayer(int numNeurons,int weightsPerNeuron,int act_fun) 
{ 
    int i; 
    NLayer h_layer; 
    NLayer* d_layer; 
    float* d_weights; 

    //SET THE LAYER VARIABLE OF THE HOST NLAYER 
    h_layer.act_function=act_fun; 
    h_layer.n_neurons=numNeurons; 
    //ALLOCATING THE DEVICE NLAYER 
    if(cudaMalloc((void**)&d_layer,sizeof(NLayer))!=cudaSuccess) 
     puts("ERROR: Unable to allocate the Layer"); 
    //ALLOCATING THE NEURONS ON THE DEVICE 
    if(cudaMalloc((void**)&h_layer.neurons,numNeurons*sizeof(Neuron))!=cudaSuccess) 
     puts("ERROR: Unable to allocate the Neurons of the Layer"); 
    //COPING THE HOST NLAYER ON THE DEVICE 
    if(cudaMemcpy(d_layer,&h_layer,sizeof(NLayer),cudaMemcpyHostToDevice)!=cudaSuccess) 
       puts("ERROR: Unable to copy the data layer onto the device"); 

    for(i=0;i<numNeurons;i++) 
    { 
     //ALLOCATING THE WEIGHTS' ARRAY ON THE DEVICE 
     cudaMalloc((void**)&d_weights,weightsPerNeuron*sizeof(float)); 
     //COPING ITS POINTER AS PART OF THE i-TH NEURONS STRUCT 
     if(cudaMemcpy(&d_layer->neurons[i].weights,&d_weights,sizeof(float*),cudaMemcpyHostToDevice)!=cudaSuccess) 
       puts("Error: unable to copy weights' pointer to the device"); 
    } 


    //RETURN THE DEVICE POINTER 
    return d_layer; 
} 

et j'appeler cette fonction de la principale de cette façon (le noyau « test » est déjà déclarée):

int main() 
{ 
    NLayer* nL; 
    int h_tmp1; 
    float h_tmp2; 

    nL=setNLayer(10,12,13); 
    test<<<1,1>>>(nL); 
    if(cudaMemcpy(&h_tmp1,&nL->neurons[0].n_weights,sizeof(float),cudaMemcpyDeviceToHost)!=cudaSuccess); 
     puts("ERROR!!"); 
    printf("RESULT:%d",h_tmp1); 

} 

Quand je compile ce code le spectacle du compilateur moi l'avertissement, et quand je l'exécution du programme, il imprime à l'écran:

Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
Error: unable to copy weights' pointer to the device 
ERROR!! 
RESULT:1 

La dernière erreur ne compare pas si je commente l'appel du noyau.

Où est-ce que je me trompe? Je ne sais pas comment faire Merci pour votre aide!

Répondre

0

Tout dépend de la carte GPU que vous utilisez. La carte de Fermi utilise un adressage uniforme de l'espace mémoire partagé et global, contrairement aux cartes pré-Fermi.

Pour le cas pré-Fermi, vous ne savez pas si l'adresse doit être partagée ou globale. Le compilateur peut généralement comprendre cela, mais il y a des cas où il ne le peut pas. Lorsqu'un pointeur vers la mémoire partagée est requis, vous prenez généralement une adresse d'une variable partagée et le compilateur peut le reconnaître. Le message "supposant global" apparaîtra lorsque ceci n'est pas explicitement défini.

Si vous utilisez un GPU qui a Compute capabiilty 2.x ou plus, il devrait fonctionner avec le -arch = compilateur sm_20 drapeau

+0

Alors que vous avez raison à propos de l'avertissement, je doute que ce soit ce qui provoque un comportement anormal du programme. Après tout, l'hypothèse du compilateur sur la structure résidant dans l'espace emory global est correcte ... – aland

+0

J'utilise un NVIDIA GeForce 320M 256 Mo avec la capacité 1.2, donc je ne pense pas que ce soit une carte "Fermi" –

5

Le problème est ici:

cudaMalloc((void**)&nL,sizeof(NLayer)); 
cudaMalloc((void**)&nL->neurons,6*sizeof(Neuron)); 

En premier ligne, nL pointe vers la structure dans la mémoire globale sur le périphérique. Par conséquent, en deuxième ligne, le premier argument à cudaMalloc est adresse résidant sur GPU, ce qui est un comportement indéfini (sur mon système de test, il provoque segfault, dans votre cas, cependant, il y a quelque chose de plus subtil).

La bonne façon de faire ce que vous voulez est d'abord de créer une structure en mémoire hôte, le remplir avec des données, puis copiez-le à l'appareil, comme ceci:

NLayer* nL; 
NLayer h_nL; 
int i; 
int tmp=9; 
// Allocate data on device 
cudaMalloc((void**)&nL, sizeof(NLayer)); 
cudaMalloc((void**)&h_nL.neurons, 6*sizeof(Neuron)); 
// Copy nlayer with pointers to device 
cudaMemcpy(nL, &h_nL, sizeof(NLayer), cudaMemcpyHostToDevice); 

En outre, ne pas oublier de vérifiez toujours les erreurs des routines CUDA.

MISE À JOUR

Dans la deuxième version de votre code:

cudaMemcpy(&d_layer->neurons[i].weights,&d_weights,...) --- à nouveau, vous pointeur de périphérique déréférencement (d_layer) sur l'hôte. Au lieu de cela, vous devez utiliser

cudaMemcpy(&h_layer.neurons[i].weights,&d_weights,sizeof(float*),cudaMemcpyHostToDevice 

vous prenez ici h_layer (structure d'accueil), lire son élément (h_layer.neurons), qui est le pointeur à la mémoire de l'appareil. Ensuite, vous faites un peu d'arithmétique de pointeur dessus (&h_layer.neurons[i].weights). Aucun accès à la mémoire de l'appareil n'est nécessaire pour calculer cette adresse.

+0

J'ai modifié mon code, mais ça ne marche pas, pourriez-vous jeter un oeil? Le nouveau code est dans mon message initial ... Merci! –

+0

Oh! Merci ça fonctionne !! Je n'ai qu'une autre question: Si je veux accéder à partir de l'hôte aux données contenues dans la variable entière ** d_layer-> neurones [0] .n_weights ** Je dois auparavant copier ** d_layer ** sur l'hôte, alors je dois copier le ** d_layer-> neurones [0] ** sur l'hôte, puis, finalement, je peux prendre la variable "d_layer-> neurones [0] .n_weights ?? Je le demande juste parce que J'ai essayé de copier directement les "d_layer-> neurones [0] .n_weights avec cudaMemcpy (...), mais cela retourne toujours une erreur" argument invalide ". –

+0

@AndreaSylarSolla Vous pouvez simplement utiliser 'int t; cudaMemcpy (& t, & h_layer.neurons [0] .n_weights, ....) 'ou' Neuron t; cudaMemcpy (& t, & h_layer.neurons [0], ....) '. Il n'est pas nécessaire de copier 'd_layer', puisque vous n'avez besoin que de la valeur du pointeur' neurons', mais la même valeur est déjà dans 'h_layer'. – aland