2015-09-17 4 views
1

Я использую pycuda для создания релятивистского raytracer. В принципе, для каждого «пикселя» в большом двумерном массиве мы должны решить систему из 6 ОДУ с помощью Рунге Кутты. Поскольку каждая интеграция не зависит от остальных, это должно быть очень просто. Другие люди достигают этого, используя C/C++ CUDA с отличными результатами (см. this project).Pycuda: Лучший способ вызвать Kernel несколько раз

Проблема возникает в том, что я не знаю, как это лучший способ сделать это. Я пишу Ядро, которое выполняет некоторые шаги Runge Kutta, а затем возвращает результаты в CPU. Это ядро ​​называется много раз, чтобы интегрировать весь лучи. Проблема по какой-то причине очень медленно. Конечно, я знаю, что передача памяти на самом деле является узким местом в CUDA, но поскольку это очень медленно, я начинаю думать, что я делаю что-то неправильно.

Было бы здорово, если бы вы порекомендовали мне лучшие методы программирования для этого случая. (Использование pycuda). Некоторые вещи, которые я брожу:

  1. Нужно ли мне создать новый контекст при достижении вызова ядра?
  2. Существует способ не должен передачи памяти от GPU к CPU, то есть, начиная с ядром, делая паузу, чтобы получить его некоторой информации, и ее пересчета повторить.
  3. Каждая итерация RK4 занимает примерно полсекунды, что является безумным (также по сравнению с кодом CUDA в ссылке, которая выполняет некоторую аналогичную операцию). И я думаю, что это связано с чем-то не так с тем, как я использую pycuda, поэтому, если вы можете объяснить лучший способ сделать такую ​​операцию наилучшим образом, это может быть здорово !.

Чтобы уточнить: причина, по которой я должен приостановить/перезапустить ядро, связана с сторожевым псом. Ядро более 10 секунд было убито сторожевым псом.

Спасибо заранее!

ответ

2

Ваш главный вопрос кажется слишком общим, и трудно дать конкретный совет, не видя кода. Я постараюсь ответить на ваши подзапросы (не фактический ответ, но он немного длинный для комментария)

Нужно ли мне создать новый контекст при достижении вызова ядра?

No.

Существует способ, чтобы не передавать память от GPU к CPU, то есть, начиная с ядра, задержавшись его, чтобы получить какую-то информацию, и ее пересчета повторить.

Зависит от того, что вы подразумеваете под «получить информацию». Если это означает делать с ним вещи на процессоре, то, конечно же, вы должны перенести его. Если вы хотите использовать в другом вызове ядра, вам не нужно его передавать.

Каждая итерация RK4 занимает примерно полсекунды, что является безумным (также по сравнению с кодом CUDA в ссылке, которая выполняет некоторую аналогичную операцию).

Это действительно зависит от уравнения, количества потоков и используемой вами видеокарты. Я могу представить себе ситуацию, когда один шаг в РК затянется так долго.

И я думаю, что это связано с чем-то не так с тем, как я использую pycuda, поэтому, если вы можете объяснить лучший способ сделать такую ​​операцию наилучшим образом, это может быть здорово !.

Невозможно сказать точно без кода. Попробуйте создать какой-то минимальный демонстрационный пример или, по крайней мере, разместите ссылку на runnable (даже если это довольно длинный) фрагмент кода, который иллюстрирует вашу проблему. Что касается PyCUDA, это очень тонкая оболочка над CUDA, и все методы программирования, которые применяются к последним, также относятся к первому.

-1

Я мог бы помочь вам с обработкой памяти, то есть не нужно копировать с CPU на GPU во время ваших итераций. Я разрабатываю систему во времени с использованием таймера эйлеров, а способ хранения всех моих данных на моем графическом процессоре приведен ниже. Однако проблема заключается в том, что после запуска первого ядра процессор продолжает выполнять строки после него. То есть граничное ядро ​​запускается до шага эволюции времени.

Что мне нужно - это способ синхронизации вещей. Я попытался сделать это с помощью strm.synchronize() (см. Мой код), но он не всегда работает. Если у вас есть идеи по этому поводу, я бы очень признателен за ваш вклад! Благодаря!

def curveShorten(dist,timestep,maxit): 
""" 
iterates the function image on a 2d grid through an euler anisotropic 
diffusion operator with timestep=timestep maxit number of times 
""" 
image = 1*dist 
forme = image.shape 
if(np.size(forme)>2): 
    sys.exit('Only works on gray images') 

aSize = forme[0]*forme[1] 
xdim = np.int32(forme[0]) 
ydim = np.int32(forme[1]) 


image[0,:]  = image[1,:] 
image[xdim-1,:] = image[xdim-2,:] 
image[:,ydim-1] = image[:,ydim-2] 
image[:,0]  = image[:,1] 

#np arrays i need to store things on the CPU, image is the initial 
#condition and final is the final state 
image = image.reshape(aSize,order= 'C').astype(np.float32) 
final = np.zeros(aSize).astype(np.float32) 

#allocating memory to GPUs 
image_gpu = drv.mem_alloc(image.nbytes) 
final_gpu = drv.mem_alloc(final.nbytes) 

#sending data to each memory location 
drv.memcpy_htod(image_gpu,image) #host to device copying 
drv.memcpy_htod(final_gpu,final) 

#block size: B := dim1*dim2*dim3=1024 
#gird size : dim1*dimr2*dim3 = ceiling(aSize/B) 
blockX  = int(1024) 
multiplier = aSize/float(1024) 
if(aSize/float(1024) > int(aSize/float(1024))): 
    gridX = int(multiplier + 1) 
else: 
    gridX = int(multiplier) 
strm1 = drv.Stream(1) 
ev1 = drv.Event() 
strm2 = drv.Stream() 
for k in range(0,maxit): 

    Kern_diffIteration(image_gpu,final_gpu,ydim, xdim, np.float32(timestep), block=(blockX,1,1), grid=(gridX,1,1),stream=strm1) 
    strm1.synchronize() 

    if(strm1.is_done()==1): 
    Kern_boundaryX0(final_gpu,ydim,xdim,block=(blockX,1,1), grid=(gridX,1,1)) 
    Kern_boundaryX1(final_gpu,ydim,xdim,block=(blockX,1,1), grid=(gridX,1,1))#,stream=strm1) 
    Kern_boundaryY0(final_gpu,ydim,xdim,block=(blockX,1,1), grid=(gridX,1,1))#,stream=strm2) 
    Kern_boundaryY1(final_gpu,ydim,xdim,block=(blockX,1,1), grid=(gridX,1,1))#,stream=strm1) 

    if(strm1.is_done()==1): 
     drv.memcpy_dtod(image_gpu, final_gpu, final.nbytes) 
    #Kern_copy(image_gpu,final_gpu,ydim,xdim,block=(blockX,1,1), grid=(gridX,1,1),stream=strm1) 



drv.memcpy_dtoh(final,final_gpu) #device to host copying 
#final_gpu.free() 
#image_gpu.free() 


return final.reshape(forme,order='C') 
+1

Это не ответ на исходный вопрос. Просьба рассмотреть возможность публикации этого вопроса как * нового * –

 Смежные вопросы

  • Нет связанных вопросов^_^