Итак, я должен передать некоторые данные в ядро OpenCL с помощью PyOpenCL или некоторые обходные пути с использованием Python. Данные читаются на стороне ядра как структура, и я не могу изменить ядро, потому что оно работает нормально и является частью гораздо большего проекта, с которым должен работать мой код.
Ядро выглядит так:
typedef struct VglClStrEl{
float data[VGL_ARR_CLSTREL_SIZE];
int ndim;
int shape[VGL_ARR_SHAPE_SIZE];
int offset[VGL_ARR_SHAPE_SIZE];
int size;
} VglClStrEl;
typedef struct VglClShape{
int ndim;
int shape[VGL_ARR_SHAPE_SIZE];
int offset[VGL_ARR_SHAPE_SIZE];
int size;
} VglClShape;
__kernel void kernel(__global unsigned char* img_input,
__global unsigned char* img_output,
__constant VglClShape* img_shape,
__constant VglClStrEl* window)
{
// do what is needed
}
Итак, как вы можете видеть, структуры VglClShape и VglClStrEl имеют разные типы массивов и переменные static-bitize.
Обходной путь [1] поддерживает структуры только с массивами одного типа (или мне, к сожалению, не удалось найти способ сделать это с несколькими типами массивов).
Обходной путь [2] — это ссылка на документацию PyOpenCL для передачи данных Python в структуру ядра OpenCL. Этот подход вообще не поддерживает массивы.
Итак, как я могу передать данные Python, которые может прочитать ядро OpenCL? У меня уже есть все данные на стороне Python, и мне просто нужно знать, как передать их из Python в ядро.
Прежде чем спросить: я использую Python 3 и Я не могу изменить ядро.
И да, размеры массива статичны. Вы можете предположить что-то подобное:
VGL_ARR_CLSTREL_SIZE=256;
VGL_ARR_SHAPE_SIZE=20;
[1] Передача структуры с указателями на ядро OpenCL с помощью PyOpenCL
[2] https://documen.tician.de/pyopencl/howto.html#how-to-use-struct-types-with-pyopencl
Есть хакерский способ сделать это, который требует утомительного спора байтов. Предположительно, вы в порядке с развертыванием небольшого зондирующего ядра OpenCL? (PyOpenCL делает это под капотом для некоторых операций в любом случае)
Основная идея заключается в том, чтобы:
Следующее ядро делает работу:
__kernel void get_struct_sizes( __global uint *struct_sizes )
{
const uint global_id = get_global_id(0u)+get_global_id(1u)*get_global_size(0u);
VglClStrEl vgclstrel;
VglClShape vgclshape;
uint offset;
printf("In GPU (probing):\n Kernel instance = %d\n", global_id);
if (global_id==0) {
offset = (uint)&(vgclstrel.data);
struct_sizes[0] = (uint)sizeof(vgclstrel);
struct_sizes[1] = (uint)&(vgclstrel.ndim)-offset;
struct_sizes[2] = (uint)&(vgclstrel.shape)-offset;
struct_sizes[3] = (uint)&(vgclstrel.offset)-offset;
struct_sizes[4] = (uint)&(vgclstrel.size)-offset;
offset = (uint)&(vgclshape.ndim);
struct_sizes[5] = (uint)sizeof(vgclshape);
struct_sizes[6] = (uint)&(vgclshape.shape)-offset;
struct_sizes[7] = (uint)&(vgclshape.offset)-offset;
struct_sizes[8] = (uint)&(vgclshape.size)-offset;
}
return;
}
Запустите это ядро и вернитесь struct_sizes
в vgclshape_sizes
создайте этот массив:
img_shape = np.zeros((vgclshape_sizes[0]), dtype=np.uint8)
и скопируйте в него то, что вам нужно:
def copy_into_byte_array(value, byte_array, offset):
for i,b in enumerate(np.ndarray.tobytes(value)):
byte_array[i+offset] = b
copy_into_byte_array(ndim, img_shape, 0)
copy_into_byte_array(shape, img_shape, vgclshape_sizes[1])
copy_into_byte_array(offset, img_shape, vgclshape_sizes[2])
copy_into_byte_array(size, img_shape, vgclshape_sizes[3])
Я пропустил несколько шагов здесь; заполнив их, вы обнаружите, что этот подход работает. Я смог передать демонстрационную структуру фиктивной копии вашего нерушимого ядра.
Мне было бы интересно услышать, есть ли более изящные способы сделать любой / все эти шаги. Я также ожидаю, что будут проблемы с порядком байтов и т. Д., Которые в противном случае были бы прозрачными. Если повезет, вы можете обойти их.
Других решений пока нет …