【问题标题】:OpenCL (unexpectedly) freezes when trying to run kernel code尝试运行内核代码时,OpenCL(意外)冻结
【发布时间】:2013-01-04 06:09:31
【问题描述】:

嗯,我试过在 Apple 开发者论坛上提问,但没有人回应。我认为stackoverflow会更合适。在这里……

我有一些 OpenCL 内核,它遍历存储在帧缓冲区对象中的像素,并计算非黑色和非白色像素。它曾经在我的机器上运行良好,但我相信 Mac OS X 和/或 devtools 的更新可能会导致问题导致它停止。

与内核代码关联的内核对象附加到 QT 窗口,当窗口需要渲染更新时,内核代码会运行 n 次。此窗口在初始创建后会更新两次,这意味着 openCL 代码序列最初不会引起问题。当我将窗口置于前台时,它需要再次更新并尝试再次运行内核代码 n 次。但在这些 n 次中间,它停止了。即如果它需要运行 51 次,它会在第 26 次迭代时停止。看来对 clEnqueueReadBuffer 的调用会导致停止。

除非绝对必要,否则我将省略有关为什么使用 openCL 代码的详细信息,因为这可能会使人们感到困惑。我认为专注于 OpenCL 代码本身会很好。供参考:http://dl.dropbox.com/u/10838242/forumsquestion.cpp

这是 gdb 回溯:

#0  0x00007fff8e3a6122 in __psynch_mutexwait ()
#1  0x00007fff8955ad9d in pthread_mutex_lock ()
#2  0x000000010dd3acbd in gldFlushQueue ()
#3  0x000000010bbc193f in IOAccelContextFinishResourceSysMem ()    
#4  0x000000010bbcd5b0 in gpumAcquireFenceOnQueue ()
#5  0x000000010dd43fcd in gldCopyBufferDataWithQueue ()
#6  0x00007fff8ffa7e2e in GCC_except_table49 ()
#7  0x00007fff8ffc5f11 in clFinish ()
#8  0x00007fff936800b6 in _dispatch_client_callout ()
#9  0x00007fff93681723 in _dispatch_barrier_sync_f_invoke ()
#10 0x00007fff8ffc5ddb in clFinish ()
#11 0x00007fff8ffc25c2 in clSetEventCallback ()
#12 0x00007fff8ffb86e6 in clEnqueueReadBuffer ()
#13 0x0000000100020a31 in CLHandler::update (this=0x107683e20, tagged=@0x7fff5fbfb960, w=761, h=711) at clhandler.cpp:343
#14 0x000000010002f8c1 in CustomBladesGLWidget::render (this=0x1072b09e0, indexMode=true, offset=135288, numPnts=4416, blobID=25, bladeIdsIntersected=@0x7fff5fbfb960) at customBladesGLWidget.cpp:943

在附件中,第 343 行(上面的粗体)对应于这个调用(在函数 CLHandler::update 中):

//read data from buffer
status = clEnqueueReadBuffer(cqueue,hitbuffer,CL_TRUE,0,mNumBladeCells * sizeof(float),mBladesHit,0, NULL,&event);
handleError("clEnqueueReadBuffer","",status);

现在,如果我要在对 clEnqueueWriteBuffer 的初始调用下方注释所有内容,它将改为在该函数调用处停止。我不知道为什么会这样。这不像我在尝试使用互斥锁或任何东西。非常感谢任何帮助。

系统规格:MacbookPro 8,2、Core i7 2.2 GHz、AMD Radeon HD 6750M、OS X 10.8.2。

谢谢

【问题讨论】:

    标签: c++ macos opencl


    【解决方案1】:

    在使用 GL 对象的第一个 OpenCL API 调用之前应该调用glFinish,在最后一个之后调用clFinish。较弱的选项(即调用 Flush 而不是 Finish)可能适用于特定平台。

    请参阅OpenCL 1.2 extension specification,第 9.7.6.1 节。

    更新。特别是在 Apple 平台上,最快的选择是在第一次 OpenCL 调用之前调用glFlushRenderApple,在最后一次调用之后调用clFinish

    【讨论】:

    • 这对我来说很有意义——存在某种同步问题。对我有用的两种可能的解决方案包括执行 glFinish/clFinish 或在 clEnqueueReleaseGLObjects 调用之后执行 waitForevents 调用。该文件中提到了两者。但总的来说,最好调用 glFinish 和 clFinish(即使我调用了 waitforevents)以确保不会发生任何不好的事情。谢谢。
    • 我刚刚看到您对 Apple 平台的更新评论。我想我在这里并不需要速度,但我会记住这一点。
    【解决方案2】:

    如果您声明它正在阻止写入(第三个参数为真),为什么要将事件传递给 clEnqueueWriteBuffer/clEnqueueReadBuffer?由于这个原因,您也不需要对 clWaitForEvents(1, &event) 进行任何调用。

    相反,我会将事件添加到 clEnqueueNDRangeKernel。并在 clFlush() 之后等待它。 因为 clFlush 只触发执行,但不能保证在其调用之后所有先前排队的命令都会完成(与 clFinish 不同)。然后才调用 clEnqueueReleaseGLObjects。但是,只要您的队列不是使用 CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE 标志创建的,您的情况也应该没问题。

    您还可以指定注释/取消注释的确切行吗?

    【讨论】:

    • 谢谢。我已经在链接的 cpp 文件中标记了内容被评论的位置(请参阅 update(*) 函数)。我会给你与活动相关的建议。我将它用于 clEnqueueWrite/Read 调用,因为我是 OpenCL 的新手……是的,不需要 clWaitForEvents,因为它已经阻塞了。所以你想让我在 NDRangeKernel 之后等待事件,然后调用 release?
    • 虽然 waitforevents 调用可以在 clEnqeueueNDRangeKernel 之后进行并且不会导致锁定,但它应该在根据@Eric 链接的规范释放对象的调用之后。无论如何,根据该链接,确保挂起的 OpenGL 和/或 OpenCL 操作不会相互干扰是一种很好的做法。这很重要,因为我的代码确实使用了 OpenGL 对象。我在 forumsquestion.cpp 文件中添加了一个“好版本”的更新功能,就在“坏”之后。
    猜你喜欢
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-23
    • 1970-01-01
    相关资源
    最近更新 更多