收集的两个测试 amd gpu 平台上opencl的几个示例 hello example and hello kernel sample

hello_opencl_world.cpp

#include <iostream>
#include <unistd.h>
#include <string>
#include <CL/opencl.h>

std::string getPlatformName(const cl_platform_id pid){
        cl_int err_no=CL_SUCCESS;
    size_t param_value_size;

    err_no = clGetPlatformInfo(pid, CL_PLATFORM_NAME, 0, NULL, &param_value_size);
    //sleep(1);
    if(err_no != CL_SUCCESS)
    {
            std::cout<<"Error get CL_PLATFORM_NAME"<<std::endl;
            exit(1);
    }
    std::cout<<"param_value_size = "<< param_value_size<<std::endl;
    char *param_value = (char*)malloc(param_value_size*sizeof(char));///new char[param_value_size];
    clGetPlatformInfo(pid, CL_PLATFORM_NAME, param_value_size, param_value, NULL);
    return param_value;
}

int main(int argc, char **argv) {
    std::cout << "Hello, world!" << std::endl;

    cl_uint num_platforms;
    clGetPlatformIDs(0, NULL, &num_platforms);
    cl_platform_id *platforms = new cl_platform_id[num_platforms];
    clGetPlatformIDs(num_platforms, platforms, NULL);
    for (cl_uint i = 0; i < num_platforms; i++){
        std::string platname = getPlatformName(platforms[i]);
        std::cout << "<" << i << "> " << "Platform name is :" << platname << std::endl;
    }

    cl_platform_id platform_id = NULL;
    cl_device_id device_id = NULL;
    cl_uint num_platform = 0;
    cl_uint num_device = 0;
    clGetPlatformIDs(1, &platform_id, &num_platform);
    std::cout << "stab num_platform=" << num_platform <<std::endl;
    int index = 0;
    while(true) {
      platform_id = platforms[index];
      if(clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_GPU, 1, &device_id, &num_device) != CL_SUCCESS) {
        index++;
        if(index >= num_platforms) break;
      } else {
        break;
      }
    }
    if(index >= num_platforms) {
      std::cout << "not found GPU" << std::endl;
    } else {
      std::cout << "found GPU index=" << index << std::endl;
    }
    clGetDeviceIDs(platforms[0], CL_DEVICE_TYPE_GPU, 1, &device_id, &num_device);
    std::cout << "stab num_device=" << num_device <<std::endl;
    std::string platnamenow = getPlatformName(platforms[0]);
    std::cout << "Platform device name is :" << platnamenow << std::endl;

    size_t      valueSize;
    clGetDeviceInfo(device_id, CL_DEVICE_NAME, 0, NULL, &valueSize);
//    valueSize*=2;
    std::cout<<"valueSize = "<< valueSize<<std::endl;
    char* value = (char*) malloc(valueSize);
    clGetDeviceInfo(device_id, CL_DEVICE_NAME, valueSize, value, NULL);
    std::cout << "device name is :" << std::string(value) << std::endl;
    free(value);

    cl_device_type cur_type;
    clGetDeviceInfo(device_id, CL_DEVICE_TYPE, sizeof(cur_type), &cur_type, NULL);
    std::cout << "device type is :" << cur_type << std::endl;

    std::cout << "CL_DEVICE_TYPE_DEFAULT is :" << CL_DEVICE_TYPE_DEFAULT << std::endl;
    std::cout << "CL_DEVICE_TYPE_CPU is :" << CL_DEVICE_TYPE_CPU << std::endl;
    std::cout << "CL_DEVICE_TYPE_GPU is :" << CL_DEVICE_TYPE_GPU << std::endl;
    std::cout << "CL_DEVICE_TYPE_ACCELERATOR is :" << CL_DEVICE_TYPE_ACCELERATOR << std::endl;
    std::cout << "CL_DEVICE_TYPE_CUSTOM is :" << CL_DEVICE_TYPE_CUSTOM << std::endl;
    std::cout << "CL_DEVICE_TYPE_ALL is :" << CL_DEVICE_TYPE_ALL << std::endl;

    delete[] platforms;

    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.17)

add_executable(hello_opencl_world hello_opencl_world.cpp)

set(CMAKE_BUILD_TYPE Debug)

target_link_libraries(hello_opencl_world  /opt/rocm/opencl/lib/libOpenCL.so)
target_include_directories(hello_opencl_world   PRIVATE  /opt/rocm/include)

运行:

第二个示例,借用于此:

rocman@Radeonnvii-host:~/ex/opencl_ex/OpenCL-examples$ git remote -v
origin  https://github.com/rsnemmen/OpenCL-examples.git (fetch)
origin  https://github.com/rsnemmen/OpenCL-examples.git (push)
rocman@Radeonnvii-host:~/ex/opencl_ex/OpenCL-examples$

add_number.c

#define PROGRAM_FILE "add_numbers.cl"
#define KERNEL_FUNC "add_numbers"
#define ARRAY_SIZE 64

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

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

/* Find a GPU or CPU associated with the first available platform

The `platform` structure identifies the first platform identified by the
OpenCL runtime. A platform identifies a vendor's installation, so a system
may have an NVIDIA platform and an AMD platform.

The `device` structure corresponds to the first accessible device
associated with the platform. Because the second parameter is
`CL_DEVICE_TYPE_GPU`, this device must be a GPU.
*/
cl_device_id create_device() {

   cl_platform_id platform;
   cl_device_id dev;
   int err;

   /* Identify a platform */
   err = clGetPlatformIDs(1, &platform, NULL);
   if(err < 0) {
      perror("Couldn't identify a platform");
      exit(1);
   }

   // Access a device
   // GPU
   err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &dev, NULL);
   if(err == CL_DEVICE_NOT_FOUND) {
      // CPU
      err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_CPU, 1, &dev, NULL);
   }
   if(err < 0) {
      perror("Couldn't access any devices");
      exit(1);
   }

   return dev;
}





/* Create program from a file and compile it */
cl_program build_program(cl_context ctx, cl_device_id dev, const char* filename) {

   cl_program program;
   FILE *program_handle;
   char *program_buffer, *program_log;
   size_t program_size, log_size;
   int err;

   /* Read program file and place content into buffer */
   program_handle = fopen(filename, "r");
   if(program_handle == NULL) {
      perror("Couldn't find the program file");
      exit(1);
   }
   fseek(program_handle, 0, SEEK_END);
   program_size = ftell(program_handle);
   rewind(program_handle);
   program_buffer = (char*)malloc(program_size + 1);
   program_buffer[program_size] = '\0';
   fread(program_buffer, sizeof(char), program_size, program_handle);
   fclose(program_handle);

   /* Create program from file

   Creates a program from the source code in the add_numbers.cl file.
   Specifically, the code reads the file's content into a char array
   called program_buffer, and then calls clCreateProgramWithSource.
   */
   program = clCreateProgramWithSource(ctx, 1,
      (const char**)&program_buffer, &program_size, &err);
   if(err < 0) {
      perror("Couldn't create the program");
      exit(1);
   }
   free(program_buffer);

   /* Build program

   The fourth parameter accepts options that configure the compilation.
   These are similar to the flags used by gcc. For example, you can
   define a macro with the option -DMACRO=VALUE and turn off optimization
   with -cl-opt-disable.
   */
   err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
   if(err < 0) {

      /* Find size of log and print to std output */
      clGetProgramBuildInfo(program, dev, CL_PROGRAM_BUILD_LOG,
            0, NULL, &log_size);
      program_log = (char*) malloc(log_size + 1);
      program_log[log_size] = '\0';
      clGetProgramBuildInfo(program, dev, CL_PROGRAM_BUILD_LOG,
            log_size + 1, program_log, NULL);
      printf("%s\n", program_log);
      free(program_log);
      exit(1);
   }

   return program;
}





int main() {

   /* OpenCL structures */
   cl_device_id device;
   cl_context context;
   cl_program program;
   cl_kernel kernel;
   cl_command_queue queue;
   cl_int i, j, err;
   size_t local_size, global_size;

   /* Data and buffers    */
   float data[ARRAY_SIZE];
   float sum[2], total, actual_sum;
   cl_mem input_buffer, sum_buffer;
   cl_int num_groups;

   /* Initialize data */
   for(i=0; i<ARRAY_SIZE; i++) {
      data[i] = 1.0f*i;
   }

   /* Create device and context

   Creates a context containing only one device — the device structure
   created earlier.
   */
   device = create_device();
   context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);
   if(err < 0) {
      perror("Couldn't create a context");
      exit(1);
   }

   /* Build program */
   program = build_program(context, device, PROGRAM_FILE);

   /* Create data buffer

   • `global_size`: total number of work items that will be
      executed on the GPU (e.g. total size of your array)
   • `local_size`: size of local workgroup. Each workgroup contains
      several work items and goes to a compute unit

   In this example, the kernel is executed by eight work-items divided into
   two work-groups of four work-items each. Returning to my analogy,
   this corresponds to a school containing eight students divided into
   two classrooms of four students each.

     Notes:
   • Intel recommends workgroup size of 64-128. Often 128 is minimum to
   get good performance on GPU
   • On NVIDIA Fermi, workgroup size must be at least 192 for full
   utilization of cores
   • Optimal workgroup size differs across applications
   */
   global_size = 8; // WHY ONLY 8?
   local_size = 4;
   num_groups = global_size/local_size;
   input_buffer = clCreateBuffer(context, CL_MEM_READ_ONLY |
         CL_MEM_COPY_HOST_PTR, ARRAY_SIZE * sizeof(float), data, &err); // <=====INPUT
   sum_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE |
         CL_MEM_COPY_HOST_PTR, num_groups * sizeof(float), sum, &err); // <=====OUTPUT
   if(err < 0) {
      perror("Couldn't create a buffer");
      exit(1);
   };

   /* Create a command queue

   Does not support profiling or out-of-order-execution
   */
   queue = clCreateCommandQueue(context, device, 0, &err);
   if(err < 0) {
      perror("Couldn't create a command queue");
      exit(1);
   };

   /* Create a kernel */
   kernel = clCreateKernel(program, KERNEL_FUNC, &err);
   if(err < 0) {
      perror("Couldn't create a kernel");
      exit(1);
   };

   /* Create kernel arguments */
   err = clSetKernelArg(kernel, 0, sizeof(cl_mem), &input_buffer); // <=====INPUT
   err |= clSetKernelArg(kernel, 1, local_size * sizeof(float), NULL);
   err |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &sum_buffer); // <=====OUTPUT
   if(err < 0) {
      perror("Couldn't create a kernel argument");
      exit(1);
   }

   /* Enqueue kernel

   At this point, the application has created all the data structures
   (device, kernel, program, command queue, and context) needed by an
   OpenCL host application. Now, it deploys the kernel to a device.

   Of the OpenCL functions that run on the host, clEnqueueNDRangeKernel
   is probably the most important to understand. Not only does it deploy
   kernels to devices, it also identifies how many work-items should
   be generated to execute the kernel (global_size) and the number of
   work-items in each work-group (local_size).
   */
   err = clEnqueueNDRangeKernel(queue, kernel, 1, NULL, &global_size,
         &local_size, 0, NULL, NULL);
   if(err < 0) {
      perror("Couldn't enqueue the kernel");
      exit(1);
   }

   /* Read the kernel's output    */
   err = clEnqueueReadBuffer(queue, sum_buffer, CL_TRUE, 0,
         sizeof(sum), sum, 0, NULL, NULL); // <=====GET OUTPUT
   if(err < 0) {
      perror("Couldn't read the buffer");
      exit(1);
   }

   /* Check result */
   total = 0.0f;
   for(j=0; j<num_groups; j++) {
      total += sum[j];
   }
   actual_sum = 1.0f * ARRAY_SIZE/2*(ARRAY_SIZE-1);
   printf("Computed sum = %.1f.\n", total);
   if(fabs(total - actual_sum) > 0.01*fabs(actual_sum))
      printf("Check failed.\n");
   else
      printf("Check passed.\n");

   /* Deallocate resources */
   clReleaseKernel(kernel);
   clReleaseMemObject(sum_buffer);
   clReleaseMemObject(input_buffer);
   clReleaseCommandQueue(queue);
   clReleaseProgram(program);
   clReleaseContext(context);
   return 0;
}

kernel 代码

add_number.cl

/*
Code that contains kernels to run on accelerator in parallel. A kernel
represents the basic unit of executable code. Each kernel will be
executed on one work item ("pixel") of your parallel task:

1 work item = 1 "pixel" in your image

A practical application may generate thousands or even millions of
work-items, but for the simple task of adding 64 numbers,
eight work-items will suffice. The program file add_numbers.cl
contains a function called add_numbers that performs this operation.
Like all kernel functions, it returns void and its name is preceded by
the __kernel identifier.

The kernel has 64 values to add together and eight work-items with
which to add them. After each work-item computes its sum of eight
values, these partial results will be added together to form a sum for
the entire group. In the end, the kernel will return two sums — one for
each work-group executing the kernel.

data <===== input_buffer
group_result <===== sum_buffer
*/

__kernel void add_numbers(__global float4* data,
      __local float* local_result, __global float* group_result) {

   float sum;
   float4 input1, input2, sum_vector; // array of 4 floats which support vectorization
   uint global_addr, local_addr;

   global_addr = get_global_id(0) * 2;
   input1 = data[global_addr];
   input2 = data[global_addr+1];
   sum_vector = input1 + input2; // perform four floating-point additions simultaneously

   local_addr = get_local_id(0);
   local_result[local_addr] = sum_vector.s0 + sum_vector.s1 +
                              sum_vector.s2 + sum_vector.s3;
   barrier(CLK_LOCAL_MEM_FENCE);

   if(get_local_id(0) == 0) {
      sum = 0.0f;
      for(int i=0; i<get_local_size(0); i++) {
         sum += local_result[i];
      }
      group_result[get_group_id(0)] = sum;
   }
}

Makefile

PROJ=add_numbers

CC=gcc

CFLAGS=-std=c99 -Wall -DUNIX -g -DDEBUG
# No OpenCL
CFLAGSS=-std=c99 -Wall -DUNIX -g -DDEBUG

# Check for 32-bit vs 64-bit
PROC_TYPE = $(strip $(shell uname -m | grep 64))

# Check for Mac OS
OS = $(shell uname -s 2>/dev/null | tr [:lower:] [:upper:])
DARWIN = $(strip $(findstring DARWIN, $(OS)))

# MacOS System
ifneq ($(DARWIN),)
        CFLAGS += -DMAC
        LIBS=-framework OpenCL

        ifeq ($(PROC_TYPE),)
                CFLAGS+=-arch i386
        else
                CFLAGS+=-arch x86_64
        endif
else

# Linux OS
LIBS=-lOpenCL
ifeq ($(PROC_TYPE),)
        CFLAGS+=-m32
else
        CFLAGS+=-m64
endif

# Check for Linux-AMD
ifdef AMDAPPSDKROOT
   INC_DIRS=. $(AMDAPPSDKROOT)/include
        ifeq ($(PROC_TYPE),)
                LIB_DIRS=$(AMDAPPSDKROOT)/lib/x86
        else
                LIB_DIRS=$(AMDAPPSDKROOT)/lib/x86_64
        endif
else

# Check for Linux-Nvidia
ifdef CUDA
   INC_DIRS=. $(CUDA)/OpenCL/common/inc
endif
INC_DIRS=/opt/rocm-5.4.3/opencl/include
LIB_DIRS=/opt/rocm-5.4.3/opencl/lib
endif
endif

$(PROJ): $(PROJ).c
        $(CC) $(CFLAGS) -o $@ $^ $(INC_DIRS:%=-I%) $(LIB_DIRS:%=-L%) $(LIBS)

.PHONY: clean

clean:
        rm $(PROJ)

运行:

第三个借用的示例:

hello_ocl.cpp

#include <iostream>
#include <fstream>
#include <sstream>
#include <CL/cl.h>

const int ARRAY_SIZE = 1000;

//一、 选择OpenCL平台并创建一个上下文
cl_context CreateContext()
{
        cl_int errNum;
        cl_uint numPlatforms;
        cl_platform_id firstPlatformId;
        cl_context context = NULL;

        //选择可用的平台中的第一个
        errNum = clGetPlatformIDs(1, &firstPlatformId, &numPlatforms);
        if (errNum != CL_SUCCESS || numPlatforms <= 0)
        {
                std::cerr << "Failed to find any OpenCL platforms." << std::endl;
                return NULL;
        }

        //创建一个OpenCL上下文环境
        cl_context_properties contextProperties[] =
        {
                CL_CONTEXT_PLATFORM,
                (cl_context_properties)firstPlatformId,
                0
        };
        context = clCreateContextFromType(contextProperties, CL_DEVICE_TYPE_GPU,
                NULL, NULL, &errNum);

        return context;
}


//二、 创建设备并创建命令队列
cl_command_queue CreateCommandQueue(cl_context context, cl_device_id *device)
{
        cl_int errNum;
        cl_device_id *devices;
        cl_command_queue commandQueue = NULL;
        size_t deviceBufferSize = -1;

        // 获取设备缓冲区大小
        errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &deviceBufferSize);

        if (deviceBufferSize <= 0)
        {
                std::cerr << "No devices available.";
                return NULL;
        }

        // 为设备分配缓存空间
        devices = new cl_device_id[deviceBufferSize / sizeof(cl_device_id)];
        errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceBufferSize, devices, NULL);

        //选取可用设备中的第一个
        commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);

        *device = devices[0];
        delete[] devices;
        return commandQueue;
}


// 三、创建和构建程序对象
cl_program CreateProgram(cl_context context, cl_device_id device, const char* fileName)
{
        cl_int errNum;
        cl_program program;

        std::ifstream kernelFile(fileName, std::ios::in);
        if (!kernelFile.is_open())
        {
                std::cerr << "Failed to open file for reading: " << fileName << std::endl;
                return NULL;
        }

        std::ostringstream oss;
        oss << kernelFile.rdbuf();

        std::string srcStdStr = oss.str();
        const char *srcStr = srcStdStr.c_str();
        program = clCreateProgramWithSource(context, 1,
                (const char**)&srcStr,
                NULL, NULL);

        errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);

        return program;
}

//创建和构建程序对象
bool CreateMemObjects(cl_context context, cl_mem memObjects[3],
        float *a, float *b)
{
        memObjects[0] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                sizeof(float) * ARRAY_SIZE, a, NULL);
        memObjects[1] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                sizeof(float) * ARRAY_SIZE, b, NULL);
        memObjects[2] = clCreateBuffer(context, CL_MEM_READ_WRITE,
                sizeof(float) * ARRAY_SIZE, NULL, NULL);
        return true;
}


// 释放OpenCL资源
void Cleanup(cl_context context, cl_command_queue commandQueue,
        cl_program program, cl_kernel kernel, cl_mem memObjects[3])
{
        for (int i = 0; i < 3; i++)
        {
                if (memObjects[i] != 0)
                        clReleaseMemObject(memObjects[i]);
        }
        if (commandQueue != 0)
                clReleaseCommandQueue(commandQueue);

        if (kernel != 0)
                clReleaseKernel(kernel);

        if (program != 0)
                clReleaseProgram(program);

        if (context != 0)
                clReleaseContext(context);
}

int main(int argc, char** argv)
{
        cl_context context = 0;
        cl_command_queue commandQueue = 0;
        cl_program program = 0;
        cl_device_id device = 0;
        cl_kernel kernel = 0;
        cl_mem memObjects[3] = { 0, 0, 0 };
        cl_int errNum;

        // 一、选择OpenCL平台并创建一个上下文
        context = CreateContext();

        // 二、 创建设备并创建命令队列
        commandQueue = CreateCommandQueue(context, &device);

        //创建和构建程序对象
        program = CreateProgram(context, device, "HelloWorld.cl");

        // 四、 创建OpenCL内核并分配内存空间
        kernel = clCreateKernel(program, "hello_kernel", NULL);

        //创建要处理的数据
        float result[ARRAY_SIZE];
        float a[ARRAY_SIZE];
        float b[ARRAY_SIZE];
        for (int i = 0; i < ARRAY_SIZE; i++)
        {
                a[i] = (float)i;
                b[i] = (float)(ARRAY_SIZE - i);
        }

        //创建内存对象
        if (!CreateMemObjects(context, memObjects, a, b))
        {
                Cleanup(context, commandQueue, program, kernel, memObjects);
                return 1;
        }

        // 五、 设置内核数据并执行内核
        errNum = clSetKernelArg(kernel, 0, sizeof(cl_mem), &memObjects[0]);
        errNum |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &memObjects[1]);
        errNum |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &memObjects[2]);

        size_t globalWorkSize[1] = { ARRAY_SIZE };
        size_t localWorkSize[1] = { 1 };

        errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL,
                globalWorkSize, localWorkSize,
                0, NULL, NULL);

        // 六、 读取执行结果并释放OpenCL资源
        errNum = clEnqueueReadBuffer(commandQueue, memObjects[2], CL_TRUE,
                0, ARRAY_SIZE * sizeof(float), result,
                0, NULL, NULL);

        for (int i = 0; i < ARRAY_SIZE; i++)
        {
                std::cout << result[i] << " ";
        }
        std::cout << std::endl;
        std::cout << "Executed program succesfully." << std::endl;
        getchar();
        Cleanup(context, commandQueue, program, kernel, memObjects);

        return 0;
}

HelloWorld.cl

__kernel void hello_kernel(__global const float *a,
        __global const float *b,
        __global float *result)
{
        int gid = get_global_id(0);

//      result[gid] = a[gid] + b[gid];
//for(int i=0; i<10; i++)              result[gid] += a[gid] *0.1+ b[gid] *0.1;
         result[gid] = a[gid]*0.1 + b[gid]*0.1;
         result[gid] = a[gid]*0.22 + b[gid]*0.22;
}

编译:

$ g++ hello_ocl.cpp  -I /opt/rocm-5.4.3/opencl/include -L /opt/rocm-5.4.3/opencl/lib -lOpenCL -g

kernel是jit编译的,所以,可以只g++一次,然后不断地修改kernel代码,而不断地直接运行

运行:

示例4:测风扇性能,文件名同示例3,仅仅改了数据量,和 kernel 中加入 for 循环

#include <iostream>
#include <fstream>
#include <sstream>
#include <CL/cl.h>

const int ARRAY_SIZE =100000;// 483647;//100000;

//一、 选择OpenCL平台并创建一个上下文
cl_context CreateContext()
{
        cl_int errNum;
        cl_uint numPlatforms;
        cl_platform_id firstPlatformId;
        cl_context context = NULL;

        //选择可用的平台中的第一个
        errNum = clGetPlatformIDs(1, &firstPlatformId, &numPlatforms);
        if (errNum != CL_SUCCESS || numPlatforms <= 0)
        {
                std::cerr << "Failed to find any OpenCL platforms." << std::endl;
                return NULL;
        }

        //创建一个OpenCL上下文环境
        cl_context_properties contextProperties[] =
        {
                CL_CONTEXT_PLATFORM,
                (cl_context_properties)firstPlatformId,
                0
        };
        context = clCreateContextFromType(contextProperties, CL_DEVICE_TYPE_GPU,
                NULL, NULL, &errNum);

        return context;
}


//二、 创建设备并创建命令队列
cl_command_queue CreateCommandQueue(cl_context context, cl_device_id *device)
{
        cl_int errNum;
        cl_device_id *devices;
        cl_command_queue commandQueue = NULL;
        size_t deviceBufferSize = -1;

        // 获取设备缓冲区大小
        errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &deviceBufferSize);

        if (deviceBufferSize <= 0)
        {
                std::cerr << "No devices available.";
                return NULL;
        }

        // 为设备分配缓存空间
        devices = new cl_device_id[deviceBufferSize / sizeof(cl_device_id)];
        errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceBufferSize, devices, NULL);

        //选取可用设备中的第一个
        commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);

        *device = devices[0];
        delete[] devices;
        return commandQueue;
}


// 三、创建和构建程序对象
cl_program CreateProgram(cl_context context, cl_device_id device, const char* fileName)
{
        cl_int errNum;
        cl_program program;

        std::ifstream kernelFile(fileName, std::ios::in);
        if (!kernelFile.is_open())
        {
                std::cerr << "Failed to open file for reading: " << fileName << std::endl;
                return NULL;
        }

        std::ostringstream oss;
        oss << kernelFile.rdbuf();

        std::string srcStdStr = oss.str();
        const char *srcStr = srcStdStr.c_str();
        program = clCreateProgramWithSource(context, 1,
                (const char**)&srcStr,
                NULL, NULL);

        errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);

        return program;
}

//创建和构建程序对象
bool CreateMemObjects(cl_context context, cl_mem memObjects[3],
        float *a, float *b)
{
        memObjects[0] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                sizeof(float) * ARRAY_SIZE, a, NULL);
        memObjects[1] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                sizeof(float) * ARRAY_SIZE, b, NULL);
        memObjects[2] = clCreateBuffer(context, CL_MEM_READ_WRITE,
                sizeof(float) * ARRAY_SIZE, NULL, NULL);
        return true;
}


// 释放OpenCL资源
void Cleanup(cl_context context, cl_command_queue commandQueue,
        cl_program program, cl_kernel kernel, cl_mem memObjects[3])
{
        for (int i = 0; i < 3; i++)
        {
                if (memObjects[i] != 0)
                        clReleaseMemObject(memObjects[i]);
        }
        if (commandQueue != 0)
                clReleaseCommandQueue(commandQueue);

        if (kernel != 0)
                clReleaseKernel(kernel);

        if (program != 0)
                clReleaseProgram(program);

        if (context != 0)
                clReleaseContext(context);
}

int main(int argc, char** argv)
{
        cl_context context = 0;
        cl_command_queue commandQueue = 0;
        cl_program program = 0;
        cl_device_id device = 0;
        cl_kernel kernel = 0;
        cl_mem memObjects[3] = { 0, 0, 0 };
        cl_int errNum;

        // 一、选择OpenCL平台并创建一个上下文
        context = CreateContext();

        // 二、 创建设备并创建命令队列
        commandQueue = CreateCommandQueue(context, &device);

        //创建和构建程序对象
        program = CreateProgram(context, device, "HelloWorld.cl");

        // 四、 创建OpenCL内核并分配内存空间
        kernel = clCreateKernel(program, "hello_kernel", NULL);

        //创建要处理的数据
        float result[ARRAY_SIZE];
        float a[ARRAY_SIZE];
        float b[ARRAY_SIZE];
        for (int i = 0; i < ARRAY_SIZE; i++)
        {
                a[i] = (float)i;
                b[i] = (float)(ARRAY_SIZE - i);
        }

        //创建内存对象
        if (!CreateMemObjects(context, memObjects, a, b))
        {
                Cleanup(context, commandQueue, program, kernel, memObjects);
                return 1;
        }

        // 五、 设置内核数据并执行内核
        errNum = clSetKernelArg(kernel, 0, sizeof(cl_mem), &memObjects[0]);
        errNum |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &memObjects[1]);
        errNum |= clSetKernelArg(kernel, 2, sizeof(cl_mem), &memObjects[2]);

        size_t globalWorkSize[1] = { ARRAY_SIZE };
        size_t localWorkSize[1] = { 1 };

        errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 1, NULL,
                globalWorkSize, localWorkSize,
                0, NULL, NULL);

        // 六、 读取执行结果并释放OpenCL资源
        errNum = clEnqueueReadBuffer(commandQueue, memObjects[2], CL_TRUE,
                0, ARRAY_SIZE * sizeof(float), result,
                0, NULL, NULL);

        for (int i = ARRAY_SIZE-7; i < ARRAY_SIZE; i++)
        {
                std::cout << result[i] << " ";
        }
        std::cout << std::endl;
        std::cout << "Executed program succesfully." << std::endl;
        getchar();
        Cleanup(context, commandQueue, program, kernel, memObjects);

        return 0;
}

__kernel void hello_kernel(__global const float *a,
        __global const float *b,
        __global float *result)
{
        int gid = get_global_id(0);
        result[gid] = 0.0f;
//      result[gid] = a[gid] + b[gid];
//for(int i=0; i<10; i++)              result[gid] += a[gid] *0.1+ b[gid] *0.1;
        for(int jj=0; jj<1000000; jj++){
                result[gid] += a[gid]*0.11 + b[gid]*0.11;
//              result[gid] += (a[gid]*0.22 + b[gid]*0.22);
        }
}

clrx_OpencL_GPU_汇编_amd

https://download.csdn.net/download/weixin_42667269/26666041

借名一用

CLRadeonExtender

https://github.com/CLRX/CLRX-mirror

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值