Analizzare i grafici a fiamma per la profilazione GPU in Servizio Azure Kubernetes (AKS) (anteprima)

I grafici di fiamma di profilatura GPU mostrano quali funzioni utilizzano la maggior parte della memoria GPU. Questo articolo illustra come interpretare i grafici di fiamma generati dagli strumenti di profilatura GPU per Servizio Azure Kubernetes (AKS).

Important

Le funzionalità in anteprima di AKS sono disponibili in modalità self-service, su base volontaria. Le anteprime vengono fornite "così come sono" e "come disponibili" e sono escluse dai contratti di servizio e dalla garanzia limitata. Le anteprime di AKS sono coperte solo parzialmente dall'assistenza clienti nei limiti del possibile. Di conseguenza, queste funzionalità non sono destinate all'uso in produzione. Per altre informazioni, vedere gli articoli di supporto seguenti:

Prima di iniziare, configurare la profilatura GPU e verificare che i dati di profilatura siano disponibili in Pyroscope e Grafana.

Annotazioni

La prima esecuzione della profilatura potrebbe non visualizzare tutti i simboli, inclusi i simboli delle operazioni di avvio, ad esempio il caricamento del modello, mentre il profiler analizza il carico di lavoro e risolve i simboli. Eseguire di nuovo il carico di lavoro dopo l'analisi iniziale per acquisire questi simboli nei profili successivi.

Comprendere i grafici delle fiamme

Un grafico di fiamma visualizza gli stack di chiamate profilati. Ogni barra rappresenta una funzione e le barre in pila mostrano la catena di chiamate o quale funzione ha chiamato un'altra funzione. La larghezza di ogni barra rappresenta la quantità della risorsa misurata, ad esempio il tempo cpu o la memoria GPU allocata, che passa attraverso tale funzione.

Regola chiave: più ampia è una barra, maggiore è il flusso delle risorse misurate attraverso tale funzione.

I grafici di fiamma di esempio seguenti vengono acquisiti da un carico di lavoro di inferenza vLLM.

Schermata della vista iniziale compressa del grafico di fiamma in Grafana per un carico di lavoro vLLM, con barre sovrapposte che rappresentano gli stack di chiamate per l'allocazione della memoria GPU.

Tip

Usare Espandi tutti i gruppi nel pannello del grafico flame di Grafana per visualizzare l'intero stack di chiamate senza comprimerlo. Usare la casella Di ricerca per trovare funzioni o parole chiave specifiche. Per evitare che il pannello si richiuda di nuovo, metti in pausa l'aggiornamento automatico della dashboard impostando l'intervallo di aggiornamento su Disattivato nell'angolo in alto a destra della dashboard di Grafana mentre esamini il flame graph espanso.

Schermata del grafico di fiamma in Grafana per un carico di lavoro di vLLM dopo aver selezionato Espandi tutti i gruppi, che mostra lo stack di chiamate completo con i singoli frame delle funzioni per le allocazioni di memoria della GPU.

Tip

Usa blocco di messa a fuoco per focalizzarti su un percorso di allocazione specifico.

Leggi i simboli

Le etichette dei grafi di fiamma seguono queste convenzioni:

Formato del simbolo Meaning
Foo > bar class Foo: method def bar()
Foo > __init__ Costruttore della classe Foo
bar (solo) Funzione autonoma def bar()
<interpreter trampoline> Overhead di CPython. È possibile ignorare questo simbolo.
<raw-address>, ad esempio, 0x7f151 Codice C o CUDA nativo senza simbolo Python disponibile.

Ecco alcuni esempi:

  • GPUModelRunner / _allocate_kv_cache_tensors: metodo in una classe. Leggere questo simbolo come class GPUModelRunner: def _allocate_kv_cache_tensors(self).
  • LlamaMLP / __init__: costruttore chiamato durante la creazione di un LlamaMLP(...) oggetto .
  • _compile_fx_inner: funzione autonoma a livello di modulo che non si trova all'interno di una classe.

Comprendere l'allocazione propria rispetto a quella totale

Usare i valori Self e Total per determinare dove viene utilizzata la risorsa:

  • Total è la risorsa utilizzata da una funzione e tutto ciò che chiama. Una funzione può avere un totale elevato, ma allocare nulla perché fa parte della catena di chiamate.
  • Self indica la risorsa utilizzata direttamente dalla funzione, escluse le relative funzioni figlio. Un valore proprio elevato indica che in questa funzione viene consumata la risorsa.

Ad esempio, se GPUModelRunner._allocate_kv_cache_tensors ha 55,1 GB di allocazione automatica, è la funzione che chiama torch.empty() per creare i tensori della cache chiave-valore (KV).

Usare le tecniche di spostamento seguenti:

  • Inizia con i nodi foglia, che sono barre senza nulla sopra. L'intera larghezza rappresenta l'allocazione propria.
  • Quando si cerca l'origine di un'allocazione, ignorare le barre larghe con allocazione propria pari a zero. Queste funzioni coordinano le chiamate ad altre funzioni.
  • Esaminare le barre larghe con un'allocazione propria elevata come potenziali destinazioni di ottimizzazione.

Individua il maggior consumatore di risorse

Per identificare gli hotspot, seguire questa procedura:

  1. Esaminare le barre più ampie nella parte superiore del grafico. Queste funzioni foglia allocano memoria. Più ampia è la barra, maggiore è la quantità di memoria utilizzata.

  2. Controllare l'allocazione propria rispetto all'allocazione totale. Una barra larga nella parte inferiore con self: 0 fa parte della catena di chiamate. Seguirlo verso l'alto fino a trovare una barra con autoallocazione elevata.

  3. Leggere lo stack di chiamate dal basso verso l'alto per comprendere il motivo per cui è stata chiamata la funzione. L'esempio seguente termina con la funzione che esegue l'allocazione:

    <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
    

Usare la tabella seguente come riferimento rapido:

Obiettivo Cosa cercare
Trovare ciò che alloca la maggior parte della memoria Barra foglia più larga nella parte superiore dello stack
Trovare ciò che è responsabile della maggior parte della memoria Barra più larga nella parte inferiore dello stack
Identificare le destinazioni di ottimizzazione Barre con allocazione propria elevata
Identificare le funzioni che è possibile ignorare Barre larghe con allocazione propria pari a zero

Passaggi successivi