前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >opencl C++接口: 关于CL_KERNEL_FUNCTION_NAME的一个坑

opencl C++接口: 关于CL_KERNEL_FUNCTION_NAME的一个坑

作者头像
10km
发布2019-05-25 22:42:46
6970
发布2019-05-25 22:42:46
举报
文章被收录于专栏:10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433793

我的项目中所有的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对象,挺方便的。

下面是它的源码:

代码语言:javascript
复制
    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:

代码语言:javascript
复制
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。但是发现了问题:

代码语言:javascript
复制
/* 通过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_namename虽然打印出来看着是一模一样,但它们俩的长度却不一样

下面是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

只需要修改下面这行代码:

代码语言:javascript
复制
map.insert({ name, k });//将kernel以name为key加入map

改为:

代码语言:javascript
复制
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函数中获取的字符串类型的数据,都有这个问题。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年03月13日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • cl::Program::createKernels
  • cl::Kernel构造函数
  • 找不到kernel的问题
  • 解决办法
  • 结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档