インテル® FPGA SDK for OpenCL™プロ・エディション: プログラミング・ガイド

ID 683846
日付 4/01/2019
Public
ドキュメント目次

5.5.5.1. 他のOpenCL SDKとの互換性の確保

インテルによるOpenCLパイプの実装は現在、OpenCL Specification version 2.0に部分的に準拠しています。 他のOpenCL SDKからのパイプを実装するカーネルを、 インテル® FPGA SDK for OpenCL™ にポートする場合は、ホストコードとカーネルコードを変更する必要があります。 この変更は、このアプリケーションの他のOpenCL SDKに対する移植性に影響しません。

ホストコードの変更

以下は、変更されたホスト・アプリケーションの例です。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "CL/opencl.h"
#define SIZE 1000

const char *kernel_source = "__kernel void pipe_writer(__global int *in,"
                            "                          write_only pipe int p_in)\n"
                            "{\n"
                            "    int gid = get_global_id(0);\n"
                            "    write_pipe(p_in, &in[gid]);\n"
                            "}\n"
                            "__kernel void pipe_reader(__global int *out,"
                            "                          read_only pipe int p_out)\n"
                            "{\n"
                            "    int gid = get_global_id(0);\n"
                            "    read_pipe(p_out, &out[gid]);\n"
                            "}\n";

int main()
{
    int *input = (int *)malloc(sizeof(int) * SIZE);
    int *output = (int *)malloc(sizeof(int) * SIZE);
    memset(output, 0, sizeof(int) * SIZE);
    for (int i = 0; i != SIZE; ++i)
    {
        input[i] = rand();
    }

    cl_int status;
    cl_platform_id platform;
    cl_uint num_platforms;
    status = clGetPlatformIDs(1, &platform, &num_platforms);

    cl_device_id device;
    cl_uint num_devices;
    status = clGetDeviceIDs(platform,
	                        CL_DEVICE_TYPE_ALL,
                            1,
                            &device,
                            &num_devices);

    cl_context context = clCreateContext(0, 1, &device, NULL, NULL, &status);

    cl_command_queue queue = clCreateCommandQueue(context, device, 0, &status);

    size_t len = strlen(kernel_source);  
    cl_program program = clCreateProgramWithSource(context,
	                                               1,
                                                   (const char **)&kernel_source,
                                                   &len,
                                                   &status);

    status = clBuildProgram(program, num_devices, &device, "", NULL, NULL);

    cl_kernel pipe_writer = clCreateKernel(program, "pipe_writer", &status);
    cl_kernel pipe_reader = clCreateKernel(program, "pipe_reader", &status);

    cl_mem in_buffer = clCreateBuffer(context,
                                      CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                                      sizeof(int) * SIZE,
                                      input,
                                      &status);
    cl_mem out_buffer = clCreateBuffer(context,
                                       CL_MEM_WRITE_ONLY,
                                       sizeof(int) * SIZE,
                                       NULL,
                                       &status);

    cl_mem pipe = clCreatePipe(context, 0, sizeof(cl_int), SIZE, NULL, &status);

    status = clSetKernelArg(pipe_writer, 0, sizeof(cl_mem), &in_buffer);
    status = clSetKernelArg(pipe_writer, 1, sizeof(cl_mem), &pipe);
    status = clSetKernelArg(pipe_reader, 0, sizeof(cl_mem), &out_buffer);
    status = clSetKernelArg(pipe_reader, 1, sizeof(cl_mem), &pipe);

    size_t size = SIZE; 
    cl_event sync;
    status = clEnqueueNDRangeKernel(queue,
                                    pipe_writer,
                                    1,
                                    NULL,
                                    &size,
                                    &size,
                                    0,
                                    NULL,
                                    &sync);
    status = clEnqueueNDRangeKernel(queue,
                                    pipe_reader,
                                    1,
                                    NULL,
                                    &size,
                                    &size,
                                    1,
                                    &sync,
                                    NULL);
    status = clFinish(queue);

    status = clEnqueueReadBuffer(queue,
                                 out_buffer,
                                 CL_TRUE,
                                 0,
                                 sizeof(int) * SIZE,
                                 output,
                                 0,
                                 NULL,
                                 NULL);

    int golden = 0, result = 0;
    for (int i = 0; i != SIZE; ++i)
    {
      golden += input[i];
      result += output[i];
    }

    int ret = 0;
    if (golden != result)
    {
        printf("FAILED!");
        ret = 1;
    } else
    {
        printf("PASSED!");
    }
    printf("\n");

    return ret;
}

カーネルコードの変更

カーネルコードが、OpenCL Specification version 2.0に準拠するOpenCL SDKで実行される場合、 インテル® FPGA SDK for OpenCL™ で実行する前にこのコードを変更する必要があります。次のようにカーネルコードを変更してください。

  • パイプ引数の名前が両方のカーネルにおいて同一になるように変更します。例えば、p_inp_outpに変更します。
  • パイプ引数にdepth属性を指定します。ホストで保持するためにパイプが作成する最大パケット数に等しい値を、depth属性に割り当てます。
  • インテル® FPGA SDK for OpenCL™ にはオフライン・コンパイラーがあるため、オフライン・コンパイル・モードでカーネルプログラムを実行します。

変更後のカーネルコードは次のようになります。

#define SIZE 1000

__kernel void pipe_writer(__global int *in,
                          write_only pipe int __attribute__((depth(SIZE))) p)
{
    int gid = get_global_id(0);
    write_pipe(p, &in[gid]);
}

__kernel void pipe_reader(__global int *out,
                          read_only pipe int __attribute__((depth(SIZE))) p)
{
    int gid = get_global_id(0);
    read_pipe(p, &out[gid]);
}