PyCUDA+线程 = 内核调用时无效句柄

1 投票
2 回答
3183 浏览
提问于 2025-04-16 17:10

我尽量把这个说清楚;

我有两个类;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 个回答

1

典型啊;我一写出问题就自己想明白了。

问题在于SourceModule在一个不活跃的环境中运行。为了解决这个问题,我把SourceModule的调用移到了线程中的run函数里,放在了cuda上下文设置的下面。

我先把这个留着一段时间,因为我相信还有其他人能给出更好的解释!

5

原因在于上下文的亲和性。每个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")

撰写回答