草庐IT

c++ - clEnqueueNDRangeKernel 触发 CL_INVALID_MEM_OBJECT (-38)

coder 2024-02-24 原文

我正在为 OpenCL 使用 C++ 绑定(bind),当我的一个内核入队时,我得到一个 cl::Error,它说 -38 (CL_INVALID_MEM_OBJECT) for clEnqueueNDRangeKernel.

此错误未列为 clEnqueueNDRangeKernel 的可能错误之一. 通知功能给我以下输出:

CL_INVALID_MEM_OBJECT error executing CL_COMMAND_NDRANGE_KERNEL on GeForce GTX 560 (Device 0).

我还没有找到展示这种行为的最小示例。

在调用这个函数时,什么会导致这种错误?

使用谷歌我只找到了这个 answer然而。它声明我需要重新setKernelArg 附加的内存对象(如果它已更新)。 (至少这是我对它的解释,没有详细解释更新的含义。) 然而,我怀疑这是正确的,尽管我无法证明这一点。也许您知道这方面的官方消息来源?

更新

经过一些测试,我发现向内核添加一个 __global const float* 参数会引入错误。我还发现,如果我在另一个(已经存在的)参数之后 clSetKernelArg 这个新参数,那么每次都会发生错误。如果我在设置另一个参数之前这样做,它会每隔两次工作一次。当然这不是一个选项,因为我需要能够随时设置参数。

更新2

我注意到通过调试单步执行代码会“重新引入”我在另一个参数之前设置新参数的版本中的错误。 (这意味着错误每次都会再次发生。)

这可能是某种竞争条件吗?我自己不使用多线程,但在调试器中有 7 个线程可能来自 Qt 或 OpenCL。

最小工作示例

#include <CL/cl.hpp>
#include <vector>
#include <iostream>

#define STRINGIFY(x) #x

std::string kernel = STRINGIFY(
__kernel void apply(__global const float *param1)
{
}
);


template <class T>
cl::Buffer genBuffer(const cl::Context &context, const std::vector<T> &data,
                        cl_mem_flags flags = CL_MEM_READ_ONLY)
{
        return cl::Buffer(context, flags | CL_MEM_COPY_HOST_PTR,
                                data.size() * sizeof(data[0]),
                                const_cast<T*>(&data[0]));
}

int main()
{
        std::vector<cl::Platform> clPlatforms;
        cl::Platform::get(&clPlatforms);
        cl_context_properties props[] = {
                CL_CONTEXT_PLATFORM, (cl_context_properties)clPlatforms[0](),
                0};
        cl::Context clContext = cl::Context(CL_DEVICE_TYPE_GPU, props);
        std::vector<cl::Device> devices = clContext.getInfo<CL_CONTEXT_DEVICES>();
        if(devices.empty())
        {
                std::cerr << "No devices found!\n";
                exit(-1);
        }
        cl::Device clDevice = devices[0];
        cl::CommandQueue clQueue = cl::CommandQueue(clContext, clDevice, 0, 0);
        cl::Program program(clContext, cl::Program::Sources(1,
                                std::make_pair(kernel.c_str(), kernel.size())));
        program.build(devices);
        cl::Kernel kernel(program, "apply");

        //this introduces the error
        kernel.setArg(0, genBuffer(clContext, std::vector<cl_float>(100));
        //the error is triggered here
        clQueue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(100), cl::NullRange);
}

最佳答案

问题是我将缓冲区附加到内核,假设内核会保留缓冲区。然后我销毁了所有引用 cl::Buffer/Memory 的对象,这导致 OpenCL 实现删除缓冲区。


通过 valgrind 运行我的程序后,我注意到 opencl.so 访问了先前在 cl::~Buffer 子例程中释放的对象的内存。继续阅读 clSetKernelArg我注意到:

Users may not rely on a kernel object to retain objects specified as argument values to the kernel.

不确定的行为显然是驱动程序访问释放的内存区域从而进入 UB 域的结果。

修正后的 MWE

#include <CL/cl.hpp>
#include <vector>
#include <iostream>

#define STRINGIFY(x) #x

std::string kernel = STRINGIFY(
__kernel void apply(__global const float *param1)
{
}
);


template <class T>
cl::Buffer genBuffer(const cl::Context &context, const std::vector<T> &data,
                        cl_mem_flags flags = CL_MEM_READ_ONLY)
{
        return cl::Buffer(context, flags | CL_MEM_COPY_HOST_PTR,
                                data.size() * sizeof(data[0]),
                                const_cast<T*>(&data[0]));
}

int main()
{
        std::vector<cl::Platform> clPlatforms;
        cl::Platform::get(&clPlatforms);
        cl_context_properties props[] = {
                CL_CONTEXT_PLATFORM, (cl_context_properties)clPlatforms[0](),
                0};
        cl::Context clContext = cl::Context(CL_DEVICE_TYPE_GPU, props);
        std::vector<cl::Device> devices = clContext.getInfo<CL_CONTEXT_DEVICES>();
        if(devices.empty())
        {
                std::cerr << "No devices found!\n";
                exit(-1);
        }
        cl::Device clDevice = devices[0];
        cl::CommandQueue clQueue = cl::CommandQueue(clContext, clDevice, 0, 0);
        cl::Program program(clContext, cl::Program::Sources(1,
                                std::make_pair(kernel.c_str(), kernel.size())));
        program.build(devices);
        cl::Kernel kernel(program, "apply");

        //this version triggers the error
        //kernel.setArg(0, genBuffer(clContext, std::vector<cl_float>(100));

        //This is how it is done correctly
        cl::Buffer buffer = genBuffer(clContext, std::vector<cl_float>(100));
        kernel.setArg(0, buffer);

        clQueue.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(100), cl::NullRange);
}

关于c++ - clEnqueueNDRangeKernel 触发 CL_INVALID_MEM_OBJECT (-38),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18902575/

有关c++ - clEnqueueNDRangeKernel 触发 CL_INVALID_MEM_OBJECT (-38)的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  4. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  5. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  6. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  7. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  8. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby - 你会如何在 Ruby 中表达成语 "with this object, if it exists, do this"? - 2

    在Ruby(尤其是Rails)中,您经常需要检查某物是否存在,然后对其执行操作,例如:if@objects.any?puts"Wehavetheseobjects:"@objects.each{|o|puts"hello:#{o}"end这是最短的,一切都很好,但是如果你有@objects.some_association.something.hit_database.process而不是@objects呢?我将不得不在if表达式中重复两次,如果我不知道实现细节并且方法调用很昂贵怎么办?显而易见的选择是创建一个变量,然后测试它,然后处理它,但是你必须想出一个变量名(呃),它也会在内存中

随机推荐