Темы



Расширение LLDB для отладки приложений, работающих на CPU и GPU

Коротко сгенерировано ИИ по тексту статьи
  • В lldb-server создана независимая от производителей архитектура плагинов для отладки приложений на CPU и GPU.
  • CPU и GPU представлены отдельными целями отладки, доступными в одном сеансе LLDB; плагин координирует их работу.
  • Meta передала в LLVM большую часть общей платформы, включая интерфейс плагинов, поддержку нескольких адресных пространств и имитационные тесты.

Почему это важно: Цель архитектуры — подключать новое оборудование к LLDB с помощью плагина производителя, а не отдельного отладчика.

  • Мы создали в lldb-server нейтральную к производителям архитектуру плагинов-ускорителей для отладки приложений, работающих на CPU и GPU. Она отделяет общую инфраструктуру отладчика от управления устройствами, зависящего от конкретного оборудования.
  • В этой архитектуре CPU и GPU представлены как отдельные процессы отладчика, но доступны в рамках одного сеанса отладки.

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

Это сложнее, чем подключить обычный отладчик к другому процессу. CPU и GPU могут использовать разные наборы инструкций, регистры, адресные пространства и модели выполнения. Кроме того, GPU управляется средой выполнения и драйвером внутри процесса хоста, поэтому для отладки устройства часто требуется тщательно координировать действия с CPU.

Исторически производители GPU создавали специализированные отладчики для своих устройств, в том числе AMD ROCgdb и NVIDIA CUDA-GDB. Эти инструменты обеспечивают глубокую поддержку соответствующих платформ, но общие возможности отладчика часто приходится реализовывать и поддерживать отдельно.

В Meta мы разрабатываем для LLDB другой подход: общую архитектуру плагинов-ускорителей в lldb-server. В этой статье слово «GPU» обозначает конкретные устройства и примеры, а «ускоритель» — более широкую, нейтральную к производителям абстракцию плагинов LLDB. Архитектура развивается благодаря вкладу инженеров Meta и участников экосистемы ускорителей. Она позволяет общему отладчику не зависеть от какого-либо одного GPU и при этом предоставляет производителям оборудования отдельный компонент для реализации специфичного для устройства поведения.

Почему отладка GPU бросает вызов традиционным моделям отладчиков

Традиционный отладчик обычно предполагает, что у одного процесса одна архитектура и единообразное представление потоков, регистров и памяти. Программы для GPU ставят под сомнение каждое из этих предположений.

Процесс хоста может работать на x86–64, тогда как его ядра используют совершенно другой набор инструкций. У потока CPU есть привычный контекст регистров, а GPU может выполнять группы дорожек синхронно. Указатели хоста и устройства могут относиться к разным адресным пространствам. GPU может предоставлять тысячи исполняемых дорожек, которые плохо вписываются в модель потоков большинства консольных и графических отладчиков.

Объединение всего этого состояния в одну искусственную модель процесса усложняет отладчик. Для каждой операции сначала приходится определять, относится ли она к CPU или GPU. Работа с регистрами, чтение памяти, точки останова, пошаговое выполнение и события остановки начинают зависеть от выбранного оборудования. Единая модель процесса также вынуждает объединять CPU и GPU в одну карту памяти, хотя их адресные пространства могут быть независимыми: один и тот же адрес, например 0×1000, может указывать на разные места в процессах CPU и GPU.

Вместо того чтобы скрывать эти различия, архитектура ускорителей LLDB задаёт для них чёткую границу.

Поддержка плагинов в lldb-server для отладки GPU

В LLDB используется вспомогательный процесс под названием lldb-server для запуска программы или подключения к ней, а также для выполнения низкоуровневых операций отладки. Клиент LLDB взаимодействует с сервером по удалённому протоколу GDB — протоколу команд для таких операций, как чтение памяти, проверка регистров, управление выполнением и установка точек останова.

Поскольку lldb-server уже управляет нативным процессом, это также подходящее место для взаимодействия со средой выполнения ускорителя. Новый интерфейс плагинов позволяет специализированному для оборудования бэкенду работать вместе с обычным отладчиком CPU. Бэкенд преобразует API отладки устройства, предоставляемый производителем, в понятия, уже знакомые LLDB: процессы, потоки, регистры, память, модули и причины остановки.

Такое разделение позволяет клиенту LLDB оставаться нейтральным к производителям. Общие улучшения командной строки, удалённого протокола, обработки символов и интеграции со средами разработки могут принести пользу всем ускорителям. При этом каждый производитель отвечает за особенности своего оборудования и стека драйверов.

Поддержка отладки GPU активируется, только если отлаживаемое приложение использует поддерживаемую среду выполнения GPU. Для приложений, работающих только на CPU, LLDB и lldb-serverпродолжают использовать существующий путь нативной отладки, не создавая дополнительных вычислительных накладных расходов во время выполнения.

Две цели отладки — единый процесс

В этой архитектуре CPU и ускоритель представлены как отдельные цели отладки LLDB.
У каждой цели своя архитектура, а также связанный с ней процесс отладчика, который отслеживает потоки, регистры, адресное пространство и состояние выполнения. Для CPU по-прежнему используется проверенный нативный механизм отладки LLDB. Когда становится доступен ускоритель, плагин предоставляет второе подключение, с помощью которого LLDB создаёт цель отладки для устройства.

С технической точки зрения две цели отладки остаются независимыми. Для разработчика же они могут быть доступны в одном сеансе LLDB или IDE. Это позволяет не объединять несовместимые понятия CPU и GPU в одну модель процесса и при этом сохранить единый рабочий процесс.

CPU и GPU остаются отдельными целями отладки LLDB, а плагин в lldb-server координирует отладку хоста и устройства.

Координация хоста и устройства

Типичный сеанс отладки состоит из нескольких шагов:

  1. LLDB подключается к lldb-server и определяет, какие плагины-ускорители доступны.
  2. Плагин может попросить LLDB установить внутренние точки останова в процессе хоста. Эти точки обозначают важные события среды выполнения, например момент, когда можно начать сеанс отладки GPU.
  3. Когда хост достигает одной из таких точек, lldb-server уведомляет плагин. Плагин инициализирует API отладки производителя и подготавливает конечную точку для отладки ускорителя.
  4. LLDB создаёт для ускорителя вторую цель отладки и подключается к ней. После этого для потоков устройства, регистров, памяти, модулей и точек останова можно использовать существующие абстракции LLDB.

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

Мы также создали имитационный плагин-ускоритель, который позволяет проверять этот процесс без специального оборудования. С его помощью набор тестов LLVM проверяет обнаружение плагинов, координацию точек останова, создание подключений и базовое состояние устройства. Это оказалось важным для разработки общей инфраструктуры, которую можно независимо проверять и анализировать без привязки к какому-либо конкретному GPU.

Типичный сценарий отладки GPU

Вот сокращённый сеанс, полученный с помощью примера HIP с вычислением скалярного произведения векторов:

(lldb) target list
Current targets:
  target #0: gpu_demo (x86_64, stopped)
* target #1: amd_memory_kernel[...] (amdgcn, stopped)

(lldb) b compute_element
Breakpoint 1: no locations (pending).
(lldb) c
(lldb) target select 0
(lldb) c
Launching kernel: 2 blocks x 32 threads
1 location added to breakpoint 1
Target 1 stopped.

(lldb) target select 1
(lldb) bt
* frame #0: compute_element(..., idx=32) at gpu_demo.hip:26
  frame #1: vector_dot_kernel(..., n=64) at gpu_demo.hip:35
Отложенная точка останова срабатывает при загрузке модуля GPU, а трассировка стека
получена из цели отладки GPU.

Общая платформа плагинов для производителей оборудования

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

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

Команды Meta, работающие над отладкой GPU, уже используют эту архитектуру. Поскольку мы эксплуатируем неоднородный парк GPU с разными аппаратными и программными стеками, тот факт, что эти команды используют одну и ту же модель, служит важным подтверждением правильности архитектуры: общий слой LLDB может оставаться стабильным, а каждый бэкенд — точно описывать своё устройство.

На момент написания статьи мы передали в LLVM большую часть общей платформы. В неё входят интерфейс плагинов lldb-server; пакеты удалённого протокола GDB для обнаружения плагинов, инициализации, координации событий среды выполнения и создания подключений к GPU; поддержка связывания процессов-отладчиков CPU и GPU с сохранением независимых архитектур; поддержка нескольких адресных пространств и аппаратно-независимые имитационные тесты. Оставшиеся компоненты мы планируем передать в LLVM в ближайшее время.

Дальнейшие планы

Далее мы планируем завершить передачу оставшейся общей инфраструктуры в LLVM и расширить построенные на её основе интеграции с производителями. Наша цель — сделать так, чтобы для интеграции нового оборудования с LLDB требовался только плагин производителя, а не отдельный отладчик, который нужно создавать и поддерживать. 

Благодарности 

Мы благодарны руководящей команде Meta по инфраструктуре разработки, особенно Shane Nay, Todd Fiala и Ale Contenti: их непосредственная поддержка сделала эту работу возможной.

Мы также благодарим коллег из команды отладки и инструментов — Jacob Lalonde, David Young, Alexandre Perez, Zhiyuan Li, Piyush Jaiswal и Philip DePetro — за сотрудничество и поддержку.

Наконец, мы благодарим сообщество открытого кода, особенно Jonas Devlieghere, Jim Ingham, David Spickett и Jason Molenda, за рецензирование RFC и запросов на включение изменений в основную ветку.

© Engineering at Meta