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];
}
}
);
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
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. –
@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