Как создать заблокированную страницу памяти из существующего массива в PyCUDA?
Справка PyCUDA объясняет, как создать пустой или обнуленный массив, но не как переместить (?) Существующий массив с пустыми массивами в память с блокировкой страницы. Нужно ли мне получить указатель на массив NumPy и передать его pycuda.driver.PagelockedHostAllocation
? И как бы я это сделал?
ОБНОВИТЬ
<- sniped ->
ОБНОВЛЕНИЕ 2
Спасибо, talonmies за помощь. Теперь перенос памяти заблокирован страницей, но программа завершается со следующей ошибкой:
PyCUDA WARNING: a clean-up operation failed (dead context maybe?)
cuMemFreeHost failed: invalid context
Это обновленный код:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
import ctypes
from pycuda import driver, compiler, gpuarray
from pycuda.tools import PageLockedMemoryPool
import pycuda.autoinit
memorypool = PageLockedMemoryPool()
indata = np.random.randn(5).astype(np.float32)
outdata = gpuarray.zeros(5, dtype=np.float32)
pinnedinput = memorypool.allocate(indata.shape,np.float32)
source = indata.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
dest = pinnedinput.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
sz = indata.size * ctypes.sizeof(ctypes.c_float)
ctypes.memmove(dest,source,sz)
kernel_code = """
__global__ void kernel(float *indata, float *outdata) {
int globalid = blockIdx.x * blockDim.x + threadIdx.x ;
outdata[globalid] = indata[globalid]+1.0f;
}
"""
mod = compiler.SourceModule(kernel_code)
kernel = mod.get_function("kernel")
kernel(
driver.In(pinnedinput), outdata,
grid = (5,1),
block = (1, 1, 1),
)
print indata
print outdata.get()
memorypool.free_held()
3 ответа
Вам нужно будет скопировать данные из вашего исходного массива в массив, содержащий блокировку страницы, возвращенную из Pycuda. Самый простой способ сделать это через ctypes
:
import numpy
import ctypes
x=numpy.array([1,2,3,4],dtype=numpy.double)
y=numpy.zeros_like(x)
source = x.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
dest = y.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
sz = x.size * ctypes.sizeof(ctypes.c_double)
ctypes.memmove(dest,source,sz)
print y
numpy.ctypes
Интерфейс может использоваться для получения указателя на память, используемую для хранения данных массивов, а затем ctypes.memmove
используется для копирования между двумя разными ndarrays. Применяются все обычные предостережения при работе с голыми указателями C, поэтому требуется некоторая осторожность, но она достаточно проста в использовании.
Блок памяти все еще активен. Вы можете явно освободить закрепленный массив:
print memorypool.active_blocks
pinnedinput.base.free()
print memorypool.active_blocks
memorypool.free_held()
Я делал это намного проще:
locked_ary = cuda.pagelocked_empty_like(ary, mem_flags=cuda.host_alloc_flags.DEVICEMAP)
locked_ary[:] = ary
Результат имеет право AlignedHostAllocation
база, а сроки совпадают с тем, что я получаю с помощью ctypes.memmove
,