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

相关推荐
西岸行者11 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意11 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码11 天前
嵌入式学习路线
学习
毛小茛11 天前
计算机系统概论——校验码
学习
babe小鑫11 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms11 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下11 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。11 天前
2026.2.25监控学习
学习
im_AMBER11 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J11 天前
从“Hello World“ 开始 C++
c语言·c++·学习