Что такое программирование GPU?
В мире высокопроизводительных вычислений GPU (графические процессоры) встречаются повсюду, и учёные, работающие в определённых областях, сталкиваются со всё более сложной задачей. А именно: им нужно дорабатывать свои компьютерные программы, чтобы максимально использовать эти современные GPU-системы. Эта задача важна для того, чтобы раскрыть всю мощь этих высокотехнологичных архитектур GPU.
В этой статье мы дадим базовое понимание программирования GPU тем, кто ищет ответ на вопрос «Что такое программирование GPU?». Кроме того, мы рассмотрим разные подходы и фреймворки для GPU, а также самую популярную платформу программирования GPU на Python, CUDA, и её значение для написания кода для GPU.
Что такое GPU?
Графический процессор (GPU) - это электронная схема, которая ускоряет создание изображений для вывода на экран за счёт быстрой работы с памятью и одновременной обработки данных. Сегодня такие GPU встречаются повсеместно: они есть в различных вычислительных устройствах, таких как персональные компьютеры, игровые консоли, профессиональные рабочие станции и даже смартфоны.
Со временем GPU превзошли CPU по производительности: у них больше транзисторов, и они отлично справляются с параллельными вычислениями. Превратившись в сложные устройства с собственной памятью, шинами и процессорами, GPU можно рассматривать как дополнительный мозг или процессор компьютерной системы.
Что такое программирование GPU?
Программирование GPU использует GPU-ускорители для одновременного выполнения вычислений общего назначения. Раньше GPU использовались в основном для компьютерной графики, но теперь их применяют и для самых разных вычислительных задач общего назначения. Помимо создания графики, GPU теперь широко используют для научного моделирования, машинного обучения и других работ, которые можно выполнить быстрее, обрабатывая много задач одновременно.
В чём разница между GPU и CPU?
Основное различие между вычислениями на GPU и CPU заключается в их архитектурных особенностях. Благодаря высокой степени параллелизма GPU эффективнее CPU при обработке данных, которые можно разделить и обрабатывать несколькими способами. GPU специально оптимизированы для интенсивных вычислений, таких как матричная арифметика и арифметика с плавающей запятой.
Разница в вычислительной мощности между CPU и GPU объясняется тем, что GPU разработаны для выполнения высокопараллельных и вычислительно интенсивных задач, а именно этого и требует рендеринг графики.
В архитектуре GPU приоритет отдаётся обработке данных, а не кешированию данных и управлению потоком выполнения. При параллельном решении задачи возникают два заметных преимущества: во-первых, для каждого элемента выполняется одна и та же операция, что снижает потребность в сложном управлении потоком выполнения; во-вторых, большой набор данных и высокая арифметическая интенсивность снижают потребность в памяти с низкой задержкой.
Какие подходы или API для программирования GPU используются?
К использованию GPU для вычислений можно подходить по-разному. В простейших случаях, когда код уже написан, может быть достаточно настроить параметры и начальные конфигурации. Другой вариант - использовать библиотеки для наиболее ресурсоёмких частей кода. Однако в более сложных сценариях может потребоваться некоторое программирование.
Существуют различные программные среды и API для программирования GPU. Их делят на модели на основе директив, непереносимые модели на основе ядер и переносимые модели на основе ядер, а также на высокоуровневые фреймворки и библиотеки.
Стандартные C++/Fortran
Программы на стандартных C++ и Fortran могут использовать GPU NVIDIA без внешних библиотек. Компиляторы NVIDIA SDK оптимизируют код для выполнения на GPU, как показано в приведённых рекомендациях.
Программирование на основе директив
Подходы на основе директив предполагают аннотирование существующего последовательного кода, чтобы обозначить циклы и участки для выполнения на GPU. Этот метод, примерами которого являются OpenACC и OpenMP, ориентирован на продуктивность разработки и простоту использования, но может несколько уступать в производительности.
OpenACC: консорциум, созданный в 2010 году. OpenACC стремится предоставить стандартную, переносимую и масштабируемую модель программирования для ускорителей, включая GPU. Изначально он поддерживал только GPU NVIDIA, но расширяет поддержку на другие устройства и архитектуры.
OpenMP: изначально это был API для параллельного программирования с общей памятью для многоядерных CPU, а теперь OpenMP поддерживает перенос вычислений на GPU и ориентирован на разные типы GPU.
Непереносимые модели на основе ядер (нативные модели программирования)
Прямое программирование GPU даёт разработчикам больше контроля благодаря низкоуровневому коду, взаимодействующему непосредственно с GPU. Примеры: CUDA (NVIDIA) и HIP (AMD), причём HIP разработан для совместимости между GPU NVIDIA и AMD.
Переносимые модели на основе ядер (кроссплатформенные экосистемы переносимости)
Кроссплатформенные экосистемы переносимости, такие как Alpaka, Kokkos, OpenCL, RAJA и SYCL, предлагают абстракции более высокого уровня для удобного и переносимого программирования GPU. Их цель - переносимость производительности при едином исходном коде приложения.
Kokkos: разработанная в Sandia National Laboratories, Kokkos - это экосистема на основе C++, поддерживающая эффективные и масштабируемые параллельные приложения на CPU, GPU и FPGA.
OpenCL: открытый стандартный API для параллельных вычислений общего назначения на различном оборудовании. OpenCL предоставляет низкоуровневый программный интерфейс для программирования GPU. Он поддерживает CPU, GPU и FPGA от многих производителей.
SYCL: бесплатная (без лицензионных отчислений) модель программирования на C++ с открытым стандартом. SYCL предоставляет высокоуровневую модель программирования с единым исходным кодом для гетерогенных систем, включая GPU. Её можно реализовать поверх OpenCL, CUDA или HIP.
Поддержка в высокоуровневых языках
Python поддерживает программирование GPU с помощью нескольких библиотек, у каждой из которых своё назначение:
CuPy
- Библиотека массивов данных на основе GPU.
- Бесшовная интеграция с NumPy/SciPy.
- Простой переход к вычислениям на GPU: достаточно заменить 'numpy' и 'scipy' на 'cupy' и 'cupyx.scipy' в коде Python.
cuDF (RAPIDS)
- Часть RAPIDS, реализующая функциональность CUDA с привязками к Python.
- Предназначена для работы с датафреймами на GPU.
- Предлагает API, похожий на pandas, что позволяет пользователям, знакомым с Pandas, ускорить работу без глубоких знаний CUDA.
PyCUDA
- Среда программирования на Python для CUDA.
- Предоставляет доступ к CUDA API от NVIDIA из Python.
- Ограничена GPU NVIDIA и требует опыта программирования на CUDA.
Numba
- Позволяет выполнять JIT-компиляцию (Just-In-Time) кода Python для выполнения на GPU.
- Поддерживает GPU NVIDIA, а в будущем ожидается поддержка GPU AMD.
Эти библиотеки предоставляют разнообразные варианты программирования GPU на Python с учётом разных предпочтений и требований пользователей. Будь то переход с NumPy/SciPy с помощью CuPy или использование похожего на pandas API cuDF, Python обеспечивает гибкость для эффективных вычислений с ускорением на GPU.
Что такое CUDA?
CUDA - это платформа параллельных вычислений и API, созданные NVIDIA, с которых началась эра массовых фреймворков для программирования GPU. Эта технология позволяет разработчикам писать код, похожий на C++, который выполняется на GPU.
CUDA не только предоставляет множество библиотек и инструментов для низкоуровневого программирования GPU, но и значительно повышает эффективность вычислительно требовательных приложений. Следует отметить, что CUDA работает только с оборудованием NVIDIA, несмотря на такую мощную экосистему.
Как установить CUDA на Ubuntu 20.04 для программирования GPU
Вы можете установить CUDA на Ubuntu 20.04, выполнив приведённые ниже пошаговые инструкции:
Шаг 1: сначала скачайте файл конфигурации приоритета CUDA (cuda-ubuntu2004.pin), необходимый для настройки репозиториев CUDA на Ubuntu 20.04, с помощью команды ‘wget’ или ‘curl’.
$ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pinШаг 2: переместите скачанный файл конфигурации приоритета в указанный каталог, установив для него приоритет 600.
$ sudo mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600Шаг 3: скачайте пакет репозитория CUDA:
wget https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda-repo-ubuntu2004-11-4-local_11.4.2-470.57.02-1_amd64.debШаг 4: установите скачанный пакет репозитория CUDA с помощью менеджера пакетов dpkg.
$ sudo dpkg -i cuda-repo-ubuntu2004-11-4-local_11.4.2-470.57.02-1_amd64.debШаг 5: добавьте публичный ключ, необходимый для аутентификации репозитория CUDA.
$ sudo apt-key add /var/cuda-repo-ubuntu2004-11-4-local/7fa2af80.pubШаг 6: обновите списки пакетов:
$ sudo apt-get updateОбновите локальные списки пакетов информацией из только что добавленного репозитория CUDA.
Шаг 7: теперь установите CUDA Toolkit на свою машину с Ubuntu 20.04 с помощью следующей команды:
$ sudo apt-get -y install cudaВыполнив приведённые выше шаги, вы сможете установить CUDA на машину с GPU, поддерживающим CUDA, под управлением Ubuntu 20.04. Теперь вы можете запускать код для GPU и использовать платформу CUDA на своей Linux-машине.
Заключение
Выбор среды программирования GPU зависит от таких факторов, как целевые аппаратные платформы, характер вычислений и опыт разработчика. Совместимость с конкретными GPU, соответствие требованиям проекта и предпочтения разработчика в пользу высокоуровневой простоты или низкоуровневого контроля - ключевые соображения для оптимального выбора.