PyCUDA+线程 = 内核调用时无效句柄
我尽量把这个说清楚;
我有两个类;GPU(Object)
,用于一般的GPU功能访问,还有multifunc(threading.Thread)
,这是我想要让它支持多设备的一个特定功能。GPU
包含了所有后续使用所需的大部分“第一次”处理,所以multifunc
是从GPU
中调用的,并且将它的self
实例作为__init__
的参数传递(还有一些常规的队列等)。
不幸的是,multifunc
出现了问题:
File "/home/bolster/workspace/project/gpu.py", line 438, in run
prepare(d_A,d_B,d_XTG,offset,grid=N_grid,block=N_block)
File "/usr/local/lib/python2.7/dist-packages/pycuda-0.94.2-py2.7-linux-x86_64.egg/pycuda/driver.py", line 158, in function_call
func.set_block_shape(*block)
LogicError: cuFuncSetBlockShape failed: invalid handle
首先检查的当然是块的维度,但它们都在正常范围内(即使我强制设置block=(1,1,1)
,行为也是一样,网格也是如此)。
基本上,在multifunc
中,所有常规的CUDA内存分配等功能都正常工作(这意味着不是上下文的问题),所以问题一定出在内核函数的SourceModule
上。
我有一个包含所有CUDA代码的内核模板,它是文件作用域的,模板化是在GPU
初始化时使用jinja2
完成的。无论这个模板对象是在GPU
中转换为SourceModule
对象并传递给multifunc
,还是在multifunc
中转换,都会出现同样的问题。
谷歌在这个特定问题上几乎没什么用,但根据堆栈信息,我猜测提到的Invalid Handle
是指内核函数句柄,而不是块维度上有什么奇怪的情况。
我知道这是一个非常特殊的情况,但我相信总有人能发现我遗漏的问题。
2 个回答
典型啊;我一写出问题就自己想明白了。
问题在于SourceModule在一个不活跃的环境中运行。为了解决这个问题,我把SourceModule的调用移到了线程中的run函数里,放在了cuda上下文设置的下面。
我先把这个留着一段时间,因为我相信还有其他人能给出更好的解释!
原因在于上下文的亲和性。每个CUDA函数实例都与一个上下文绑定在一起,它们不能随意移动(同样的情况也适用于内存分配和纹理引用)。所以每个上下文必须单独加载函数实例,然后使用加载操作返回的函数句柄。
如果你完全不使用元编程,可能会觉得将你的CUDA代码编译成一个cubin文件更简单,然后通过driver.module_from_file
从cubin中加载你需要的函数到每个上下文中。下面是我一些生产代码的直接剪切和粘贴:
# Context establishment
try:
if (autoinit):
import pycuda.autoinit
self.context = None
self.device = pycuda.autoinit.device
self.computecc = self.device.compute_capability()
else:
driver.init()
self.context = tools.make_default_context()
self.device = self.context.get_device()
self.computecc = self.device.compute_capability()
# GPU code initialization
# load pre compiled CUDA code from cubin file
# Select the cubin based on the supplied dtype
# cubin names contain C++ mangling because of
# templating. Ugly but no easy way around it
if self.computecc == (1,3):
self.fimcubin = "fim_sm13.cubin"
elif self.computecc[0] == 2:
self.fimcubin = "fim_sm20.cubin"
else:
raise NotImplementedError("GPU architecture not supported")
fimmod = driver.module_from_file(self.fimcubin)
IterateName32 = "_Z10fimIterateIfLj8EEvPKT_PKiPS0_PiS0_S0_S0_jjji"
IterateName64 = "_Z10fimIterateIdLj8EEvPKT_PKiPS0_PiS0_S0_S0_jjji"
if (self.dtype == np.float32):
IterateName = IterateName32
elif (self.dtype == np.float64):
IterateName = IterateName64
else:
raise TypeError
self.fimIterate = fimmod.get_function(IterateName)
except ImportError:
warn("Could not initialise CUDA context")