我正在尝试学习pycuda,我有一些问题,我正在努力理解。 我认为我的主要问题是如何在pycuda和cuda文件中的函数之间进行通信。
所以,如果我有一个C ++文件(cuda文件)并且在那里我有一些函数,我想在其中一个中实现pycuda。例如,假设我想要包含一些数组的函数'compute'和对它们进行计算。我的方法是什么?
1)在python中初始化数组,为GPU分配内存并将数据传输到GPU。
2)从pycuda调用mod = SourceModule(“” global void ......“”“)。
现在,我想问:我将如何处理这个模块?我将把所有'计算'功能放入其中?因为,如果只在'全局'中做一些计算,我不知道如何沟通然后pycuda和c ++函数之间。如何将我的结果传递回c ++文件(cuda文件)。
3)在cuda中我们将线程数量设置为'blockDIm',将块数设置为'gridDim'。在pycuda中?我们有块大小,块(4,4,1)意味着16个线程??网格大小,大小(16,16)表示256个块?
4)我试图在pycuda做一个来自'cuda by a book book'的例子,它增加了向量。代码如下:
import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import SourceModule
import scipy as sc
N=50*1024
a=sc.arange(0,N).astype(sc.float32)
a_gpu = cuda.mem_alloc(a.nbytes) #allocate memory on GPU
cuda.memcpy_htod(a_gpu, a) #transfer data to the GPU
b=sc.array([i**2 for i in range(0,N)]).astype(sc.float32)
b_gpu = cuda.mem_alloc(b.nbytes)#allocate memory on GPU
cuda.memcpy_htod(b_gpu, b) #transfer data to the GPU
c=sc.zeros(N).astype(sc.float32)
c_gpu = cuda.mem_alloc(c.nbytes)#allocate memory on GPU
mod =SourceModule("""
__global__ void add(int*a,int *b,int *c){
int tid=threadIdx.x + blockIdx.x*gridDim.x;
while (tid<N){
c[tid]=a[tid]+b[tid];
tid+=blockDim.x*gridDim.x;
}
}
""")
#call the function(kernel)
func = mod.get_function("add")
func(a_gpu,b_gpu,c_gpu, block=(16,16,1),grid=(16,16))
#transfer data back to CPU
cuda.memcpy_dtoh(c, c_gpu)
但它给了我一个错误:“标识符”N“未定义”
谢谢!
答案 0 :(得分:2)
我使用pycuda的方式以及我认为它的使用方式是作为python和cuda之间的桥接接口。它不是python-&gt; c ++接口工具。为此,您必须查看SWIG之类的内容。我不会在c ++代码中使用pycuda与GPU接口,而是使用pycuda进行原型设计或设计我的应用程序,然后将其移动到仅使用c ++。
考虑到这一点,我会尝试解决你的问题
1)使用Pycuda,您还可以使用gpuarray模块,它将为您分配和传输步骤,因此您可以实例化它们并在GPU中使用它们:
import pycuda.gpuarray as gpuarray
a = gpuarray.arange(400, dtype=numpy.float32)
b = gpuarray.arange(400, dtype=numpy.float32)
#call Cuda function pass 'a' and 'b'
resulta = a.get()
resultb = b.get()
2)同样,pycuda不是c ++接口。如果你需要结果来自cuda-&gt; python-&gt; c ++,我认为你不需要在中间使用python。
3)是块(4,4,1)是16个线程,网格(16,16)是256个块。
编辑:
回答你的一些评论:
是块(4,1,1)是一维的,块(4,4,1)是2D。
我修复了你的代码,你只需要将N传递给CUDA内核。
import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import SourceModule
import scipy as sc
N=50*1024
a=sc.arange(0,N).astype(sc.float32)
a_gpu = cuda.mem_alloc(a.nbytes) #allocate memory on GPU
cuda.memcpy_htod(a_gpu, a) #transfer data to the GPU
b=sc.array([i**2 for i in range(0,N)]).astype(sc.float32)
b_gpu = cuda.mem_alloc(b.nbytes)#allocate memory on GPU
cuda.memcpy_htod(b_gpu, b) #transfer data to the GPU
c=sc.zeros(N).astype(sc.float32)
c_gpu = cuda.mem_alloc(c.nbytes)#allocate memory on GPU
mod = SourceModule("""
__global__ void add(int*a,int *b,int *c, int N){
int tid=threadIdx.x + blockIdx.x*gridDim.x;
while (tid<N){
c[tid]=a[tid]+b[tid];
tid+=blockDim.x*gridDim.x;
}
}
""")
#call the function(kernel)
func = mod.get_function("add")
func(a_gpu,b_gpu,c_gpu, sc.int32(N), block=(16,16,1),grid=(16,16))
#transfer data back to CPU
cuda.memcpy_dtoh(c, c_gpu)
print c
另一种方法是在SourceModule上使用字符串替换:
mod = SourceModule("""
__global__ void add(int*a,int *b,int *c){
const int N = %d;
int tid=threadIdx.x + blockIdx.x*gridDim.x;
while (tid<N){
c[tid]=a[tid]+b[tid];
tid+=blockDim.x*gridDim.x;
}
}
""" % (N))
最后一点需要注意的是,当您使用Pycuda时,它通常用作连接CUDA的所有不同部分的粘合剂。它可以帮助你编译分配内存,运行你的内核等...只要你这样使用它就可以了。