之前写OpenCL kernel的时候曾经饱受CL_OUT_OF_RESOURCES的困扰。
平时写完kernel都是核显在跑,毕竟NV对OpenCL的支持就像苹果对OpenGL的支持一样,是个存在利益竞争的老大难问题。可问题在于,核显上跑得好好的kernel,一到独显上就出问题了。
在跑完kernel,EnqueueReadBuffer时,我会收到一个CL_OUT_OF_RESOURCES的错误。
官方文档的说法是这样的[1]:
there is a failure to allocate resources required by the OpenCL implementation on the device
可我在ReadBuffer呀,那块buffer都已经在device端被写入了,并不需要申请什么资源,要报错也应该在CreateBuffer的时候报错才对啊。
直到后来某天,我在debug时改了一个下标越界的bug,心血来潮放到独显上一跑,居然通过了……
好嘛,这哪是out of resources,这明明是index out of range……
其实类似的现象我不是头一个遇到的,很多人都或多或少总结过原因,比如这里:
Basic Concepts: out of resources with clEnqueueReadBuffer - StreamHPCstreamhpc.com按照文内的说法,除了下标越界,资源申请过多这两种最常见情况,kernel运行过久触发TDR也会引起OUT_OF_RESOURCES的错误。
OpenCL不像OpenGL那么古老,它一开始就有针对context的notify回调,输出具体错误信息再好不过了。像现在这样什么都往OUT_OF_RESOURCES这样文不对题的错误里装,实在不应该。
看起来问题已经解决了?
其实并不算。为什么N卡会报告下标越界,I家核显却不会呢?
其实这个不算是bug,更像是一种feature……
iGPU的内存读写(包括纹理)都是靠message完成的。而根据文档[2],硬件的确是会对message做bound check,只不过似乎并不产生实际的错误。对于越界读,它会直接返回0;对于越界写,写入会被忽略。并且这个bound check是以4字节为单位进行检查的。
这也大概也能解释上一篇文章中,I家核显bindless texture设置错却不报错的原因:
XZiar:OGL和OGLU的Texture bindingzhuanlan.zhihu.com毕竟设置错texture,只会使得读纹理的message变得malformed,而这条message本身是不会产生异常的。
iGPU甚至对GRF寄存器的越界访问都不会产生异常,而是可能直接映射回从0开始[3]。我不确定其他家有没有类似的操作。
“GRF越界”看起来不可思议,毕竟GRF数量应该是ISA定好的,Gen也不支持动态生成指令,驱动完全可以检测出这种问题才对。但iGPU有一个特性,支持间接寄存器寻址(即R1=16,[R1]意味着R16),所以的确是可能越界……
(当然我并没在反汇编里真的看见过indirect GRF addressing的存在……)
参考
- ^clEnqueueReadBuffer https://www.khronos.org/registry/OpenCL/sdk/1.2/docs/man/xhtml/clEnqueueReadBuffer.html
- ^P183 https://www.x.org/docs/intel/HSW/intel-gfx-prm-osrc-hsw-3d-media-gpgpu-engine_0.pdf
- ^P1006 https://www.x.org/docs/intel/HSW/intel-gfx-prm-osrc-hsw-3d-media-gpgpu-engine_0.pdf