opencl C++接口: 关于CL_KERNEL_FUNCTION_NAME的一个坑
来源:互联网 发布:淘宝互踩 编辑:程序博客网 时间:2024/05/29 13:35
我的项目中所有的kernel在程序初始化时就被编译生成了,存放在一个std::unordered_map<std::string, cl::Kernel>
类型的map表中(kernel name为key),以后程序需要调用的时候,就通过kernel name来获取指定的cl::Kernel
对象。
建这个表的时候,要创建cl::Kernel
。常用的创建cl::Kernel
的途径有两个:
cl::Program::createKernels
opencl C++接口(cl.hpp)中的cl::Program::createKernels
成员函数封装了clCreateKernelsInProgram函数,可以返回cl::Program
中所有的cl::Kernel
对象,当一个cl::Program
中有多个kernel函数的时候,用它可以一次性得到所有的cl::Kernel
对象,挺方便的。
下面是它的源码:
cl_int createKernels(VECTOR_CLASS<Kernel>* kernels) { cl_uint numKernels; cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels); if (err != CL_SUCCESS) { return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); } Kernel* value = (Kernel*) alloca(numKernels * sizeof(Kernel)); err = ::clCreateKernelsInProgram( object_, numKernels, (cl_kernel*) value, NULL); if (err != CL_SUCCESS) { return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR); } kernels->assign(&value[0], &value[numKernels]); return CL_SUCCESS; }
cl::Kernel构造函数
从cl::Program
中创建cl::Kernel
还有一个方法就是使用cl::Kernel
的构造函数,指定kernel name(下面代码中的name
参数)就可以创建指定的cl::Kernel
:
inline Kernel::Kernel(const Program& program, const char* name, cl_int* err){ cl_int error; object_ = ::clCreateKernel(program(), name, &error); detail::errHandler(error, __CREATE_KERNEL_ERR); if (err != NULL) { *err = error; }}
找不到kernel的问题
我本来使用的是第二种方法,一切正常,昨天我想改变一下代码结构使用第一种方法来创建cl::Kernel
。但是发现了问题:
/* 通过param提供的源码创建一组cl::Kernel,并将cl::Kernel命名为name加入kernels映射表中 */static std::unordered_map<std::string, cl::Kernel> createKernels(const build_param& param, const std::vector<std::string>& kernel_names) { auto program = buildExecutableProgram(param);//编译kernel源码生成可执行的cl::Program对象 std::unordered_map<std::string, cl::Kernel> map;// name->kernel映射表 std::vector<cl::Kernel> kernels; program.createKernels(std::addressof(kernels));//获取cl::Program中所有的cl::Kernel对象 for (auto k:kernels) { auto name=k.getInfo<CL_KERNEL_FUNCTION_NAME>();// 调用clGetKernelInfo获取的kernel名字 cout << "name from kernel:"<<name <<" size="<<name.size()<< endl; map.insert({ name, k });//将kernel以name为key加入map std::string original_name = "image_scaling";// 实际的kernel name cout << "original name:" <<original_name <<" size="<<original_name .size()<< endl; if (original_name != name) { cout << "not equal" << endl; } // 用original_name在map中查找指定的cl::Kernel if (map.find(original_name ) == map.end()) { cout << "not found:"<<a << endl; } } return map;}
下面是程序的输出,尼玛,它居然找不到image_scaling
!!!
其实上面的程序输出也指明了找不到的原因,original_name
与name
虽然打印出来看着是一模一样,但它们俩的长度却不一样
下面是original_name
在内存中的数据
下面是name 在内存中的数据
也就是说clGetKernelInfo
取出来的kernel name字符串比original_name
多了一个结尾’\0’…
解决办法
找到原因了,解决问题办法也就有了:
在执行map.insert()
函数将cl::Kernel
加入std::unordered_map
时不能直接用 auto name=k.getInfo<CL_KERNEL_FUNCTION_NAME>()
得到的std::string
对象为key,要把name
中最后那个多出来的’\0’去掉,才是个正常的std:string
只需要修改下面这行代码:
map.insert({ name, k });//将kernel以name为key加入map
改为:
map.insert({ std::string(name.data()), k });//将kernel以name为key加入map
问题解决。
结论
cl::Kernel::getInfo<CL_KERNEL_FUNCTION_NAME>()
获取的std::string
对象不是一个正常的std:string
,需要改造将结尾处多余的’\0’去掉,才是一个我们通常意义上的string。
其实不仅获取kernel name有这个坑,而是所有clgetXXXInfo
函数中获取的字符串类型的数据,都有这个问题。
- opencl C++接口: 关于CL_KERNEL_FUNCTION_NAME的一个坑
- opencl:一个关于向量赋值的异常
- 一个简单的OpenCL程序
- OpenCL的一个简单例子!
- 关于OpenCL架构的整理
- 【入门】OpenCL C的限制
- 关于接口的一个理解
- OpenCL 学习笔记 - OpenCL C built-in functions - OpenCL C的内建函数
- OpenCL: OpenCL的shader
- opencl 插值取样的一个代码
- JAVA菜鸟关于接口的一个问题
- 关于PreparedStatement接口的一个测试
- 关于Java内部接口的一个问题
- 关于接口隔离原则的一个实现
- 关于测试一个接口的面试题
- 一个 C 接口设计的问题
- 一个 C 接口设计的问题
- 关于C的 一个问题
- 索引之tf-idf
- 交换机和路由器的区别
- Best practices for the logging REST API
- ios-提升之【7】-定时器
- UIScrollView、UIPageControl、NSTimer
- opencl C++接口: 关于CL_KERNEL_FUNCTION_NAME的一个坑
- 并查集
- iOS开发笔记--什么时候调用layoutSubviews
- Service之断点续传(下载)
- js将字符串转换为一维二维数组
- OpenCV学习笔记_用指针操作图像元素
- 旋转方法
- 第三周项目三 输出图形
- 代理模式