Menjalankan Kernel yang sama beberapa kali di OpenCL

Saya ingin menjalankan kernel (sama) beberapa kali (katakanlah 3 kali) secara paralel dengan OpenCL. Saya membaca judul thread serupa tetapi saya masih bingung. Saya sudah menulis sebuah program yang menjalankannya sekali. Saya tahu saya perlu melakukan perubahan pada clEnqueueNDKernelRangeKernel( ) dan saya mencoba tetapi gagal. Jadi mohon bisakah seseorang memberi tahu saya bagaimana saya bisa melakukannya berkali-kali. Terimakasih atas bantuannya.

//Includes
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif

#define DATA_SIZE 10

using namespace std;

const char *ProgramSource =
"__kernel void add(__global float *inputA, __global float *inputB, __global 
float *inputC, __global float *output)\n"\
"{\n"\
"  size_t id = get_global_id(0);\n"\
"float f;\n"\
"float y1 = 0.0f;\n"\
"y1 = inputA[id] + inputB[id] + inputC[id];\n"\
"  output[id] = y1;\n"\
"}\n";

int main(void)
{
cl_context context;
cl_context_properties properties[3];
cl_kernel kernel;
cl_command_queue command_queue;
cl_program program;
cl_int err;
cl_uint num_of_platforms = 0;
cl_platform_id platform_id;
cl_device_id device_id;
cl_uint num_of_devices = 0;
cl_mem inputA, inputB, inputC, output;

size_t global;

float inputDataA[DATA_SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
float inputDataB[DATA_SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
float inputDataC[DATA_SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };    
float y1[DATA_SIZE] = { 0 };
int i;

// retreive a list of platforms avaible
if (clGetPlatformIDs(1, &platform_id, &num_of_platforms) != CL_SUCCESS)
{
    printf("Unable to get platform_id\n");
    return 1;
}

// try to get a supported GPU device
if (clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, 
&num_of_devices) != CL_SUCCESS)
{
    printf("Unable to get device_id\n");
    return 1;
}

// context properties list - must be terminated with 0
properties[0] = CL_CONTEXT_PLATFORM;
properties[1] = (cl_context_properties)platform_id;
properties[2] = 0;

// create a context with the GPU device
context = clCreateContext(properties, 1, &device_id, NULL, NULL, &err);

// create command queue using the context and device
command_queue = clCreateCommandQueue(context, device_id, 0, &err);

// create a program from the kernel source code
program = clCreateProgramWithSource(context, 1, (const char 
**)&ProgramSource, NULL, &err);

// compile the program
if (clBuildProgram(program, 0, NULL, NULL, NULL, NULL) != CL_SUCCESS)
{
    printf("Error building program\n");
    return 1;
}

// specify which kernel from the program to execute
kernel = clCreateKernel(program, "add", &err);

// create buffers for the input and ouput
inputA = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float) * DATA_SIZE, NULL, NULL);
inputB = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float) * DATA_SIZE, NULL, NULL);
inputC = clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float) * DATA_SIZE, NULL, NULL);
output = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(float) * DATA_SIZE, NULL, NULL);

// load data into the input buffer
clEnqueueWriteBuffer(command_queue, inputA, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputDataA, 0, NULL, NULL);
clEnqueueWriteBuffer(command_queue, inputB, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputDataB, 0, NULL, NULL);
clEnqueueWriteBuffer(command_queue, inputC, CL_TRUE, 0, sizeof(float) * DATA_SIZE, inputDataC, 0, NULL, NULL);
// set the argument list for the kernel command
clSetKernelArg(kernel, 0, sizeof(cl_mem), &inputA);
clSetKernelArg(kernel, 1, sizeof(cl_mem), &inputB);
clSetKernelArg(kernel, 2, sizeof(cl_mem), &inputC);
clSetKernelArg(kernel, 3, sizeof(cl_mem), &output);

global = DATA_SIZE;

clEnqueueNDRangeKernel(command_queue, kernel, 1, NULL, &global, NULL, 0, NULL, NULL);
clFinish(command_queue);

// copy the results from out of the output buffer
clEnqueueReadBuffer(command_queue, output, CL_TRUE, 0, sizeof(float) *DATA_SIZE, y1, 0, NULL, NULL);

// print the results
printf("y1: ");

for (i = 0; i<DATA_SIZE; i++)
{
    printf("%f\n ", y1[i]);
}

// cleanup - release OpenCL resources
clReleaseMemObject(inputA);
clReleaseMemObject(inputB);
clReleaseMemObject(inputC);
clReleaseMemObject(output);
clReleaseProgram(program);
clReleaseKernel(kernel);
clReleaseCommandQueue(command_queue);
clReleaseContext(context);

return 0;

}


person ZSA    schedule 25.07.2018    source sumber
comment
saya mencoba tetapi gagal - apa yang Anda coba, bagaimana bisa gagal?   -  person pmdj    schedule 25.07.2018
comment
Saya mengubah parameter SetkernelArg() tetapi tidak berfungsi tetapi sekarang saya mendapatkan hasil yang benar jika saya menulis perintah clEnqueueNDKernelRangeKernel() 3 kali. Tapi saya tidak yakin apakah 3 perintah ini berjalan secara paralel secara independen.   -  person ZSA    schedule 25.07.2018
comment
Anda perlu menambahkan contoh minimal yang dapat direproduksi ke pertanyaan Anda: jika kami tidak dapat mereplikasi hasil Anda, maka akan jauh lebih sulit bagi kami untuk menawarkan saran tentang apa yang perlu diperbaiki.   -  person Xirema    schedule 25.07.2018


Jawaban (1)


Pada dasarnya Anda bekerja dengan antrian perintah dan konteks perangkat tertentu.

Dua hal:

  • If you have not specified something particularly, the commands will be executed in order and never in parallel independently on the queue.
    • Create multiple queues for each kernel execution in order to execute the kernel in parallel independently on each queue (3 queues for 3 executions).
    • Pendekatan ini sia-sia bagi banyak eksekusi paralel independen. Jadi, saya tidak melihat banyak manfaat dalam hal ini. Namun: OpenCl adalah tentang pengukuran kinerja untuk melihat manfaat dari pendekatan ini dan saya tidak tahu manfaat Anda.
  • Lebih baik tulis fungsi yang melakukan langkah-langkah (pembuatan buffer, pengisian buffer, pengaturan argumen, permintaan eksekusi kernel, membaca dari buffer, penghapusan buffer) dan memanggilnya beberapa kali. Untuk memaksimalkan kinerja, buatlah buffer hanya satu kali dan hapus buffer tersebut saat program Anda berakhir. Gunakan kembali sesering mungkin (jika Anda melakukannya secara berurutan).

Yang terakhir: Ukur peningkatan kinerja dan evaluasi pendekatan mana yang paling sesuai untuk masalah Anda.

person Akar    schedule 27.07.2018
comment
saya telah menambahkan contoh sederhana penambahan array, dapatkah Anda memberi tahu saya di mana saya perlu melakukan perubahan untuk menjalankan kernel ini 3 kali secara paralel secara mandiri. Ini akan banyak membantu ma. Terima kasih - person ZSA; 28.07.2018