1

それぞれ100個のセルからなる2つの行列を追加しようとしています。タスク並列でそれを行う必要があります。並列データはありません。同じ行列で加算、乗算、減算、除算を行う次のコードを取得しましたが、実行すると0のみ、または2、-0、-2などが返されます...

MACのOpenCLでそれを行う必要がありますこれを行う方法について何かアイデアはありますか?

#include <stdio.h>
#include <stdlib.h>

#include <OpenCL/opencl.h>

#define MAX_SOURCE_SIZE (0x100000)

const char *_kernel = "\n" \
"__kernel void taskParallelAdd(__global float* A, __global float* B, __global float* C) \n" \
"{ \n" \
"    int base = 0; \n" \
"     \n" \
"    C[base+0]  = A[base+0]  + B[base+0]; \n" \
"    C[base+4]  = A[base+4]  + B[base+4]; \n" \
"    C[base+8]  = A[base+8]  + B[base+8]; \n" \
"    C[base+12] = A[base+12] + B[base+12]; \n" \
"} \n" \
" \n" \
"__kernel void taskParallelSub(__global float* A, __global float* B, __global float* C) \n" \
"{ \n" \
"    int base = 1; \n" \
"     \n" \
"    C[base+0]  = A[base+0]  - B[base+0]; \n" \
"    C[base+4]  = A[base+4]  - B[base+4]; \n" \
"    C[base+8]  = A[base+8]  - B[base+8]; \n" \
"    C[base+12] = A[base+12] - B[base+12]; \n" \
"} \n" \
" \n" \
"__kernel void taskParallelMul(__global float* A, __global float* B, __global float* C) \n" \
"{ \n" \
"    int base = 2; \n" \
"     \n" \
"    C[base+0]  = A[base+0]  * B[base+0]; \n" \
"    C[base+4]  = A[base+4]  * B[base+4]; \n" \
"    C[base+8]  = A[base+8]  * B[base+8]; \n" \
"    C[base+12] = A[base+12] * B[base+12]; \n" \
"} \n" \
" \n" \
"__kernel void taskParallelDiv(__global float* A, __global float* B, __global float* C) \n" \
"{ \n" \
"    int base = 3; \n" \
"     \n" \
"    C[base+0]  = A[base+0]  / B[base+0]; \n" \
"    C[base+4]  = A[base+4]  / B[base+4]; \n" \
"    C[base+8]  = A[base+8]  / B[base+8]; \n" \
"    C[base+12] = A[base+12] / B[base+12]; \n" \
"} \n" \
" \n";

int main()
{
    cl_platform_id platform_id = NULL;
    cl_device_id device_id = NULL;
    cl_context context = NULL;
    cl_command_queue command_queue = NULL;
    cl_mem Amobj = NULL;
    cl_mem Bmobj = NULL;
    cl_mem Cmobj = NULL;
    cl_program program = NULL;
    cl_kernel kernel[4] = {NULL, NULL, NULL, NULL};
    cl_uint ret_num_devices;
    cl_uint ret_num_platforms;
    cl_int ret;

    int i, j;
    float* A;
    float* B;
    float* C;

    A = (float*)malloc(4*4*sizeof(float));
    B = (float*)malloc(4*4*sizeof(float));
    C = (float*)malloc(4*4*sizeof(float));

    /* Initialize input data */
    for (i=0; i<4; i++) {
        for (j=0; j<4; j++) {
            A[i*4+j] = i*4+j+1;
            B[i*4+j] = j*4+i+1;
        }
    }

    /* Get platform/device information */
    ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
    ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices);

    /* Create OpenCL Context */
    context = clCreateContext( NULL, 1, &device_id, NULL, NULL, &ret);

    /* Create command queue */
    command_queue = clCreateCommandQueue(context, device_id, CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, &ret);

    /* Create buffer object */
    Amobj = clCreateBuffer(context, CL_MEM_READ_WRITE, 4*4*sizeof(float), NULL, &ret);
    Bmobj = clCreateBuffer(context, CL_MEM_READ_WRITE, 4*4*sizeof(float), NULL, &ret);
    Cmobj = clCreateBuffer(context, CL_MEM_READ_WRITE, 4*4*sizeof(float), NULL, &ret);

    /* Copy input data to memory buffer */
    ret = clEnqueueWriteBuffer(command_queue, Amobj, CL_TRUE, 0, 4*4*sizeof(float), A, 0, NULL, NULL);
    ret = clEnqueueWriteBuffer(command_queue, Bmobj, CL_TRUE, 0, 4*4*sizeof(float), B, 0, NULL, NULL);

    /* Create kernel from source */
    program = clCreateProgramWithSource(context, 1, (const char **)&_kernel, NULL, &ret);
    ret     = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);

    /* Create task parallel OpenCL kernel */
    kernel[0] = clCreateKernel(program, "taskParallelAdd", &ret);
    kernel[1] = clCreateKernel(program, "taskParallelSub", &ret);
    kernel[2] = clCreateKernel(program, "taskParallelMul", &ret);
    kernel[3] = clCreateKernel(program, "taskParallelDiv", &ret);

    /* Set OpenCL kernel arguments */
    for (i=0; i<4; i++) {
        ret = clSetKernelArg(kernel[i], 0, sizeof(cl_mem), (void *)&Amobj);
        ret = clSetKernelArg(kernel[i], 1, sizeof(cl_mem), (void *)&Bmobj);
        ret = clSetKernelArg(kernel[i], 2, sizeof(cl_mem), (void *)&Cmobj);
    }

    /* Execute OpenCL kernel as task parallel */
    for (i=0; i<4; i++) {
        ret = clEnqueueTask(command_queue, kernel[i], 0, NULL, NULL);
    }

    /* Copy result to host */
    ret = clEnqueueReadBuffer(command_queue, Cmobj, CL_TRUE, 0, 4*4*sizeof(float), C, 0, NULL, NULL);

    /* Display result */
    for (i=0; i<4; i++) {
        for (j=0; j<4; j++) {
            printf("%7.2f ", C[i*4+j]);
        }
        printf("\n");
    }

    /* Finalization */
    ret = clFlush(command_queue);
    ret = clFinish(command_queue);
    ret = clReleaseKernel(kernel[0]);
    ret = clReleaseKernel(kernel[1]);
    ret = clReleaseKernel(kernel[2]);
    ret = clReleaseKernel(kernel[3]);
    ret = clReleaseProgram(program);
    ret = clReleaseMemObject(Amobj);
    ret = clReleaseMemObject(Bmobj);
    ret = clReleaseMemObject(Cmobj);
    ret = clReleaseCommandQueue(command_queue);
    ret = clReleaseContext(context);

    free(A);
    free(B);
    free(C);

    return 0;
}
4

1 に答える 1

1

command_queueは、clCreateCommandQueue戻り値-35: CL_INVALID_QUEUE_PROPERTIESのように作成されていないため、基本的にそれ以上は機能しません(カーネルは実行されません)。Cマトリックスメモリがマップされるランダムメモリ値を出力するだけです(初期化されていないため)。すべてのAPI呼び出しの戻り値にエラーがないかどうかを確認する必要があります。これにより、すぐにこれが強調されます。

エラーは、CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLEフラグの使用に関連しています。これは明らかにサポートされておらず、いずれにせよ、実際にはあなたが望むことをしません。このフラグは、特定のキューに対して、カーネルがエンキューされたのと同じ順序で実行される必要がないことをOpenCLランタイムに通知します。ただし、操作の性質は、データの並列処理を伴う順次カーネル実行です。これは、カーネルを同時に実行することとは異なります。これは、タスクの並列実行で必要なことです。

必要なのは、カーネルごとに1つずつ、合計4つのコマンドキューを作成することです。次に、すべてのキューが終了するまでイベントを待つことができます。ただし、同じ出力マトリックスを共有している場合は、誤って競合状態を引き起こさないように注意する必要があります。

タスク並列モデルについては、OpenCL1.2リファレンスマニュアルのセクション3.4.2で説明されています。このように複数のキューを実行する場合は、イベントを使用して、各キューの実行ステータスと完了ステータスを追跡することをお勧めします。詳細については、リファレンスのセクション5.9を参照してください。

これがテストコードで、複数のキューで更新され、タスクを並行して実行しています。結果が正しいことを簡単に確認しました。

#include <stdio.h>
#include <stdlib.h>

#include <OpenCL/opencl.h>

#define MAX_SOURCE_SIZE (0x100000)

const char *_kernel = "\n" \
"__kernel void taskParallelAdd(__global float* A, __global float* B, __global float* C) \n" \
"{ \n" \
"    int base = 0; \n" \
"     \n" \
"    C[base+0]  = A[base+0]  + B[base+0]; \n" \
"    C[base+4]  = A[base+4]  + B[base+4]; \n" \
"    C[base+8]  = A[base+8]  + B[base+8]; \n" \
"    C[base+12] = A[base+12] + B[base+12]; \n" \
"} \n" \
" \n" \
"__kernel void taskParallelSub(__global float* A, __global float* B, __global float* C) \n" \
"{ \n" \
"    int base = 1; \n" \
"     \n" \
"    C[base+0]  = A[base+0]  - B[base+0]; \n" \
"    C[base+4]  = A[base+4]  - B[base+4]; \n" \
"    C[base+8]  = A[base+8]  - B[base+8]; \n" \
"    C[base+12] = A[base+12] - B[base+12]; \n" \
"} \n" \
" \n" \
"__kernel void taskParallelMul(__global float* A, __global float* B, __global float* C) \n" \
"{ \n" \
"    int base = 2; \n" \
"     \n" \
"    C[base+0]  = A[base+0]  * B[base+0]; \n" \
"    C[base+4]  = A[base+4]  * B[base+4]; \n" \
"    C[base+8]  = A[base+8]  * B[base+8]; \n" \
"    C[base+12] = A[base+12] * B[base+12]; \n" \
"} \n" \
" \n" \
"__kernel void taskParallelDiv(__global float* A, __global float* B, __global float* C) \n" \
"{ \n" \
"    int base = 3; \n" \
"     \n" \
"    C[base+0]  = A[base+0]  / B[base+0]; \n" \
"    C[base+4]  = A[base+4]  / B[base+4]; \n" \
"    C[base+8]  = A[base+8]  / B[base+8]; \n" \
"    C[base+12] = A[base+12] / B[base+12]; \n" \
"} \n" \
" \n";

int main()
{
    cl_platform_id platform_id = NULL;
    cl_device_id device_id = NULL;
    cl_context context = NULL;
    cl_command_queue command_queue[4] = {NULL, NULL, NULL, NULL};
    cl_mem Amobj = NULL;
    cl_mem Bmobj = NULL;
    cl_mem Cmobj = NULL;
    cl_program program = NULL;
    cl_kernel kernel[4] = {NULL, NULL, NULL, NULL};
    cl_uint ret_num_devices;
    cl_uint ret_num_platforms;
    cl_int ret;

    int i, j;
    float* A;
    float* B;
    float* C;

    A = (float*)malloc(4*4*sizeof(float));
    B = (float*)malloc(4*4*sizeof(float));
    C = (float*)malloc(4*4*sizeof(float));

    /* Initialize input data */
    for (i=0; i<4; i++) {
        for (j=0; j<4; j++) {
            A[i*4+j] = i*4+j+1;
            printf("A[%u] = %u\n", i*4+j, i*4+j+1);
            B[i*4+j] = j*4+i+1;
            printf("B[%u] = %u\n", i*4+j, j*4+i+1);
        }
    }

    /* Get platform/device information */
    ret = clGetPlatformIDs(1, &platform_id, &ret_num_platforms);
    ret = clGetDeviceIDs( platform_id, CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &ret_num_devices);

    /* Create OpenCL Context */
    context = clCreateContext( NULL, 1, &device_id, NULL, NULL, &ret);

    /* Create buffer object */
    Amobj = clCreateBuffer(context, CL_MEM_READ_WRITE, 4*4*sizeof(float), NULL, &ret);
    Bmobj = clCreateBuffer(context, CL_MEM_READ_WRITE, 4*4*sizeof(float), NULL, &ret);
    Cmobj = clCreateBuffer(context, CL_MEM_READ_WRITE, 4*4*sizeof(float), NULL, &ret);

    /* Set up each queue */
    for (i = 0; i < 4; i++)
    {
        command_queue[i] = clCreateCommandQueue(context, device_id, 0, &ret);

        /* Copy input data to memory buffer */
        ret = clEnqueueWriteBuffer(command_queue[i], Amobj, CL_TRUE, 0, 4*4*sizeof(float), A, 0, NULL, NULL);
        ret = clEnqueueWriteBuffer(command_queue[i], Bmobj, CL_TRUE, 0, 4*4*sizeof(float), B, 0, NULL, NULL);
    }

    /* Create kernel from source */
    program = clCreateProgramWithSource(context, 1, (const char **)&_kernel, NULL, &ret);
    ret     = clBuildProgram(program, 1, &device_id, NULL, NULL, NULL);

    /* Create task parallel OpenCL kernel */
    kernel[0] = clCreateKernel(program, "taskParallelAdd", &ret);
    kernel[1] = clCreateKernel(program, "taskParallelSub", &ret);
    kernel[2] = clCreateKernel(program, "taskParallelMul", &ret);
    kernel[3] = clCreateKernel(program, "taskParallelDiv", &ret);

    /* Set OpenCL kernel arguments */
    for (i=0; i<4; i++) {
        ret = clSetKernelArg(kernel[i], 0, sizeof(cl_mem), (void *)&Amobj);
        ret = clSetKernelArg(kernel[i], 1, sizeof(cl_mem), (void *)&Bmobj);
        ret = clSetKernelArg(kernel[i], 2, sizeof(cl_mem), (void *)&Cmobj);
    }

    /* Execute OpenCL kernel as task parallel */
    for (i=0; i<4; i++) {
        ret = clEnqueueTask(command_queue[i], kernel[i], 0, NULL, NULL);
    }

    /* Wait for each queue to finish */
    for (i=0; i<4; i++) {
        printf("Waiting for %u to finish...\n", i);
        ret = clFinish(command_queue[i]);
    }

    ret = clEnqueueReadBuffer(command_queue[0], Cmobj, CL_TRUE, 0, 4*4*sizeof(float), C, 0, NULL, NULL);

    /* Display result */
    for (i=0; i<4; i++) {
        for (j=0; j<4; j++) {
            printf("%7.2f ", C[i*4+j]);
        }
        printf("\n");
    }

    /* Finalization */
    ret = clReleaseKernel(kernel[0]);
    ret = clReleaseKernel(kernel[1]);
    ret = clReleaseKernel(kernel[2]);
    ret = clReleaseKernel(kernel[3]);
    ret = clReleaseProgram(program);
    ret = clReleaseMemObject(Amobj);
    ret = clReleaseMemObject(Bmobj);
    ret = clReleaseMemObject(Cmobj);
    ret = clReleaseCommandQueue(command_queue[0]);
    ret = clReleaseCommandQueue(command_queue[1]);
    ret = clReleaseCommandQueue(command_queue[2]);
    ret = clReleaseCommandQueue(command_queue[3]);
    ret = clReleaseContext(context);

    free(A);
    free(B);
    free(C);

    return 0;
}
于 2012-04-20T05:09:44.320 に答える