Pull to refresh

OpenCL: мы дождались — версия 1.1 от nVidia, а что нового?

Reading time 4 min
Views 2.7K

Немного истории или обещанного три года ждут


Чуть больше года назад Khronos Group представила новую версию OpenCL 1.1 и nVidia сразу похвасталась тем, что у нее уже готов пре-релиз драйвер с поддержкой нового стандарта. Все бы хорошо, да только пре-релиз — это не рабочий инструмент (тут и в официальных драйверах багов хватает, а в тестовой версии уж подавно), поэтому разработчики честно ждали релиза новой версии. Вышла CUDA 4, а OpenCL'а все не было и не было. Причем из новой версии драйверов исключили даже пре-релиз версию OpenCL, т.е. приходилось выбирать между старый драйвер с CUDA 3 + OpenCL 1.1 или новый драйвер с CUDA 4 + OpenCL 1.0. Но сегодня свершилось! Разработчикам пришло письмо о том, что финальная версия уже доступна в официальных драйверах 280.13, правда пока что бета версии, но это не надолго.

Итак, я решил вспомнить о том, что же там такого нового и хорошего в новой версии, поделиться комментариями о том зачем та или иная функция может понадобится и есть ли подводные камни о которых надо знать.


Что нового в OpenCL 1.1


Пройдемся по списку от Khronos Group, а если я вспомню что-то, чего там нет, то добавлю.

Host-thread safety

Потокобезопасность — штука полезная, теперь нам не надо задумываться о том, что когда вызывать и как синхронизировать. Насколько оно актуально — хороший вопрос, пока используется одна карта, толку особо нет. Когда же карт много и на каждую свой поток, тогда да, жизнь становится проще.
Есть тут правда одно исключение, про которое обычно не пишут: функция clSetKernelArg не является потокобезопасной, если она вызывается для одно и того же объекта кернела (хотя для разных вызывайте на здоровье). Сделали так то ли ради скорости (не вижу особого смысла), то ли из-за того, что смысла в использовании одного объекта разными потоками все равно нет, но факт есть факт, так что надо быть осторожным.

Sub-buffer object

По сути, теперь можно разбивать буфер на несколько кусков и отправлять нужный кусок на нужное устройство. Опять же полезно для случая нескольких видеокарт и улучшения переносимости. Да и целостность данных сохраняется, когда не надо делать отдельный буфер для каждой карточки. В целом, можно было бы и обойтись, но пригодится.
Маленький нюанс (совершенно логичный): нельзя одновременно писать в подбуфер и читать из пересекающегося подбуфера или основного буфера, в этом случае результат не определен.

User events

Появилась команды clCreateUserEvent и clSetUserEventStatus, которые позволяет пользователю создавать собственные события. Раньше можно было привязывать все только к тем событиям, которые возникали после выполнения команд OpenCL. Опять же можно обходиться и без этого (просто добавляя в очередь новые команды по факту какого-то события), но стало удобней.

Event callbacks

Появилась функция clSetEventCallback, которая регистрирует пользовательские функции, вызываемые при соответствующих изменениях статуса события. Добавлять можно несколько пользовательских функций, но порядок их вызова не определен. Вот это дополнение мне уже нравится, раньше приходилось проверять через каждые сколько-то мс состояние события, теперь же все удобно, а главное — экономятся те самые несколько секунд и упрощается весь процесс. Чем-то мне это ActionScript напоминать начинает:)

Кстати, еще одной полезной функцией может быть clSetMemObjectDestructorCallback, которая позволяет добавить пользовательскую функцию, вызываемую при удалении cl_mem объекта.

3-component vector

Раньше были вектора с размером 2, 4, 8, 16, только вот живем мы все в 3х-мерном пространстве и трехмерные вектора штука популярная. А если использовать 4х-мерные, то уже теряешь целый регистр, что является большим расточительством. Можно конечно делать свои, но они не будут обрабатываться встроенными геометрическими функциями OpenCL. Оно конечно не страшно, можно свое написать (вопрос о том, есть ли аппаратное ускорение встроенных функций или нет для меня все еще загадка, надо будет как-нибудь проверить будет), но то, что с нативной поддержкой будет красивее (красивее в моем случае = проще поддерживать) — это факт.

Global work-offset which enable kernels to operate on different portions of the NDRange

Честно говоря, я всегда думал, что это было и раньше. Да и в официальной документации к обоим версиям оно есть. Если кто знает, что тут изменилось, отпишитесь плиз.

Read, write and copy a 1D, 2D or 3D rectangular region of a buffer object

Появились функции clEnqueueReadBufferRect, clEnqueueWriteBufferRect и clEnqueueCopyBufferRect, которые позволяют скопировать прямоугольную область буфера. Т.е. если вы храните в буфере матрицу или изображение (та же матрица по сути) построчно, а надо получить лишь часть ее, больше не надо читать/копировать/писать весь буфер или выдавать по команде на каждую строку, а можно просто указать параметры матрицы и OpenCL сделает все сам. Лично мне ни разу не приходилось таким заниматься, но должно быть полезно для больших матриц.

Mirrored repeat addressing

Если вы храните изображение как текстуру, то можно использовать CLK_ADDRESS_MIRRORED_REPEAT чтобы при выходе за границу текстуры выдавался результат, как будто там ее отражение. Причем это работает сколько угодно раз, отражения как-бы чередуются.

Всякие разные дополнения и улучшения

CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE аргумент для функции clGetKernelWorkGroupInfo, должен нам подсказать множитель для размера группы, который подходит для данного устройства. Если я правильно понимаю, то эта штука вернет нам размер варпа (чтобы размер группы всегда включал в себя несколько целых варпов) и предназначена для автотюнинга приложения на разных платформах. Но я ее еще не пробовал, так что могу ошибаться.

CL_CONTEXT_NUM_DEVICES аргумент для функции clGetContextInfo нам расскажет о том, сколько устройств в контексте.

Одна полезная штука, чтобы узнать в программе какая версия OpenCL используется, есть макросы CL_VERSION_1_0 и CL_VERSION_1_1

Еще внесли в стандарт такие расширения как:
cl_khr_byte_addressable_store
cl_khr_global_int32_base_atomics,
cl_khr_global_int32_extended_atomics,
cl_khr_local_int32_base_atomics,
cl_khr_local_int32_extended_atomics
.
А префикс для встроенных атомик операций поменяли с atom_ на atomic_.

Появилось 2 новых расширения:
cl_khr_gl_event и cl_khr_d3d10_sharing.

Также появилось несколько новых команд:
get_global_offset,
minmag,
maxmag,
async_work_group_strided_copy,
vec_step,
shuffle,
shuffle2.


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

PS: Снова у меня в посте нет ни строчки кода, обещаюсь попозже это исправить, много есть идей о примерах и тестах, но пока будем жить без него:)

PS2: В прошлом моем посте OpenCL: универсальность и высокая производительность или не так все просто? спрашивали про книгу об OpenCL и тогда мне нечего было ответить. Так вот, я сегодня обнаружил, что буквально неделю назад вышла книга «OpenCL Programming Guide». Я ее еще не читал, но беглый просмотр показал, что выглядит она вполне интересно.
Tags:
Hubs:
+22
Comments 7
Comments Comments 7

Articles