OpenCL 学习(5)---- OpenCL 内核和内核参数

目录

创建内核函数

OpenCL 中,使用 cl_kernel 数据结构来表示内核对象,OpenCL 使用如下函数来创建内核对象

c 复制代码
cl_kernel clCreateKernel(
      cl_program program,           // 程序对象
      const char *kernel_name,      // 内核函数名,CL代码中要执行的函数名 如上例子,使用的内核函数名就是 "image_filter"
      cl_int *errcode_ret);         // 输出错误码,如果成功返回 0

函数 clCreateKernel,参数 programOpenCL 编译的 Program 对象中构建的程序对象,里面包含了多个内核对象

参数 kernel_name 为程序对象中用 __kernel 地址限定符的内核对象名称,参数 errcode_ret 是函数的执行返回状态

c 复制代码
clCreateKernelsInProgram(cl_program     /* program */,
                         cl_uint        /* num_kernels */,
                         cl_kernel *    /* kernels */,
                         cl_uint *      /* num_kernels_ret */) ;

函数 clCreateKernelsInProgram,参数 program 是构建的程序对象,参数 kernels 为返回的内核对象列表,参数 num_kernels 为内核对象列表中内核的个数,参数 num_kernels_ret 为程序对象中内核个数,如果为 NULL 就忽略这个参数

如果程序中有多个对象,使用 clCreateKernelsInProgram 创建内核对象,但是注意内核列表中的内核函数名称顺序并不是根据 cl 文件中的内核书写顺序,而是依赖于实现

设置内核参数

为了执行一个具体的内核,需要向内核函数传递参数,OpenCL 使用下面函数来设置内核参数:

c 复制代码
clSetKernelArg(cl_kernel    /* kernel */,
               cl_uint      /* arg_index */,
               size_t       /* arg_size */,
               const void * /* arg_value */);

参数 kernel 为内核对象,参数 arg_index 为内核函数参数的索引,按照从左到右的顺序,第一个(最左边的)参数索引为 0, 第二个参数索引为 1,以此类推:

参数 arg_size 表示参数的大小,分为下面几种情况:

  • 如果参数为内存对象,那么 arg_size 为内存对象类型的大小(例如: sizeof(cl_mem))
  • 如果参数用 local修饰符声明,则 arg_size 用来存储参数的缓冲区所需的字节数
  • 如果参数为 sampler_t 类型,则 arg_size 大小必须扽与 sizeof(cl_sampler)
  • 如果参数为 queue_t 类型,则 arg_size 大小必须等于 sizeof(cl_command_queue)
  • 如果参数为其他类型,arg_size 大小为该类型参数大小(例如: 对一个 cl_int 类型参数,大小为 sizeof(cl_int))

参数的 arg_value 为传入内核参数的一个指针:

  • 如果参数为内存对象(cl_mem),则指针指向合适的缓冲、管道、图像或者图像数组对象
  • 如果参数用 local 修饰符声明,arg_value 必须为 NULL
  • 如果参数为 sampler_t, arg_value 必须指向采样器对象
  • 如果参数为 queue 类型,arg_value 必须指向设备队列对象
内核参数设置举例

比如一个内核函数实现如下:

c 复制代码
__kernel void image_filter(
  const __global uchar*   in_img_data,            
  const int               pxl_bytes,
  const int               img_line_bytes, 
  const __global double*  in_coeff,
  const int               coeff_wnd_size,
  __global uchar*         out_img_data  )

设置内核函数参数,有下面的对应关系:

  • 对于 cl 代码中,形如charfloatint 等基本类型的参数,在 C 语言中有 cl_charcl_intcl_float 等基本的数据类型对应,设置参数时使用这些基本的数据类型即可

  • 对于 cl 代码中,形如 const __global uchar* const__global double* 等指针类型的参数,在 C 语言中统一使用 cl_mem 缓冲区对象来传递下去

  • 对于 cl 代码中,形如 image2d_t srcImage,sampler_t sampler 等图像对象、采样器对象的参数,在 C 语言中统一使用 cl_memcl_sampler 等对象传递下去

所以对上述的 imagefilter 核函数设置参数:

c 复制代码
// 这里的 image_filter 是内核函数名称
kernel_filter_ = clCreateKernel(program_, "image_filter", &err_code);
CHK_CLERR(err_code);

// 给 image_filter 中各个参数设置参数值,从索引 0 开始
err_code = clSetKernelArg(kernel_filter_, 0, sizeof(cl_mem), (void*)&mem_in_img);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 1, sizeof(cl_int), (void*)&pxl_bytes);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 2, sizeof(cl_int), (void*)&line_bytes);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 3, sizeof(cl_mem), (void*)&mem_in_coeff);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 4, sizeof(cl_int), (void*)&coeff_wnd_size);
CHK_CLERR(err_code);
err_code = clSetKernelArg(kernel_filter_, 5, sizeof(cl_mem), (void*)&mem_out_img);
CHK_CLERR(err_code);
clReleaseKernel(kernel); 
查询内核信息

一旦创建了内核对象,开发人员如果想知道内核对象的一些属性信息,可以使用如下函数查询内核对象的属性信息

c 复制代码
clGetKernelInfo(cl_kernel       /* kernel */,
                cl_kernel_info  /* param_name */,
                size_t          /* param_value_size */,
                void *          /* param_value */,
                size_t *        /* param_value_size_ret */);

参数 param_name 为查询内核对象的属性名称,可以接受的参数如下表,参数 param_value 为存储结果的位置指针,

参数 param_value_size 为参数 param_value 的字节数,参数 param_value_size_ret 为实际写入的字节数

cl_kernel_work_group_info 返回值 描述
CL_KERNEL_GLOBAL_WORK_SIZE size_t[3] 指定设备上执行内核最大可用的工作项大小
CL_KERNEL_WORK_GROUP_SIZE size_t 指定设备上执行内核最大可用工作组大小
CL_KERNEL_COMPILE_WORK_SIZE size_t[3] TBD
CL_KERNEL_LOCAL_MEM_SIZE cl_ulong 返回内核函数使用的局部内存量
CL_KERNEL_PERFERRED_WORK_GROUP_SIZE_MULTIPLE size_t 给出一个最优工作组大小倍数
CL_KERNEL_PERFERRED_PRIVATE_MEM_SIZE cl_ulong 返回各工作项使用的最小私有内存量

函数 clGetkernelInfo 不能查询特定于某个设备的内核对象信息,例如:如何将一个并行负载分派到执行内核的一个或者多个不同设备上,那么 该如何处理?

OpenCL 中提供了如下函数可以查询特定于某个设备的内核对象属性信息

c 复制代码
clGetKernelWorkGroupInfo(cl_kernel                  /* kernel */,
                         cl_device_id               /* device */,
                         cl_kernel_work_group_info  /* param_name */,
                         size_t                     /* param_value_size */,
                         void *                     /* param_value */,
                         size_t *                   /* param_value_size_ret */);

参数 device 为内核对象关联的设备列表中的一个特定设备,参数 param_name 为查询内核工作组的属性信息,可以接受参数如下表,其他参数

类似于 clGetKernelInfo

下面例子用来查询工作组信息:

TBD

相关推荐
m0_564914921 小时前
AI学习课堂网站丨OPENMAIC丨清华团队开源项目
学习
开源盛世!!2 小时前
3.26-3.27学习笔记
笔记·学习
我的xiaodoujiao3 小时前
API 接口自动化测试详细图文教程学习系列7--相关Python基础知识6
python·学习·测试工具·pytest
山川行3 小时前
Python快速闯关8:内置函数
java·开发语言·前端·笔记·python·学习·visual studio
charlie1145141913 小时前
嵌入式C++教程实战之Linux下的单片机编程:从零搭建 STM32 开发工具链(2) —— HAL 库获取、启动文件坑位与目录搭建
linux·开发语言·c++·stm32·单片机·学习·嵌入式
知识分享小能手3 小时前
MongoDB入门学习教程,从入门到精通,MongoDB聚合框架(7)
数据库·学习·mongodb
今儿敲了吗4 小时前
算法复盘——前缀和
笔记·学习·算法
啊我不会诶4 小时前
最小生成树
c++·笔记·学习·算法
STLearner5 小时前
AI论文速读 | 元认知监控赋能深度搜索:认知神经科学启发的分层优化框架
大数据·论文阅读·人工智能·python·深度学习·学习·机器学习
Z.风止5 小时前
Large Model-learning(1)
开发语言·笔记·git·python·学习