Выравнивание структуры с помощью PyOpenCL

update: int4 в моем ядре был неправильным.

Я использую pyopencl, но я не могу заставить структуру выравнивания работать правильно. В приведенном ниже коде, который дважды вызывает kernel, значение b возвращается правильно (как 1), но значение c имеет некоторое «случайное» значение.

Другими словами: я пытаюсь прочитать два члена структуры. Я могу прочитать первый, но не второй. Зачем?

Такая же проблема возникает, если я использую numpy структурированные массивы или пакет со структурой. И настройки _-attribute__ в комментариях тоже не помогают.

Я подозреваю, что делаю что-то глупое в другом месте кода, но не вижу его. Любая помощь оценивается.

 import struct as s import pyopencl as cl import numpy as n ctx = cl.create_some_context() queue = cl.CommandQueue(ctx) for use_struct in (True, False): if use_struct: a = s.pack('=ii',1,2) print(a, len(a)) a_dev = cl.Buffer(ctx, cl.mem_flags.WRITE_ONLY, len(a)) else: # a = n.array([(1,2)], dtype=n.dtype('2i4', align=True)) a = n.array([(1,2)], dtype=n.dtype('2i4')) print(a, a.itemsize, a.nbytes) a_dev = cl.Buffer(ctx, cl.mem_flags.WRITE_ONLY, a.nbytes) b = n.array([0], dtype='i4') print(b, b.itemsize, b.nbytes) b_dev = cl.Buffer(ctx, cl.mem_flags.READ_ONLY, b.nbytes) c = n.array([0], dtype='i4') print(c, c.itemsize, c.nbytes) c_dev = cl.Buffer(ctx, cl.mem_flags.READ_ONLY, c.nbytes) prg = cl.Program(ctx, """ typedef struct s { int4 f0; int4 f1 __attribute__ ((packed)); // int4 f1 __attribute__ ((aligned (4))); // int4 f1; } s; __kernel void test(__global const s *a, __global int4 *b, __global int4 *c) { *b = a->f0; *c = a->f1; } """).build() cl.enqueue_copy(queue, a_dev, a) event = prg.test(queue, (1,), None, a_dev, b_dev, c_dev) event.wait() cl.enqueue_copy(queue, b, b_dev) print(b) cl.enqueue_copy(queue, c, c_dev) print(c) 

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

 # first using struct /home/andrew/projects/personal/kultrung/env/bin/python3.2 /home/andrew/projects/personal/kultrung/src/kultrung/test6.py b'\x01\x00\x00\x00\x02\x00\x00\x00' 8 # the struct packed values [0] 4 4 # output buffer 1 [0] 4 4 # output buffer 2 /home/andrew/projects/personal/kultrung/env/lib/python3.2/site-packages/pyopencl/cache.py:343: UserWarning: Build succeeded, but resulted in non-empty logs: Build on  succeeded, but said: Build started Kernel  was successfully vectorized Done. warn("Build succeeded, but resulted in non-empty logs:\n"+message) [1] # the first value (correct) [240] # the second value (wrong) # next using numpy [[1 2]] 4 8 # the numpy struct [0] 4 4 # output buffer [0] 4 4 # output buffer /home/andrew/projects/personal/kultrung/env/lib/python3.2/site-packages/pyopencl/__init__.py:174: UserWarning: Build succeeded, but resulted in non-empty logs: Build on  succeeded, but said: Build started Kernel  was successfully vectorized Done. warn("Build succeeded, but resulted in non-empty logs:\n"+message) [1] # first value (ok) [67447488] # second value (wrong) Process finished with exit code 0 

В программе OpenCL попробуйте упакованный атрибут самой структуры, а не один из членов:

 typedef struct s { int4 f0; int4 f1; } __attribute__((packed)) s; 

Возможно, потому, что у вас был только packed атрибут на одном члене структуры, возможно, он не упаковывал всю структуру.

хорошо, я не знаю, откуда я получил int4 – я думаю, это должно быть расширение intel. переход на AMD с int поскольку тип ядра работает так, как ожидалось. я напишу больше на http://acooke.org/cute/Somesimple0.html, как только я убрал вещи.