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

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


    Чуть больше года назад 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». Я ее еще не читал, но беглый просмотр показал, что выглядит она вполне интересно.
    • +22
    • 2,2k
    • 7
    Поделиться публикацией

    Похожие публикации

    Комментарии 7

      +1
      > Потокобезопасность — штука полезная, теперь нам не надо задумываться о том, что когда вызывать и как синхронизировать. Насколько оно актуально — хороший вопрос, пока используется одна карта, толку особо нет.

      Число потоков не зависит от числа видеокарт\процессоров и т.п. к тому же даже на одной видеокарте может быть несколько ядер и запуск нескольких процессов вполне возможен, так что фича нужная и полезная (имхо)
        –2
        Вы правы, много потоков может быть при любом количестве видеокарт (да и разницы сколько там ядер тоже нет), просто, имхо, наиболее популярный сценарий — поток на видеокарту, хотя я могу и ошибаться.
        0
        Начал читать «OpenCL Programming Guide» — довольно таки ясно все раскладывают по полочкам что да как в стандарте 1.1. Примеров из разных областей предостаточно.
          0
          Эх… вот написали бы они ее на годик раньше...:) Я тогда долго искал хорошую книжку, но пришлось читать мануал и программинг гайд от nvidia. А там не все всегда ясно.
          0
          «вопрос о том, есть ли аппаратное ускорение встроенных функций или нет для меня все еще загадка, надо будет как-нибудь проверить будет»
          Читая сайт www.cmsoft.com.br/ натыкался на утверждение (вроде даже с примером на котором оно проверялось) что у nativ функций есть аппаратное ускорение. Сам обычно их и стараюсь использовать…
          Но то, что ввели трёхмерные вектора это конечно приятно.
            0
            Спасибо за сайт, почитаю.
            А вы никогда не пробовали делать какой-нибудь простенький тест? Например посчитать длину вектора нативной функцией и вручную. У меня руки все никак не доходят до этого, да и без 3х компонентных векторов смысла не было. Просто интересно, нвидевская документация тоже говорит, что будет быстрее, но вот факты мне еще не попадались.
            0
            Global work-offset which enable kernels to operate on different portions of the NDRange — самое ожидаемое нововведение 1.1, по крайней мере для меня. Я сам очень удивился когда не обнаружил такой возможности в 1.0. А столкнулся я с этим при реализации метода Гаусса (собственно, то же самое справедливо почти для любого прямого метода решения СЛАУ). Идея в том, что на каждом шаге обрабатываемая часть матрицы становится всё меньше (на одну строку сверху и один столбец слева). Вот здесь как раз глобальный офсет и нужен.
            Порылся в спеках, обнаружил что оно уже есть в 1.1, и что у Nvidia вроде бы уже есть pre-release drivers. Недолго думая, запросил эти драйвера, но Nvidia захотела чтобы я что-то там доказал… Решил, что оно того не стоит (я думал что готовые драйвера выйдут как минимум на полгода раньше), в итоге ядра дополнились конструкциями вида:
            if(x < i || y < i) return; // где i — номер шага, а x,y — глобальные id

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

            Самое читаемое