OpenCL基础介绍
参考链接: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_sizeandglobal_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 bylocal_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 对象回收
- 内核对象是动态加载构建的
- 内存对象是实时申请的
- 命令队列也是动态申情的
- 上下文按需分配
资源有限,需要及时回收
资源回收有先后顺序
- 内核对象依赖于程序对象
- 程序对象依赖于设备和上下文
- 命令队列依赖于设备和上下文
- 内存对象依赖于上下文
- 上下文依赖于设备和平台
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 在硬件开发中相互补充,帮助开发者加快设计周期并确保设计的正确性和性能。
























