Представлен OpenCL 3.0: без прошлого нет будущего
Khronos Group представила предварительные спецификации стандарта вычислений общего назначения с использованием графических и иных процессоров - OpenCL 3.0. Консорциум отметил, что новая версия стандарта призвана обеспечить новые запрашиваемые разработчиками аппаратные функции, а также повысить гибкость развертывания в целевых средах. Задачи во многом противоположные, так что без компромиссов не обойтись.
Последние 15 лет можно смело назвать эпохой роста вычислений общего назначения на ГП. Сегодня прогресс мощности ЦП сильно замедлился, а высокопараллельные расчеты становятся все более общим явлением. Самые мощные в мире суперкомпьютеры теперь обязательно включают в себя ГП. В это время развивался и стандарт OpenCL - открытая среда программирования ГП и других ускорителей вычислений. Изначально созданная Apple и получившая широкое признание в отрасли, OpenCL была первой (и до сих пор наиболее последовательной) попыткой создания общего открытого API для параллельного программирования. OpenCL был адаптирован для всего: от энергоэффективных встраиваемых процессоров и DSP до графических ускорителей, потребляющих полкиловатта.
Сегодня OpenCL не только поддерживается на широком спектре оборудования, но и невероятно актуален даже для текущих событий: это API-интерфейс, используемый в проекте Folding@Home, самом мощном вычислительном кластере в мире, который интенсивно применяется для исследования вариантов борьбы с COVID-19. В то же время эволюция рынка параллельных вычислений не всегда шла в соответствии с планами для Khronos и рабочей группы OpenCL. На ПК стандарт все еще находится в подвешенном состоянии. Интерес NVIDIA сдерживается продвижением собственного весьма успешного API CUDA, драйверы AMD OpenCL оставляют желать лучшего, Apple отказывается от OpenCL и переходит на собственный API Metal. Единственным поставщиком, которого, кажется, всерьез интересует OpenCL, выступает Intel. На мобильных устройствах OpenCL тоже никогда не был широко распространен, несмотря на поддержку большинством мобильных ГП и другими блоками параллельной обработки данных.
Поэтому Khronos решила сделать в некоторой степени большой шаг назад и перезапустить экосистему. OpenCL 3.0, последняя версия вычислительного API, делает выводы из прошлого и по сути превращает основной API в форк OpenCL 1.2. В результате все, что разработано в рамках OpenCL 2.x, теперь стало необязательным: поставщики могут (и, как правило, будут) поддерживать эти функции, но оно больше не требуются для соответствия основной спецификации. Вместо того чтобы поддерживать каждую функцию OpenCL, независимо от ее полезности или бесполезности для конкретной платформы теперь поставщики будут сами решать, какие продвинутые функции они хотели бы поддерживать помимо основных спецификаций, основанных на OpenCL 1.2.
Здесь нужно понять некоторую специфику. Дело в том, что Khronos не имеет собственной реальной власти и не может навязать технологические изменения, являясь отраслевым консорциумом, в который входит множество компаний. Проблема совместного подхода заключается в том, что он требует определенной степени согласия между основными участниками. Если не может быть достигнуто соглашение о будущем, проект не может двигаться вперед. А если никто не доволен результатом, продукт может не получить достаточно широкой поддержки и умереть в зародыше. Нечто подобное произошло с OpenCL 2.2, который был выпущен еще в 2017 году. Основным новшеством стала поддержка OpenCL C++ в качестве языка ядра - более современного и объектно-ориентированного, чем использовавшийся ранее C. Однако три года спустя никто не принялся активно продвигать OpenCL 2.2: ни NVIDIA, ни AMD, ни Intel, ни, конечно, ни один производитель однокристальных систем. В результате это вредит стандарту.
Что делать, если OpenCL 2.x в значительной степени игнорируется? Khronos и рабочая группа OpenCL нашли ответ, решив вернуться к тому, что хорошо работало, и это был OpenCL 1.2, представленный впервые в 2011 году и ставший последней версией OpenCL 1.x. По современным стандартам API очень прост: он основан на чистом C и не поддерживает такие вещи, как общая виртуальная память или язык промежуточного представления SPIR-V. Но в то же время это последняя версия API, не включающая в себя массу второстепенных и бесполезных для многих участников рынка возможностей. Это чистый, довольно низкоуровневый API для параллельных вычислений во всем спектре: от мобильных решений до самых мощных видеокарт.
В конечном итоге рабочая группа OpenCL смогла договориться о том, что OpenCL 1.2 должен стать базовой спецификацией OpenCL 3.0 - все остальное, несмотря на полезность для определенных задач, становится необязательным. Ранее жесткая, монолитная природа стандарта одновременно препятствовала его развитию. Если поставщика удовлетворял OpenCL 1.2, но при этом ему хотелось реализовать пару дополнительных функций из OpenCL 2.1, то приходилось реализовать всю базовую спецификацию 2.1. В OpenCL 1.x / 2.x не было механизма частичного соответствия - только все или ничего, и ряд компаний выбрали второе.
Теперь OpenCL 3.0 специально структурирован так, чтобы поставщики могли использовать только те части, которые им нужны, не пытаясь поддерживать все остальное. Теперь ядром является OpenCL 1.2 с поддержкой запросов дополнительных функций, а также некоторыми дополнениями, призванными обеспечить совместимость. Все функции OpenCL 2.x, а также новые функции OpenCL 3.0 являются необязательными, позволяя поставщикам платформ самим решать, какие именно дополнительные возможности им нужны, и нужны ли вообще.
Например, производитель однокристальных систем для смартфонов может обеспечить OpenCL 1.2, и затем использовать несколько новых функций вроде асинхронных расширений DMA или разделяемой виртуальной памяти. В то же время крупный производитель видеокарт может поддержать бо? льшую часть функций OpenCL 2.x, но исключить поддержку разделяемой виртуальной памяти, что малополезно для дискретного ускорителя. В конечном счете OpenCL 3.0 дает поставщикам платформ возможность выбирать те функции, которые необходимы именно им, по сути, приспосабливая OpenCL к конкретным задачам.
Это очень похоже на подход Khronos к Vulkan, который оказался гораздо более успешным API в последние годы. Предоставление поставщикам некоторой гибкости в реализации функций API позволило Vulkan распространиться как на мобильных устройствах, так и на настольных ПК. Подобный успех хотела бы повторить и рабочая группа OpenCL.
В конечном счете, как считает Khronos, последние годы развития OpenCL показали, что сложно сделать стандарт угодным сразу всем, сохранив его абсолютную монолитность. У производителей SoC нужды одни, у ЦП со встроенной графикой - другие, у дискретных видеокарт - третьи. А ведь есть еще такие вещи, как FPGA и другие более экзотические варианты использования OpenCL. Таким образом, необходимо уйти от монолитности ради высокой адаптируемости к самому широкому спектру устройств и сред.
Несмотря на значительные изменения в философии разработки, OpenCL 3.0 создан так, чтобы оставаться обратно совместимым и логичным. Для разработчиков и пользователей благодаря ядру OpenCL 1.2 приложения 1.2 будут работать без изменений на любом устройстве OpenCL 3.0. В то же время приложения для OpenCL 2.x тоже будут работать без изменений на устройствах с OpenCL 3.0, если эти устройства поддерживают соответствующие функции 2.x. То есть на ПК уже созданное с применением OpenCL 2.1 ПО будет продолжать работать, а, например, на смартфонах - нет. Драйверы OpenCL 1.2 и 2.x действительно нуждаются в некоторых изменениях для соответствия требованиям 3.x, но в основном это касается поддержки запросов новых функций OpenCL. Таким образом, производители смогут выпустить драйверы 3.0 довольно быстро.
В дальнейшем разработчикам приложений предстоит правильно использовать функциональные запросы. Поскольку возможности OpenCL 2.x теперь необязательны, всем приложениям, задействующим дополнительные возможности 2.x/3.0, настоятельно рекомендуется использовать запросы функций, чтобы убедиться в наличии их аппаратной поддержки. Поэтому разработчикам приложений OpenCL 2.x рекомендуется обновить свое ПО для выполнения запросов функциональности.
OpenCL 3.0, помимо взгляда назад, делает и шаги вперед. Главными среди них являются асинхронные расширения DMA, которые должны стать наиболее интересны тем поставщикам платформ, которые до сих пор придерживают OpenCL 1.2. Эта функция позволяет выполнять транзакции DMA одновременно с вычислительными ядрами, в отличие от синхронных операций, которые обычно могут исполняться только между другими операциями вычислительного ядра. Эта особенность примечательна тем, что позволяет передавать сложные структуры памяти, которые являются более продвинутыми, чем простые линейные. Наиболее это полезно для изображений и подобных данных, которые изначально являются 2D/3D структурами.
OpenCL 3.0 также вводит поддержку языка SPIR-V 1.3 (последняя версия SPIR-V - 1.5). Именно версия 1.3 на данный момент является частью спецификации Vulkan 1.1, что должно играть важную роль в улучшении взаимодействия между Vulkan и OpenCL, делая последний более эффективным в графических задачах.
Впрочем, стоит помнить, что OpenCL 3.0 все еще является предварительным стандартом и перед утверждением передается на обсуждение и знакомство разработчикам и широкой общественности. Впрочем, Khronos надеется, что уже через несколько месяцев они смогут получить ратификацию стандарта.