参考链接:https://registry.khronos.org/OpenCL/sdk/1.1/docs/man/xhtml/
参考文档:opencl-1.1.pdf

OpenCL介绍

  • Platform Model
  • Memory Model
  • Execution Model
  • Programming Model

平台模型

OpenCL平台模型由一个host和多个device组成,device 划分为多个计算单元(Compute Units, CUs),每个CU又可以划分为多个处理元素(Processing Element, PE),内核程序最终在PE上并行执行。

执行模型

Execution of an OpenCL program occurs in two parts: kernels that execute on one or more OpenCL devices and a host program` that executes on the host. The host program defines the context for the kernels and manages their execution.

  • 内核提交到 OpenCL 设备执行
  • OpenCL 维护整数索引空间
  • 索引空间为 N 维的网格 ( NDRange , N 可选为 1 , 2 , 3 )
  • 索引空间可以根据需要进行划分 ( work-group )
  • 工作组中的工作项可以使用局部id进行标识

对此索引空间中的每个点都执行一个内核的实例,这个内核实例称为工作项(work-item),组成的小方块称为工作组(work-group)。划分公式如下:

如图5-1所示,执行内核的global_size大小为16个work-item,work-group大小为每组8个work-item。

  • Work-group instances are executed in parallel across multiple compute units or concurrently on the same compute unit.
  • Each work-item is uniquely identified by a global identifier. The global ID, which can be read inside the kernel, is computed using the value given by global_work_size and global_work_offset. In addition, a work-item is also identified within a work-group by a unique local ID. The local ID, which can also be read by the kernel, is computed using the value given by local_work_size.
  • OpenCL没有描述全局ID和局部ID如何映射到工作项和工作组。如图5-1所示,group_id=0的工作组并没有指定0~get_local_size(0)-1的work-item。这个映射由OpenCL实现以及执行内核的设备来确定。

内存模型

OpenCL的内存模型:

  • Global Memory
  • Constant Memory
  • Local Memory
  • Private Memory

内存区域及其与平台模型之间的关系如下:

程序模型

  • 数据并行模型(data parallel)
  • 任务并行编程模型(task parallel)
  • 同时也支持这两个模型的混合模型
驱动OpenCL设计的主要模型是数据并行的。

OpenCL执行流程

OpenCL 编程基础

搜索并选择OpenCL平台

cl_int clGetPlatformIDs(cl_uint num_entries, cl_platform_id *platforms, cl_uint *num_platforms)
  • num_entries: 表示 OpenCL 平台的索引值。设置为0 , 以及platforms为NULL表示查询可用的平台数
  • platforms: 表示平台的指针
  • num_platforms: 表示OpenCL平台的数量,一般作为返回值。
一般执行两次clGetPlatformIDs,第一次获取OpenCL平台数,第二次对OpenCL平台进行初始化。

OpenCL 设备

OpenCL设备: CPU、 GPU、 FPGA。

cl_int clGetDeviceIDs(cl_platform_id platform, cl_device_type device_type, cl_uint num_entries,
                      cl_device_id *devices, cl_uint *num_devices)
  • device_type: 表示 OpenCL 设备类型
  • devices: 表示 OpenCL 设备列表
  • num_devices: 表示设备数量

创建OpenCL上下文

只能使用同一平台的设备.

cl_context clCreateContext(const cl_context_properties *properties,
                           cl_uint num_devices,
                           const cl_device_id *devices,
                           void(*pfn_notify)(const char *errinfo,
                                   const void *private_info, size_t cb,
                                   void *user_data),
                           void *user_data,
                           cl_int *errcode_ret)
  • properties: 表示上下文的属性, properties[]={属性名称, 属性值, 0}
  • devices: 表示 OpenCL 设列表
  • pfn_notify: 与 user_data 共同做一个回调函数, 报告上下文生命周期中出现的错误信息
  • errcode_ret: 表示函数的返回状态
cl_context clCreateContextFromType(const cl_context_properties *properties,
                                   cl_device_type device_type,
                                   void (*pfn_notify)(const char *errinfo,
                                           const void *private_info, size_t cb,
                                           void *user_data),
                                   void *user_data,
                                   cl_int *errcode_ret)
  • properties: 表示上下文的属性
  • devices_type: 表示设备类型。同 OpenCL的设备类型取值

OpenCL 命令队列

对上下文当中的这些对象进行操作需要通过命令队列执行。

cl_command_queue clCreateCommandQueue(cl_context context,
                                      cl_device_id device,
                                      cl_command_queue_properties properties,
                                      cl_int *errcode_ret)
  • properties: 表示命令队列的属性 , 可以设置为 NULL

OpenCL 程序对象

  • 包含内核函数集合
  • 为关联设备编译内核
  • 可以由 OpenCL C 源代码文本创建
  • 可以使用程序二进制代码创建
cl_program clCreateProgramWithSource (cl_context context,
     cl_uint count,
     const char **strings,
     const size_t *lengths,
     cl_int *errcode_ret)

cl_program clCreateProgramWithBinary (cl_context context,
     cl_uint num_devices,
     const cl_device_id *device_list,
     const size_t *lengths,
     const unsigned char **binaries,
     cl_int *binary_status,
     cl_int *errcode_ret)
cl_int clBuildProgram (cl_program program,
     cl_uint num_devices,
     const cl_device_id *device_list,
     const char *options,
     void (CL_CALLBACK *pfn_notify)(cl_program program, void *user_data),
     void *user_data)

OpenCL 内核对象

  • 程序对象只是容器, 容纳多个内核对象
  • 内核对象是一个可以在设备上运行的函数
  • 内核对象实现具体的功能
  • 本质是一段代码(函数)
  • 需要编译为可执行文件(aocx)
  • 在OpenCL设备上执行

cl_kernel clCreateKernel (cl_program  program,
     const char *kernel_name,
     cl_int *errcode_ret)
  • kernel_name: 内核名称。 实际上就是一个函数名称
  • errcode_ret: 表示错误状态码

OpenCL 内存对象

  • 内核 ( 函数 ) 的参数如何设置?
  • 主机端如何向内核传递参数数据?
  • 主机端如何获取内核的执行结果?
使用内存对象
cl_mem clCreateBuffer (cl_context context,
     cl_mem_flags flags,
     size_t size,
     void *host_ptr,
     cl_int *errcode_ret)

设置内核参数

cl_int clSetKernelArg (cl_kernel kernel,
     cl_uint arg_index,
     size_t arg_size,
     const void *arg_value)

使用例子如下:

OpenCL 执行内核

  • 平台和设备已经选定
  • 上下文已经关联
  • 命令队列、程序对象已经就绪
  • 内核对象与内核参数已经准备
下一步执行内核,并且取回执行结果
cl_int clEnqueueNDRangeKernel (cl_command_queue command_queue,
     cl_kernel kernel,
     cl_uint work_dim,
     const size_t *global_work_offset,
     const size_t *global_work_size,
     const size_t *local_work_size,
     cl_uint num_events_in_wait_list,
     const cl_event *event_wait_list,
     cl_event *event)

// 相当于clEnqueueNDRangeKernel (queue, kernel, 1, NULL, NULL,
                               num_events_in_wait_list, even_wait_list, event)
cl_int clEnqueueTask (    cl_command_queue command_queue,
     cl_kernel kernel,
     cl_uint num_events_in_wait_list,
     const cl_event *event_wait_list,
     cl_event *event)

取回结果

cl_int clEnqueueReadBuffer (cl_command_queue command_queue,
     cl_mem buffer,
     cl_bool blocking_read,
     size_t offset,
     size_t cb,
     void *ptr,
     cl_uint num_events_in_wait_list,
     const cl_event *event_wait_list,
     cl_event *event)
  • blocking_read: 阻塞式的读取方式
  • offset: 读取的偏移量 。 通常设置为 0
  • cb: opencl 执行的结果所占据的内存人小
  • ptr: 主机端接收结果的指针

OpenCL 对象回收

  • 内核对象是动态加载构建的
  • 内存对象是实时申请的
  • 命令队列也是动态申情的
  • 上下文按需分配
资源有限,需要及时回收

资源回收有先后顺序

  1. 内核对象依赖于程序对象
  2. 程序对象依赖于设备和上下文
  3. 命令队列依赖于设备和上下文
  4. 内存对象依赖于上下文
  5. 上下文依赖于设备和平台
clReleaseKernel (kernel);
clReleaseCommandQueue (queue);
clReleaseMemObject (a buffer);
clReleaseMemObject (b_buffer);
clReleaseMemObject (c_buffer);
clReleaseContext (ctxt);

OpenCL 错误处理

if (CL_SUCCESS != err)
{
    printf("......");
    return -1;
}

基本简介和基本语法

矢量数据的使用和访问

使用限制:

  • 内核函数必须以 kernel 或者__kernel 作为前置修饰符
  • 内核参数不能是指向指针的指针
  • 内核函数的返回类型必须是 void
  • 不支持递归

仿真器和FPGA有什么区别

仿真器(Simulator)和 FPGA(Field-Programmable Gate Array)是两个不同的概念和工具,在硬件开发和验证中扮演不同的角色。

仿真器(Simulator):

  • 仿真器是一种软件工具,用于模拟硬件设计的行为和功能。
  • 仿真器可以在计算机上运行,并通过执行设计描述(如硬件描述语言)来模拟电路的行为。
  • 仿真器可以用于调试和验证硬件设计,检测潜在的错误和设计缺陷。
  • 仿真器能够提供详细的波形和时序信息,帮助开发者理解和分析设计的运行情况。

FPGA(Field-Programmable Gate Array):

  • FPGA 是一种可编程逻辑器件,它是一种硬件芯片,由可编程逻辑门和存储单元组成。
  • FPGA 具有可重构的特性,可以通过编程来定义其内部的逻辑功能和连接方式。
  • FPGA 可以实现定制的硬件功能,并具有较高的计算性能和并行处理能力。
  • FPGA 可以用于快速原型开发、高性能计算加速、嵌入式系统等领域。

区别:

  • 仿真器是一种软件工具,用于模拟和验证硬件设计的行为,而 FPGA 是一种可编程的硬件器件。
  • 仿真器在计算机上运行,模拟电路的行为,而 FPGA 是一种物理芯片,通过编程来定义其内部的逻辑功能。
  • 仿真器可以提供详细的波形和时序信息,帮助开发者调试和验证设计,而 FPGA 可以实际部署和运行硬件功能。
  • 仿真器通常用于设计验证和调试阶段,而 FPGA 通常用于原型开发、加速应用和嵌入式系统。
  • 在硬件开发流程中,通常会使用仿真器进行初步验证和调试,然后将设计部署到 FPGA 上进行实际的硬件测试和性能评估。仿真器和 FPGA 在硬件开发中相互补充,帮助开发者加快设计周期并确保设计的正确性和性能。

标签: opencl, gpu

添加新评论