2017-09-05 2 views
2

J'ai l'intention d'effectuer des manipulations vectorielles et j'essayais un petit programme fictif avec addition et multiplication de vecteurs. Toutefois, le code ne s'exécute pas en raison de limitations sur mes connaissances sur la mémoire partagée. Toutes les sources sur Internet montrent des opérations matricielles 2D que je ne peux pas traduire en problèmes vectoriels. S'il vous plaît essayez d'expliquer où je me trompe compte tenu du fait que je suis un débutant dans OpenCL. Le code est donné ci-dessous:Mémoire partagée dans OpenCL

Code hôte:

std::vector<cl::Platform> platforms; 
std::vector<cl::Device> devices; 
cl::Context context; 
cl::CommandQueue queue; 
cl::Program program; 
cl::Kernel kernel; 

cl::Platform::get(&platforms); 

deviceUsed = 0; 

cl_context_properties properties[] = 
{ CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(),0 }; 

context = cl::Context(CL_DEVICE_TYPE_ALL, properties); 
devices = context.getInfo<CL_CONTEXT_DEVICES>(); 

queue = cl::CommandQueue(context, devices[deviceUsed]); 
cl::Program::Sources source(1, std::make_pair(kernel_source.c_str(), kernel_source.size())); 
program = cl::Program(context, source); 
program.build(devices); 

std::vector <float> a; 
std::vector <float> b; 
std::vector <float> sum; 
std::vector <float> prod; 

int globalSize = 128; 
int localSize = 16; 

a.resize(globalSize); 
b.resize(globalSize); 
sum.resize(globalSize); 
prod.resize(globalSize); 

for (int i = 0; i < globalSize ; i++) 
{ 
    a[i] = 1.0f * i; 
    b[i] = 5.0f * i; 
} 
cl::Buffer buffer_A; 
cl::Buffer buffer_B; 
cl::Buffer buffer_sum; 
cl::Buffer buffer_prod; 

buffer_A = cl::Buffer (context, CL_MEM_READ_WRITE, sizeof(float) * globalSize); 
buffer_B = cl::Buffer (context, CL_MEM_READ_WRITE, sizeof(float) * globalSize); 

queue.enqueueWriteBuffer(buffer_A, CL_TRUE, 0, sizeof(float) * globalSize , &a[0]); 
queue.enqueueWriteBuffer(buffer_B, CL_TRUE, 0, sizeof(float) * globalSize , &b[0]); 

buffer_sum = cl::Buffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * globalSize); 
buffer_prod = cl::Buffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * globalSize); 

kernel.setArg(0, buffer_A); 
kernel.setArg(1, buffer_B); 
kernel.setArg(2, buffer_sum); 
kernel.setArg(3, buffer_prod); 

queue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(globalSize/localSize), cl::NDRange(N), NULL); 
queue.finish(); 
queue.enqueueReadBuffer(buffer_sum, CL_TRUE, 0, sizeof(float) * globalSize, &sum[0]); 
queue.enqueueReadBuffer(buffer_prod, CL_TRUE, 0, sizeof(float) * globalSize, &prod[0]); 

Noyau:

#define STRINGI(ker) #ker 
std::string kernel_source = STRINGI(

__kernel void KernelAddMul(__global float* a, __global float* b, __global float* sum, __global float* prod) 
{ 
    unsigned int j = get_local_id(0); 
    int N = get_local_size(0); 
    unsigned int i = N * get_global_id(0) + j; 

    float locSum[N]; 
    float locProd[N]; 

    __local float Asub[N]; 
    __local float Bsub[N]; 

    for(int k = 0; k < N; k++){ 

     Asub[k] = a[i]; 
     Bsub[k] = b[i]; 
     barrier(CLK_LOCAL_MEM_FENCE); 

     locSum[k] = Asub[k] + Bsub[k]; 
     locProd[k] = Asub[k] * Bsub[k]; 
     barrier(CLK_LOCAL_MEM_FENCE); 

     sum[i] = locSum[k]; 
     prod[i] = locProd[k]; 
    } 

} 

); 
+1

La mémoire partagée est une mémoire plus rapide qui n'est visible que dans un groupe de travail. Entre les noyaux, les données sont accessibles via la mémoire globale à l'aide de tampons cl, de sorte que la mémoire partagée peut uniquement être "allouée" et utilisée dans un noyau. Pour 1D, vous utiliserez probablement la mémoire partagée pour la réduction, en enregistrant des valeurs intermédiaires pour éviter de réécrire dans la mémoire globale. Pour y accéder, utilisez '__local__'. – theoden

+0

Que voulez-vous dire que votre code ne fonctionne pas? Est-ce qu'il fonctionne et donne de mauvais résultats ou échoue-t-il? Vous devriez vérifier chaque appel OpenCL pour voir si elles retournent CL_SUCCESS. Ce serait bénéfique pour nous si vous pouviez fournir plus d'informations. –

+0

@parallelhighway J'utilise le SDK Intel et le code compile. Mais quand j'imprime les valeurs de sum et prod retournées par le noyau, il affiche tous les 0. Je suppose qu'il me manque quelque chose de trivial. Il peut y avoir un problème avec les arguments de l'instruction enqueueNDRangeKernel dans le code hôte ou le code noyau où la mémoire locale et globale communique. S'il vous plaît jeter un oeil sur le code une fois. Merci :) – Ijjz

Répondre

2

Je pense que votre code ne fonctionne pas parce que votre noyau ne compile pas.

Les lignes suivantes ne sont pas valides:

int N = get_local_size(0); 

float locSum[N]; 
float locProd[N]; 

__local float Asub[N]; 
__local float Bsub[N]; 

N doit être une constante, vous ne pouvez pas dimensionner dynamiquement les tableaux à l'aide get_local_size(0).

Je recommande fortement que vous utilisez un compilateur autonome pour compiler vos noyaux: CodeXL est très bon, tout comme le Intel SDK for OpenCL. Tout est mieux que d'essayer de déboguer votre noyau dans une application!

+0

J'utilise le SDK Intel et le code compile. Mais quand j'imprime les valeurs de sum et prod retournées par le noyau, il affiche tous les 0. Même si je code dur la valeur N = 16, le résultat est le même. Je suppose qu'il me manque quelque chose de trivial. Il peut y avoir un problème avec les arguments de l'instruction enqueueNDRangeKernel dans le code hôte ou le code noyau où la mémoire locale et globale communique. S'il vous plaît jeter un oeil sur le code une fois. Merci :) – Ijjz

+0

@Ejaz J'ai couru votre noyau à la fois par CodeXL et le SDK Intel et ils ne parviennent pas à compiler, Intel a donné l'erreur "les tableaux de longueur variable ne sont pas supportés dans OpenCL" même avec N = 16. Votre code hôte me semble correct, mais j'utilise 'clEnqueueNDRangeKernel', donc je ne connais pas l'API que vous utilisez ... – kenba

+0

Oh. Je ne suis pas capable de comprendre ce qui ne va pas dans ce code qui ajoute simplement deux vecteurs. Pouvez-vous identifier quelle erreur je fais ou fournir une solution de travail alternative? – Ijjz