【问题标题】:Using python handles on cuda allocated memory with ctypes在带有 ctypes 的 cuda 分配内存上使用 python 句柄
【发布时间】:2014-01-04 14:30:44
【问题描述】:

我正在尝试使用 python 通过 ctypes 来控制 cuda。在这里,为了说明我的问题,我使用 python 将指针传递给分配 cuda 内存的 c 函数,将 numpy 数组复制到 cuda 内存,并将 cuda 内存复制回新的 numpy 数组。但它似乎不起作用,尽管我的基本 ctypes 设置工作。我认为问题在于从 cudaMalloc 函数返回给 python 的内容。

这是python代码

  pycu_alloc = dll.alloc_gpu_mem
  pycu_alloc.argtypes = [c_size_t]
  pycu_alloc.restypes = [c_void_p]   

  host2gpu = dll.host2gpu
  host2gpu.argtypes = [c_void_p, c_void_p, c_size_t]

  gpu2host = dll.gpu2host
  gpu2host.argtypes = [c_void_p, c_void_p, c_size_t]

  a = np.random.randn(1024).astype('float32')
  c = np.zeros(1024).astype('float32')

  c_a = c_void_p(a.ctypes.data)
  c_c = c_void_p(c.ctypes.data)

  da = pycu_alloc(1024)
  c_da = c_void_p(da)

  host2gpu(c_a, c_da, 1024)
  gpu2host(c_c, c_da, 1024)

  print a
  print c

和 C:

extern "C" {
float *  alloc_gpu_mem( size_t N)
{
  float *d;
  int size = N *sizeof(float);
  int err;

  err = cudaMalloc(&d, size);

  printf("cuda malloc: %d\n", err);
  return d;
 }}

 extern "C" {
 void host2gpu(float * a, void * da, size_t N)
 {
  int size = N * sizeof(float);
  int err;
  err = cudaMemcpy(da, a, size, cudaMemcpyHostToDevice);
  printf("load mem: %d\n", err);
  }}

  extern "C"{
 void gpu2host(float *c, void *d_c, size_t N)
 {
  int  err;
  int size = N*sizeof(float);
  err = cudaMemcpy(c, d_c, size, cudaMemcpyDeviceToHost);
  printf("cpy mem back %d\n", err);
 }}

代码应该将一个随机向量 a 复制到 cuda 内存,然后将该 cuda 内存复制回一个空向量 c。当我打印c 时,我想,这只是0s。

我与float*void* 的不同可能性作斗争,尤其是alloc_gpu_mem 的工作方式。但我不知道该怎么办。

至于err 返回值,cudaMalloc 返回0,但cudaMemcpy 均返回11。

python 指针有什么问题?帮助?

【问题讨论】:

  • 这并不能直接回答您的问题,但是……您是否尝试过来自Andreas Klöckner 的现有 Python CUDA 绑定(我认为这与 Nvidia 从他们的网站链接到的绑定相同,但我没有t检查)?
  • 不,我正在看那个,我可能应该使用它们,但我想潜入并自己控制 cuda,以确保我知道发生了什么。然后我开始为自己提供 python 句柄,因为这对我来说真的很好。但是,唉。

标签: python c cuda ctypes void-pointers


【解决方案1】:

问题出在这里:

pycu_alloc.restypes = [c_void_p]   

这没有任何作用。你想要的是:

pycu_alloc.restype = c_void_p

请参阅 ctypes 文档中的 Return types

如果没有这个,ctypes 假定您的函数返回一个 C int。在 32 位平台上,您可能会侥幸成功,因为您最终会构造一个 c_void_p,其值为 int... 但在 64 位平台上,该指针将以高位 32 结尾缺位。

因此,当您将其传递给 CUDA 时,它会识别出指针不在它所知道的任何范围内,并返回一个 cudaErrorInvalidValue (11)。

另外,如果你做对了,这行应该是不必要的:

c_da = c_void_p(da)

您正在调用一个函数,其argtypes 指定c_void_p,因此您可以将您从c_void_p 获得的int 传递给它 - 返回函数就好了。


你可以看到与普通的旧 mallocfree 相同的行为,除了你可能会在 free 处得到一个段错误而不是一个很好的错误:

malloc = libc.malloc
malloc.argtypes = [c_size_t]
malloc.restype = c_void_p # comment this line to crash on most 64-bit platforms

free = libc.free
free.argtypes = [c_void_p]
free.restype = None

a = malloc(1024)
free(a) # commenting this line and uncommenting the next two has no effect
#c_a = c_void_p(a)
#free(ca)

【讨论】:

  • @Ethan:请记住要小心具有数据描述符但仍为实例提供__dict__ 的类型。 ctypes 数据类型允许这样做,因为它们被设计为子类以支持其他状态和接口。不幸的是,很容易错误地创建像restypes 这样的新属性。如果您尝试将[c_void_p] 分配给正确的restype 属性,您至少会得到TypeError。 REPL,dirhelp 是你的朋友。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-14
  • 1970-01-01
  • 2016-07-20
  • 2018-01-12
  • 1970-01-01
  • 1970-01-01
  • 2012-04-06
相关资源
最近更新 更多