Почему я не могу правильно скопировать данные в структуре в буфер openCL cl_mem?

Хорошо, я выделил это на очень специфическую проблему.

У меня сложилось впечатление, что вы можете передавать OpenCL данные любого типа в буфер массива; целые числа, символы, ваши собственные пользовательские структуры, если они были всего лишь данными и не содержали указателей на кучу объектов, которые GPU не сможет извлечь.

Теперь я попробовал это, и я думаю, что это работает для большого массива целых, но не для моего массива структур. В частности,

cl_mem log_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE, 
  num_elements * sizeof(int), NULL, NULL);

int* error_codes_in = (int*)malloc(num_elements * sizeof(int));

for (i = 0; i < num_elements; i++) {
  error_codes_in[i] = i;
}

error = clEnqueueWriteBuffer(command_queue, log_buffer, CL_TRUE,
  0, num_elements * sizeof(int), error_codes_in, 0, NULL, NULL);

это прекрасно работает, и я получаю массив чисел на GPU и могу успешно ими управлять, параллельно.

Тем не менее, когда я использую свою собственную структуру:

typedef struct {
  float position[2];
  float velocity[2];
  float radius;
  float resultant_force[2];
} ocl_element_2d_t;

(также определяется в ядре, как)

const char* kernel_string = 
  "typedef struct { float position[2]; float velocity[2]; float radius; float resultant_force[2]; } ocl_element_2d_t;"...

и я использую тот же / очень похожий код для записи в GPU-версию моего массива struct:

cl_mem gpu_buffer = clCreateBuffer(context, CL_MEM_READ_WRITE,
  num_elements * sizeof(ocl_element_2d_t), NULL, NULL);

error = clEnqueueWriteBuffer(command_queue, (cl_mem)gpu_buffer, CL_TRUE,
  0, num_elements * sizeof(ocl_element_2d_t), host_buffer, 0, NULL, NULL);

Я получаю пустые значения в графическом процессоре, а иногда и мусор (три или четыре значения в 350) для всех значений с плавающей точкой внутри структуры. Оба возвращаемых значения CL_SUCCESS,

Любые предложения относительно того, где я иду не так? Я думал только о том, что компилятор GPU создает структуру в памяти с различными пробелами, и поскольку метод copy игнорирует внутреннюю структуру элементов и просто копирует непрерывный блок RAM, вы в конечном итоге получаете несоответствия и возможные элементы, находящиеся вне фазы. Возможно ли, что моя ОС является 64-разрядной (OS X Lion) на i7 (четырехъядерном процессоре), а мой графический процессор работает на 32-разрядной версии, и в этом проблема? Это ATI Radeon HD 5750, который не имеет поддержки двойной точности и претендует на использование 128-битной шины (что может иметь или не иметь значение, я не знаю точно, что означает этот материал).

Есть ли правильный способ сделать это? Я собираюсь пройти весь FORTRAN и иметь 7 разных массивов, каждый со своим собственным аргументом ядра, для разных свойств в структуре?

2 ответа

Решение

Все благодарности @0A0D за подозрение в моих выборочных примерах кода. Проблема была в том, что я не смог правильно инициализировать структуры.

Я оправдываюсь просто тем, что я привык работать со структурными указателями, а не со структурами, и поэтому писать

ocl_element_2d_t element = host_buffer[i];
element.position[0] = 1.2;
element.position[1] = 5.7;

был стандартный способ добавить свойства к объекту. После быстрого ознакомления со структурами я наткнулся на очень простое руководство по C, http://www.asic-world.com/scripting/structs_c.html которое указывало, что

struct_instance = other_struct_instance;

выполняет глубокую копию, а не справочную копию.

Таким образом, когда я тестировал вывод из локальной переменной структуры, ожидаемое мной значение было там, но все же еще далеко от массива host_buffer,

Здесь, вероятно, есть два урока:

  1. Убедитесь, что вы публикуете весь соответствующий код, когда задаете вопрос Stackru, включая всю инициализацию, чтобы можно было рассмотреть все возможные проблемы.
  2. При использовании библиотеки, особенно такой сложной, как OpenCL, не думайте, что ее разработчики допустят глупые ошибки - они почти наверняка ваши собственные!

Я не уверен, как ваши компиляторы выравнивают вашу структуру 'float', но используя gcc вы можете попробовать:

#pragma pack(1)

чтобы выровнять его без пробелов.

Чтобы отменить эту упаковку используйте:

#pragma pack()

Также вы можете попытаться просто переставить участников, вот так:

typedef struct {
  float position[2];
  float velocity[2];
  float resultant_force[2];
  float radius;
} ocl_element_2d_t;
Другие вопросы по тегам