pycuda, cuda - некоторые вопросы и простой код, который дает мне ошибку "идентификатор" N "не определен" - PullRequest
2 голосов
/ 01 декабря 2011

Я пытаюсь выучить пикуду, и у меня есть несколько вопросов, которые я пытаюсь понять.Я думаю, что мой главный вопрос - как связаться между pycuda и функцией внутри файла cuda. ​​

Итак, если у меня есть файл C ++ (файл cuda) и там у меня есть некоторые функции, и я хочу реализовать pycudaв одном из них. Например, допустим, я хочу функцию 'вычислить', которая содержит несколько массивов, и выполнять вычисления на них. Каков будет мой подход?

1) Инициализировать массивы в python, выделить память дляGPU и передача данных в GPU.

2) Вызовите mod = SourceModule ("" " global void ......" "") из pycuda. ​​

Теперь я хочу спросить: как я буду обрабатывать этот модуль? Я добавлю в него все функции 'вычисления'? Потому что, если я делаю только некоторые вычисления в 'глобальном', я не знаю, как связываться между pycudaи функции c ++. Как я передам свои результаты обратно в файл c ++ (файл cuda).

3) В cuda у нас есть количество потоков как «blockDIm» и количество блоков как «gridDim».pycuda? У нас есть размер блока, блок (4,4,1), что означает 16 потоковs? И размер сетки, размер (16,16) означает 256 блоков?

4) Я пытался сделать в Pycuda пример из «cuda by example 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 "не определен"

Спасибо!

1 Ответ

2 голосов
/ 01 декабря 2011

То, как я использую pycuda, и то, как я думаю, что оно предназначено для использования, является мостовым интерфейсом между python и cuda.Это не инструмент интерфейса Python-> C ++.Для этого вам нужно посмотреть на что-то вроде SWIG .Я бы не использовал pycuda в коде c ++ для взаимодействия с графическим процессором, вместо этого я бы прототипировал или проектировал свое приложение, используя pycuda, а позже перешел бы на использование только c ++.

Имея это в виду, я постараюсь ответить на ваши вопросы

1) С Pycuda вы также можете использовать модуль gpuarray, который будет выполнять шаги выделения и передачи для вас, так что вы можете простосоздайте их и используйте в графическом процессоре:

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-> python-> c ++, я не думаю,вам нужен питон посередине.

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.Это поможет вам скомпилировать выделенную память, запустить ядро ​​и т. Д. До тех пор, пока вы используете это, у вас все будет хорошо.

...