Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Графики профилирования GPU показывают, какие функции используют большую часть памяти GPU. В этой статье объясняется, как интерпретировать графы пламени, созданные средствами профилирования GPU для Azure Kubernetes Service (AKS).
Important
Предварительные версии функций AKS доступны на условиях самообслуживания и по выбору пользователя. Предварительные версии предоставляются "как есть" и "при наличии". На них не распространяются соглашения об уровне обслуживания и ограниченная гарантия. Предварительные версии AKS сопровождаются частичной поддержкой клиентов на основе принципа лучших усилий. Как таковые, эти функции не предназначены для использования в производстве. Для получения дополнительной информации ознакомьтесь со следующими статьями поддержки:
Прежде чем начать, настройте профилирование GPU и убедитесь, что данные профилирования доступны в Пироскопе и Grafana.
Замечание
При первом запуске профилирования могут отображаться не все символы, включая символы операций запуска, таких как загрузка модели, пока профилировщик анализирует нагрузку и выполняет разрешение символов. Запустите рабочую нагрузку еще раз после первоначального анализа, чтобы записать эти символы в последующих профилях.
Понимание графов пламени
Граф пламени визуализирует профилированные стеки вызовов. Каждая полоса представляет функцию, а составные полосы показывают цепочку вызовов, то есть какая функция вызвала другую функцию. Ширина каждой панели представляет объем измеряемого ресурса, например времени ЦП или выделенной памяти GPU, который проходит через эту функцию.
Ключевое правило: чем шире полоса, тем больше измеряемого ресурса проходит через такую функцию.
Следующие образцы диаграмм пламени получены при нагрузке инференса vLLM.
Tip
Используйте Expand all groups на панели flame graph в Grafana, чтобы увидеть полный стек вызовов без свертывания. Используйте поле поиска для поиска определенных функций или ключевых слов. Чтобы панель снова не сворачивалась, приостановите автообновление панели мониторинга, установив интервал обновления в значение Off в правом верхнем углу панели мониторинга Grafana, пока вы проверяете развернутый flame graph.
Tip
Используйте блок фокуса , чтобы сосредоточиться на определенном пути выделения.
Чтение символов
Метки графа пламени следуют этим условностям:
| Формат символов | Значение |
|---|---|
Foo > bar |
class Foo: method def bar() |
Foo > __init__ |
Конструктор класса Foo |
bar (отдельно) |
def bar() Автономная функция |
<interpreter trampoline> |
Накладные расходы CPython. Этот символ можно игнорировать. |
<raw-address>, например 0x7f151 |
Собственный код C или CUDA без Python символов. |
Вот некоторые примеры:
-
GPUModelRunner/_allocate_kv_cache_tensors: метод класса. Прочитайте этот символ какclass GPUModelRunner: def _allocate_kv_cache_tensors(self). -
LlamaMLP/__init__: конструктор, вызываемый при созданииLlamaMLP(...)объекта. -
_compile_fx_inner: автономная функция уровня модуля, которая не находится внутри класса.
Общие сведения о самостоятельном распределении и общем выделении
Используйте значения self и Total , чтобы определить, где используется ресурс:
- Итог — это ресурс, потребляемый функцией, и все, что вызывается. Функция может иметь большую общую сумму, но выделить ничего не может, так как она является частью цепочки вызовов.
- Self — объём ресурсов, потребляемых непосредственно функцией, без учёта её дочерних функций. Высокое самозначное значение означает, что эта функция является местом использования ресурса.
Например, если на GPUModelRunner._allocate_kv_cache_tensors приходится 55,1 ГБ собственного выделения памяти, то именно эта функция вызывает torch.empty() для создания тензоров кэша «ключ-значение» (KV).
Используйте следующие методы навигации:
- Начните с листовых узлов — полос, над которыми ничего нет. Вся их ширина означает самостоятельное распределение.
- Пропускайте широкие полосы с нулевым собственным выделением памяти при поиске источника выделения памяти. Эти функции координируют вызовы других функций.
- Изучите широкие полосы с высоким уровнем самостоятельного выделения в качестве потенциальных целевых объектов оптимизации.
Поиск крупнейшего потребителя ресурсов
Чтобы определить точки доступа, выполните следующие действия.
Посмотрите на самые широкие полосы в верхней части графа. Эти листовые функции выделяют память. Чем шире панель, тем больше памяти она потребляет.
Сравните собственное и общее выделение. Широкая полоса внизу с
self: 0является частью цепочки вызовов. Следуйте за ним вверх, пока не найдете бар с высоким уровнем самостоятельного выделения.Прочитайте стек вызовов снизу вверх, чтобы понять, почему была вызвана функция. Следующий пример заканчивается функцией, выполняющей выделение:
<raw-address>, for example, 0x7f151 -> native code entry <interpreter trampoline> -> CPython dispatch <module> -> script top level EngineCoreProc.run_engine_core -> vLLM engine startup EngineCore.__init__ -> engine initialization EngineCore._initialize_kv_caches -> KV cache setup Worker.initialize_from_config -> worker setup GPUModelRunner.initialize_kv_cache -> model runner GPUModelRunner._allocate_kv_cache_tensors -> actual allocation
Используйте следующую таблицу в качестве краткой ссылки:
| Goal | Что искать |
|---|---|
| Найдите, что использует больше всего памяти | Самая широкая полоса листа в верхней части стека |
| Найдите, что использует больше всего памяти | Самая широкая полоса внизу стека |
| Определение целевых объектов оптимизации | Панели с широким самораспределением |
| Определение функций, которые можно пропустить | Широкие полосы с нулевым самостоятельным выделением |