Использование графических ускорителей (Graphical Processing Unit, GPU) наряду с классическими микропроцессорами (Central Processing Unit, CPU) сегодня является распространенной практикой в сфере параллельных вычислений на гетерогенных платформах, сочетающих в себе вычислительные элементы различного типа. Однако GPU и CPU изначально разрабатывались как различные устройства, нацеленные на решение своих задач, и их совместное использование осложняется рядом проблем. Например, они имеют раздельную память и разные адресные пространства, поэтому приложение должно явным образом копировать данные в память GPU и обратно в основную память компьютера. Отправка вычислительного задания в очередь исполнения устройства осуществляется через стек драйверов с использованием системных вызовов и ядра операционной системы, что вносит большую задержку и зачастую делает нецелесообразным выполнение маленьких заданий на отдельном ускорителе. Кроме того, отправка заданий одного ускорителя другому или CPU затруднительна.

Для развития архитектуры гетерогенных систем и упрощения моделей программирования в 2012 году был образован фонд HSA Foundation, занимающийся разработкой спецификаций Heterogeneous System Architecture (HSA). В HSA Foundation сегодня входят такие компании, как AMD, ARM, Imagination Technologies, MediaTek, Texas Instruments, Samsung Electronics и Qualcomm.

HSA — это архитектура гетерогенных систем с общей когерентной памятью для разнородных вычислительных элементов, поддержкой управления очередями задач, широкого спектра оборудования и языков высокого уровня. Свойство когерентности памяти означает, что различные процессоры видят консистентное (непротиворечивое) состояние общей памяти, даже когда память независимо обновляется любым из процессоров. Когерентность памяти давно воспринимается как нечто само собой разумеющееся для гомогенных многопроцессорных и многоядерных систем, однако еще в новинку для гетерогенных систем.

В общем случае поддержка когерентности представляет собой сложную задачу. Правда, способность процессоров различных типов (CPU, GPU, DSP) работать с одними и теми же данными в общей памяти позволяет избавиться от лишних операций копирования и повысить производительность и энергоэффективность (рис. 1). В среде HSA приложения, работающие на CPU, могут выполнять отдельные задания на GPU/DSP так же легко, как и на CPU. Для этого приложению достаточно предоставить указатели на данные в общей памяти и обновить соответствующие очереди задач. При традиционном подходе приложение должно собрать все необходимые данные и, задействовав драйверы ОС, выполнить операции ввода-вывода для перемещения данных на вычислительное устройство, а затем запустить вычислительный процесс. HSA позволяет разработчикам ПО создавать приложения без необходимости глубоко вникать в специфику работы различных ускорителей, имеющихся на целевой системе, таких как GPU, DSP, видеокодеры/декодеры и прочие акселераторы.

Рис. 1. В HSA интегрированы системы с процессорными ядрами любого типа
Рис. 1. В HSA интегрированы системы с процессорными ядрами любого типа

Общая виртуальная память

Для упрощения работы ОС и приложений на платформе HSA используется единый набор таблиц виртуальных страниц для всех типов процессоров, что позволяет обмениваться указателями между любыми вычислительными устройствами — одинаковые указатели преобразуются в одинаковые физические адреса. Более того, данный подход избавляет ОС и менеджер памяти от необходимости вести учет нескольких независимых наборов таблиц страниц для каждого устройства. Если CPU и GPU используют одинаковые участки памяти, то для традиционных GPU используются отдельные адресные пространства, и драйвер графического адаптера должен сбрасывать кэши при совместном использовании памяти с CPU.

Платформа HSA предоставляет разработчику полностью когерентную память, что упрощает создание приложений — где вычислители с разной архитектурой используются в рамках единых шаблонов программирования, позволяя применять привычные алгоритмы, например производитель-потребитель. Однако HSA поддерживает и некогерентную память, что бывает необходимо для получения максимальной производительности, когда нет необходимости совместного использования данных процессорами разного типа.

Операционная система, за счет механизма подкачки страниц, позволяет пользовательским процессам работать с объемами памяти, превышающими размер физической, однако обычные GPU могут работать только с невыгружаемой основной памятью — драйвер и ОС должны выделить участок в физической памяти, пометить его как невыгружаемый и создать отдельное виртуальное адресное пространство специально для работы ускорителя. HSA позволяет избавиться от невыгружаемой памяти и разделенных пространств адресов, позволяя всем GPU за счет механизма страничных прерываний использовать такое же большое адресное пространство, как и у CPU, с возможностью подкачки страниц.

Имеется множество задач, требующих памяти больше, чем могут предоставить современные графические ускорители, даже с учетом использования невыгружаемой основной памяти. В этом случае разделение задачи и данных на независимые части и реализация подкачки данных требует значительных усилий со стороны программиста, поэтому такие большие задачи редко переносились на GPU. Единое адресное пространство и страничные прерывания, обеспечиваемые архитектурой HSA, позволяют использовать ускорители и для подобных задач, что существенно повышает производительность, причем без усложнения программного кода. В дополнение к этому общее адресное пространство позволяет использовать структуры данных, содержащие указатели, такие как связные списки и деревья, одновременно доступные и CPU, и GPU. При традиционном подходе подобные случаи требуют от программиста отдельного рассмотрения и зачастую являются основной причиной невозможности переноса алгоритмов на GPU.

Очереди и диспетчеризация задач

Работа ядра операционной системы зачастую была причиной появления узких мест в массово-параллельных системах — HSA позволяет снизить время, затрачиваемое на диспетчеризацию вычислительных задач, давая возможность процессам напрямую работать с очередями задач в пользовательском режиме без необходимости вызова системных функций и переключения в режим ядра. Такой подход минимизирует накладные расходы, вносимые системными драйверами. Кроме того, платформа HSA предоставляет ускорителям возможность аппаратного переключения контекста задач, стоящих в очереди, без необходимости вызова функций ядра ОС — специальный аппаратный планировщик способен существенно ускорить переключение контекста и сократить энергозатраты. Тем не менее ОС сохраняет за собой контроль над планировщиком, и в зависимости от сложности аппаратной составляющей конкретного ускорителя управление очередью может быть как чисто программным или аппаратным, так и смесью программного и аппаратного управления. В случае полностью аппаратного управления, CPU может ставить задачи на исполнение ускорителю без обращения к ОС.

Обеспечение малых задержек при диспетчеризации задач — важный элемент архитектуры HSA. Данная особенность позволяет рассматривать дополнительные ускорители как сопроцессоры и работать с ними соответствующим образом — разработчики приложений могут не опасаться снижения производительности из-за перемещения данных на внешнее или удаленное вычислительное устройство, а также за задания малого размера.

Очереди представляют собой области физической памяти, куда производитель помещает запросы, а потребитель их считывает. Потребителем в данном случае является исполняющее вычислительное устройство. Системные программные компоненты HSA отвечают за выделение и освобождение памяти и создание очередей — как только очередь создана, программист может посылать в нее задания без участия ОС, причем работать с очередями можно при помощи вызовов библиотечных функций или напрямую. При непосредственной работе с очередями необходимо учитывать их ограниченный размер и прочие нюансы. Библиотеки, в свою очередь, могут предоставлять возможность автоматической балансировки нагрузки и другой полезный функционал. Очереди могут быть не только у ускорителей, но и у CPU, что позволяет любому вычислительному устройству посылать задачи на исполнение на любое другое вычислительное устройство. Возможны три варианта:

  • Процессор посылает задачу на ускоритель. Данный вариант взаимодействия типичен для GPU-вычислений (OpenCL, CUDA).
  • Ускоритель посылает задачу другому ускорителю (в том числе себе). Этот вариант позволяет ставить на исполнение дополнительные задачи без участия CPU. В противном случае необходимость выполнения кода на CPU и ожидания диспетчеризации соответствующего процесса ОС вносила бы очень большие задержки.
  • Ускоритель посылает задачу на CPU. Таким образом ускоритель может запросить выполнение системных функций, например выделение памяти или осуществление ввода-вывода.

Важным требованием HSA является вытесняемость задач (preemption) — неотъемлемое свойство многопроцессорных многопользовательских систем. Без реализации вытесняемости одна задача может занять все устройство на произвольный промежуток времени, блокируя остальные задачи, стоящие в очереди. Ошибка в коде может привести к необходимости перезагрузки устройства. HSA не ограничивает разработчиков ускорителей в способе реализации вытесняемости.

Программные компоненты HSA

Архитектура HSA определяет не только необходимые аппаратные возможности системы, но и ее программную часть — систему компиляции и загрузки исполняемых файлов и компоненты, работающие в пользовательском режиме и на уровне ядра ОС (рис. 2).

Рис. 2. Программный стек HSA
Рис. 2. Программный стек HSA

Архитектура HSA нацелена на поддержку большого разнообразия оборудования, однако необходимо сохранить независимость приложений от конкретной аппаратной платформы. Для достижения этой цели используется стандартизованный интерфейс в виде языка низкого уровня — HSAIL (HSA Intermediate Language). Для участков программы, которые планируется запускать на ускорителях, компилятор генерирует HSAIL-код, единый для всех типов GPU. Язык HSAIL специально проектировался так, чтобы он мог быть быстро и относительно просто отображен на конкретное устройство и скомпилирован в его систему команд. Перед исполнением код HSAIL преобразуется в код системы команд целевого акселератора — это преобразование может проводиться как в момент компиляции, так и во время выполнения приложения. Компонент программного стека, выполняющий эту трансляцию, именуемый финализатором (finalizer), специфичен для каждого вида ускорителей. Язык HSAIL предназначен для использования возможностей параллельных вычислений и близок по концепции с OpenCL SPIR, где также используются понятия «рабочая единица» (work item) и «рабочая группа» (work group). При использовании OpenCL на платформе HSA код на языках SPIR или OpenCL транслируется в HSAIL.

Компиляторы, генерирующие код для платформы HSA, целиком компилируют приложение для системы команд процессора, включая вычислительные ядра, предназначенные для запуска на ускорителях. Код на HSAIL добавляется в специальную секцию исполняемого файла, за счет чего подобный файл может быть запущен на системе без поддержки HSA. HSA-приложение может содержать функции, предназначенные как для CPU, так и для GPU (HSAIL), а вызов функции будет осуществляться одним из следующих способов:

  • Из функции CPU вызывается функция CPU. В таком случае при вызове будут использоваться стандартные для данной платформы соглашения о вызове функций.
  • Из функции HSAIL вызывается функция HSAIL. Архитектура HSA имеет свой стандарт на правила вызова функций, однако финализатор может использовать то соглашение о вызове функций, которое наиболее подходит для конкретного оборудования (например, передача параметров через память или через регистры).
  • Из функции CPU вызывается функция HSAIL и наоборот. В данном случае предполагается асинхронный вызов с использованием очередей задач.

Стандартные синхронные модели вызовов, наподобие RPC, могут быть реализованы поверх очередей.

В среду выполнения HSA на пользовательском уровне (рис. 2) входят компоненты, необходимые для запуска уже скомпилированной HSA-программы. Они отвечают за размещение задач в очередях и предоставление информации о возможностях текущей платформы. Системный слой HSA отвечает за выполнение функций планировщика, управление памятью и выделение ресурсов, в том числе памяти под очереди. Сюда же входит функция управления модулем MMU (Memory Management Module), который в архитектуре HSA обозначается HMMU.

 

Поддержка архитектуры HSA

Полные спецификации архитектуры HSA пока не обнародованы и находятся в разработке в рабочих группах HSA Foundation, однако для некоторых процессоров уже заявлена поддержка того или иного функционала HSA. В частности, используемые в Google Nexus 10 и Google Chromebook системы на кристалле с процессорными ядрами ARM Cortex-A15 и графическими ядрами семейства Mali-T600 поддерживают когерентную общую память hUMA (heterogeneous Uniform Memory Access), что увеличивает производительность приложений OpenCL. По сравнению с обычной обработкой изображений на CPU, связка CPU+GPU дает прирост скорости от 3 до 15 раз. Семейство процессоров AMD Kaveri также поддерживает когерентную память hUMA и объединяет до четырех ядер с микроархитектурой SteamrollerB и графическое ядро GCN, содержащие до 512 потоковых процессоров. Алгоритм распознавания лиц в данной конфигурации выполняется 2,3 раза быстрее при снижении энергопотребления в 2,4 раза по сравнению с его выполнением на процессоре прошлого поколения AMD Triniti. Подобные показатели стали возможны за счет совместной эффективной работы ядер CPU и GPU. Следующим шагом к воплощению HSA будет реализация вытесняемости задач и смены контекста на GPU-ядрах.

 

Поддержка технологий программирования

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

Платформа HSA также предоставляет дополнительные возможности графическим приложениям — приложение может иметь доступ к тем регионам памяти, где располагаются данные, используемые графическими API. Это позволяет ускорителям напрямую использовать графические буферы для отображения результатов вычислений вообще без вмешательства процессора.

В HSA Foundation решается задача предоставления разработчикам всех возможностей параллельных и гетерогенных систем без необходимости освоения новых языков программирования — путем эволюционирования существующих языков и библиотек. Это позволит разработчикам вместе с их уже написанными приложениями воспользоваться преимуществами архитектуры HSA — например, компания AMD начала этот процесс с оптимизации под HSA средств разработки параллельных программ для гетерогенных сред: OpenCL и C++ AMP.

Кроме этого, сейчас ведется работа по обеспечению поддержки HSA в таких языках, как Java и Python, — например, библиотека APARAPI позволяет конвертировать байткод Java в OpenCL при использовании специального класса Java. Компании AMD и Oracle совместно развивают проект Sumatra, планируемый к выходу вместе с Java 9 в 2015 году и предоставляющий виртуальной машине Java возможность использования HSA. Обновляются стандартные библиотеки, поэтому многие Java-приложения могут использовать HSA без изменения кода.

Задача HSA — ликвидация барьера сложности программирования между CPU, GPU и DSP различных типов (рис. 3), снижение задержек при их взаимодействии, обеспечение поддержки широкого набора программных платформ и технологий программирования. Сегодня ускорители GPU/DSP еще не обладают достаточной гибкостью для решения многих задач, тогда как архитектура HSA предоставляет доступ к единому адресному пространству со стороны всех вычислительных устройств, механизм управления очередями задач на пользовательском уровне и переключение контекстов с возможностью вытеснения задач для всех типов вычислительных элементов. HSA объединяет процессоры CPU, GPU, DSP и другие ускорители в единую систему с общим принципом организации вычислений, что существенно облегчает разработчикам процесс решения разнообразных вычислительных задач.

Рис. 3. Этапы работы приложения на традиционной и HSA платформах
Рис. 3. Этапы работы приложения на традиционной и HSA платформах

 

Тимур Палташев (timpal@mail.npu.edu) — заведующий кафедрой технологий визуализации, Илья Перминов (i.am.perminov@gmail.com) — аспирант, НИУ ИТМО (Санкт-Петербург). Статья подготовлена на основе материалов доклада, представленного авторами на IV Московский суперкомпьютерный форум (МСКФ-2013, грант РФФИ 13-07-06046 г).