Implementare DMABUF e l'account della memoria GPU in Android 12

Questa pagina descrive i vari miglioramenti al calcolo della memoria introdotti in Android 12.

Statistiche DMA-BUF in sysfs

In Android 11 e Android 12, debugfs non può essere montato nelle build utente. Pertanto, le statistiche DMA-BUF sono state aggiunte a sysfs nella directory /sys/kernel/dmabuf/buffers in Android 12.

Percorso Descrizione
/sys/kernel/dmabuf/buffers La directory /sys/kernel/dmabuf/buffers contiene uno snapshot dello stato interno di ogni DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> contiene le statistiche per il DMA-BUF con il numero di inodi univoco <inode_number>.
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name Questo file di sola lettura contiene il nome dell'esportatore DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number>/size Questo file di sola lettura specifica la dimensione del DMA-BUF in byte.

L'API libdmabufinfo analizza le statistiche sysfs DMA-BUF per esporre le statistiche per esportatore e per buffer.

Tieni presente che i driver del kernel che esportano DMA-BUF devono impostare correttamente il campo exp_name di struct dma_buf_export_info sul nome dell'esportatore prima di invocare l'API dma_buf_export() per creare un DMA-BUF. Questo è necessario per libdmabufinfo e lo strumento dmabuf_dump per ricavare le statistiche per esportatore che vengono poi esposte nel report di bug.

Lo strumento dmabuf_dump è stato modificato per restituire queste informazioni con un nuovo argomento, -b.

Statistiche per il framework degli heap DMA-BUF

ION in GKI 2.0 è stato ritirato a favore del framework degli heap DMA-BUF, che fa parte del kernel Linux upstream.

In Android 11 vengono monitorate le seguenti statistiche globali di ION:

  • Dimensione totale delle DMA-BUF esportate da ogni heap ION
  • Dimensione totale della memoria preallocata inutilizzata archiviata da ogni heap ION

In Android 11 non è disponibile un'interfaccia per esporre le statistiche relative all'heap per ION.

La tabella seguente mette a confronto le interfacce delle statistiche ION con le relative controparti per i dispositivi che utilizzano il framework heap DMA-BUF in Android 12.

Android 11 o dispositivi con supporto ION in Android 12 Dispositivi lanciati con heap DMA-BUF in Android 12
Statistiche ION per heap Nessuno Analizzato in base alle statistiche di sistema DMA-BUF
Dimensioni totali dei DMA-BUF esportati /sys/kernel/ion/total_heap_size_kb
(Non include le dimensioni delle DMA-BUF esportate da esportatori non ION)
Analizzata dalle statistiche di sysfs DMA-BUF
(include le dimensioni di tutte le DMA-BUF esportate).
Memoria totale raggruppata per heap /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Migliora la precisione del calcolo della RAM persa

In precedenza, il calcolo della RAM persa veniva eseguito nel seguente modo:

finale lungo lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)

- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()

- kernelUsed - memInfo.getZramTotalSizeKb();

Il componente totalPss includeva l'utilizzo della memoria GPU (restituito dall'interfaccia getMemory() dell'HAL Memtrack). Il componente kernelUsed includeva l'utilizzo totale della memoria DMA-BUF. Tuttavia, per i dispositivi Android, la memoria GPU proveniva da quanto segue:

  • Allocazioni dirette effettuate dal driver della GPU utilizzando l'allocatore di pagine fisiche
  • DMA-BUF mappate nello spazio di indirizzi GPU

Pertanto, i DMA-BUF mappati nella memoria nello spazio degli indirizzi GPU sono stati sottratti due volte al momento del calcolo della RAM persa. Android 12 implementa una soluzione per calcolare le dimensioni dei DMA-BUF mappati nello spazio indirizzi della GPU, il che significa che vengono conteggiate una sola volta nel calcolo della RAM persa.

I dettagli della soluzione sono i seguenti:

  • L'API HAL Memtrack getMemory() quando viene chiamata con PID 0 deve segnalare la memoria privata GPU totale globale per MemtrackType::GL e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • getMemory() quando viene chiamato con PID 0 per un MemtrackType diverso da GL non deve avere esito negativo. Deve invece restituire 0.
  • La soluzione tracepoint/eBPF per la memoria GPU aggiunta in Android 12 tiene conto della memoria GPU totale. Sottraendo la memoria privata della GPU totale dalla memoria GPU totale si ottengono le dimensioni dei DMA-BUF mappati nello spazio degli indirizzi della GPU. Il valore può essere utilizzato per migliorare l'accuratezza dei calcoli della RAM persa tenendo conto correttamente dell'utilizzo della memoria GPU.
  • La memoria GPU privata è inclusa in totalPss nella maggior parte delle implementazioni HAL Memtrack e pertanto deve essere deduplicata prima di rimuoverla da lostRAM.

La soluzione implementata è descritta in dettaglio nella sezione successiva.

Rimuovi la variabilità Memtrack dalla RAM persa

Poiché le implementazioni dell'HAL di Memtrack possono variare da un partner all'altro, la memoria GPU inclusa in totalPSS dell'HAL non è sempre coerente. Per rimuovere la variabilità da lostRAM, la memoria considerata in MemtrackType::GRAPHICS e MemtrackType::GL viene rimossa da totalPss durante il calcolo di lostRAM.

La memoria MemtrackType::GRAPHICS viene rimossa da totalPss e sostituita con la memoria totalExportedDmabuf nel calcolo lostRAM in ActivityManagerService.java come mostrato di seguito:

final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();

. . .

final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;

. . .

// Account unmapped dmabufs as part of the kernel memory allocations
kernelUsed += dmabufUnmapped;

// Replace Memtrack HAL reported Graphics category with mapped dmabufs
totalPss -= totalMemtrackGraphics;
totalPss += dmabufMapped;

La memoria MemtrackType::GL viene rimossa da totalPss e sostituita con la memoria GPU privata (gpuPrivateUsage) nel calcolo di lostRAM in ActivityManagerService.java come mostrato di seguito:

final long gpuUsage = Debug.getGpuTotalUsageKb();

. . .

final long gpuPrivateUsage = Debug.getGpuPrivateMemoryKb();

. . .

// Replace the Memtrack HAL-reported GL category with private GPU allocations.
// Count it as part of the kernel memory allocations.
totalPss -= totalMemtrackGl;
kernelUsed += gpuPrivateUsage;

Calcolo della RAM persa aggiornato

Sia la memoria GPU privata totale sia la memoria buffer DMA esportata totale sono contenute in kernelUsed + totalPss, che viene rimosso da lostRAM. Ciò elimina sia il doppio conteggio sia la variabilità Memtrack dal calcolo della RAM persa.

final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();

Convalida

I test VTS applicano la regola che i dispositivi avviati in Android 12 con un kernel Linux versione 5.4 o successive supportano l'API getGpuDeviceInfo().

Una nuova API HAL Memtrack getGpuDeviceInfo() deve restituire informazioni sul dispositivo GPU in uso.

In questo modo, viene migliorata la conta della memoria e la visibilità dell'utilizzo della memoria della GPU e del buffer DMA. Implementa l'HAL AIDL memtrack per una migliore contabilizzazione della RAM e della memoria persa. Questa funzionalità non dipende dai servizi Google.

Implementazione

Questa funzionalità dipende dall'AIDL Memtrack HAL e le istruzioni per implementarla in Android 12 sono incluse nel codice sotto forma di commenti.

È prevista la conversione di tutti gli HAL HIDL in AIDL nelle release future.

Le seguenti API sono state aggiunte a core/java/android/os/Debug.java:

   /**
     * Return total memory size in kilobytes for exported DMA-BUFs or -1 if
     * the DMA-BUF sysfs stats at /sys/kernel/dmabuf/buffers could not be read.
     *
     * @hide
     */
    public static native long getDmabufTotalExportedKb();

   /**
     * Return memory size in kilobytes allocated for DMA-BUF heap pools or -1 if
     * /sys/kernel/dma_heap/total_pools_kb could not be read.
     *
     * @hide
     */
    public static native long getDmabufHeapPoolsSizeKb();

Per assicurarti che la tua versione funzioni come previsto, integra i tracepoint nei driver della GPU e implementa l'API AIDL memtrack HAL getMemory() per restituire correttamente la memoria privata GPU totale globale quando viene chiamata con PID 0 per MemtrackType::GL e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.