pointeurs de fonction de l'appareil


11

I ont besoin d'une version de l'appareil du code hôte suivant:

double (**func)(double x); 

double func1(double x) 
{ 
return x+1.; 
} 

double func2(double x) 
{ 
return x+2.; 
} 

double func3(double x) 
{ 
return x+3.; 
} 

void test(void) 
{ 
double x; 

for(int i=0;i<3;++i){ 
    x=func[i](2.0); 
    printf("%g\n",x); 
} 

} 

int main(void) 
{ 
func=(double (**)(double))malloc(10*sizeof(double (*)(double))); 

test(); 

return 0; 
} 

où func1, func2, fonc3 doivent être fonctions __device__ et "test" doit être un (modifié de manière appropriée) __global__ noyau.

J'ai une NVIDIA GeForce GTS 450 (capacité de calcul 2.1) Nous vous remercions à l'avance Michele

======================= =================================

Une solution de travail

#define REAL double 

typedef REAL (*func)(REAL x); 

__host__ __device__ REAL func1(REAL x) 
{ 
    return x+1.0f; 
} 

__host__ __device__ REAL func2(REAL x) 
{ 
    return x+2.0f; 
} 

__host__ __device__ REAL func3(REAL x) 
{ 
    return x+3.0f; 
} 

__device__ func func_list_d[3]; 
func func_list_h[3]; 

__global__ void assign_kernel(void) 
{ 
    func_list_d[0]=func1; 
    func_list_d[1]=func2; 
    func_list_d[2]=func3; 
} 

void assign(void) 
{ 
    func_list_h[0]=func1; 
    func_list_h[1]=func2; 
    func_list_h[2]=func3; 
} 


__global__ void test_kernel(void) 
{ 
    REAL x; 
    for(int i=0;i<3;++i){ 
     x=func_list_d[i](2.0); 
     printf("%g\n",x); 
    } 
} 

void test(void) 
{ 
    REAL x; 
    printf("=============\n"); 
    for(int i=0;i<3;++i){ 
     x=func_list_h[i](2.0); 
     printf("%g\n",x); 
    } 
} 

int main(void) 
{ 
    assign_kernel<<<1,1>>>(); 
    test_kernel<<<1,1>>>(); 
    cudaThreadSynchronize(); 

    assign(); 
    test(); 

    return 0; 
} 
  0

Fonctions pointeurs ne sont pas supportés dans un code de l'appareil. 25 janv.. 122012-01-25 09:42:01

  0

@Yappie: c'est faux - les pointeurs de fonction sont supportés sur Fermi 25 janv.. 122012-01-25 10:06:36

  0

Il y a un exemple de pointeur de fonction qui est livré dans le SDK CUDA, et vous pouvez voir un exemple très similaire à votre question [dans ce post sur les forums des développeurs CUDA ] (http://forums.nvidia.com/index.php?showtopic=156792&view=findpost&p=1201985). 25 janv.. 122012-01-25 10:17:59

19

pointeurs de fonction sont autorisé sur Fermi. Voici comment vous pouvez le faire:

typedef double (*func)(double x); 

__device__ double func1(double x) 
{ 
return x+1.0f; 
} 

__device__ double func2(double x) 
{ 
return x+2.0f; 
} 

__device__ double func3(double x) 
{ 
return x+3.0f; 
} 

__device__ func pfunc1 = func1; 
__device__ func pfunc2 = func2; 
__device__ func pfunc3 = func3; 

__global__ void test_kernel(func* f, int n) 
{ 
    double x; 

    for(int i=0;i<n;++i){ 
    x=f[i](2.0); 
    printf("%g\n",x); 
    } 
} 

int main(void) 
{ 
    int N = 5; 
    func* h_f; 
    func* d_f; 
    h_f = (func*)malloc(N*sizeof(func)); 
    cudaMalloc((void**)&d_f,N*sizeof(func)); 

    cudaMemcpyFromSymbol(&h_f[0], pfunc1, sizeof(func)); 
    cudaMemcpyFromSymbol(&h_f[1], pfunc1, sizeof(func)); 
    cudaMemcpyFromSymbol(&h_f[2], pfunc2, sizeof(func)); 
    cudaMemcpyFromSymbol(&h_f[3], pfunc3, sizeof(func)); 
    cudaMemcpyFromSymbol(&h_f[4], pfunc3, sizeof(func)); 

    cudaMemcpy(d_f,h_f,N*sizeof(func),cudaMemcpyHostToDevice); 

    test_kernel<<<1,1>>>(d_f,N); 

    cudaFree(d_f); 
    free(h_f); 

    return 0; 
} 
  0

Merci beaucoup beaucoup !! Votre réponse m'a été très utile. Est-il possible d'allouer dynamiquement le tableau func_list? 25 janv.. 122012-01-25 11:56:53

  0

J'ai modifié le code pour illustrer comment utiliser l'allocation dynamique. 25 janv.. 122012-01-25 12:44:53

  0

brano Je vous suis infiniment reconnaissant pour votre aide !! Cependant j'ai trouvé cette solution de travail ... est-ce correct? Je dois faire l'affectation de "func_list_d" dans un noyau 25 janv.. 122012-01-25 13:30:21

  0

La solution de travail est écrit ci-dessous ma question originale 25 janv.. 122012-01-25 13:39:42

  0

L'exemple ci-dessus fonctionne. Si vous voulez assigner d_f dans un noyau, vous pouvez le faire. Supprimez simplement tout cudaMemcpyFromSymbol et lancez un noyau qui écrit à la place de df et utilise pfunc1, pfunc2, pfunc3. 25 janv.. 122012-01-25 13:43:47

  0

Je ne vois pas la solution de travail à laquelle vous faites référence. 25 janv.. 122012-01-25 13:48:05

  0

Maintenant, je peux le voir, oui, il semble correct. 25 janv.. 122012-01-25 13:51:32

  0

OK brano! Votre code sera un trésor pour moi dans mon futur travail 25 janv.. 122012-01-25 13:52:14

  0

Je suis heureux que je puisse vous aider. Bonne chance! P.S. Ne pas oublier d'accepter la solution. :) 25 janv.. 122012-01-25 13:59:41

  0

Pardon brano ... Je suis juste inscrit ... 25 janv.. 122012-01-25 14:12:30

  0

Je ne sais pas pourquoi vous voudriez écrire autant de code pour faire quelque chose de si simple. Si vous le faisiez dans la version gratuite de ArrayFire, ce serait ~ 5 lignes de code. http://accelereyes.com/arrayfire 25 janv.. 122012-01-25 15:23:38

  0

Je connais ArrayFire juste maintenant! Merci pour la suggestion 26 janv.. 122012-01-26 13:32:05

  0

La syntaxe de lancement du noyau dans le code affiché dans cette réponse est incorrecte. 11 sept.. 152015-09-11 02:20:58

  0

J'ai modifié le code pour utiliser la syntaxe correcte du noyau. Je vous remercie de le faire remarquer. 01 déc.. 152015-12-01 08:27:28