Implementa DMABUF e la contabilità della memoria GPU in Android 12

Questa pagina descrive i vari miglioramenti alla contabilità della memoria introdotti in Android 12.

Statistiche DMA-BUF in sysfs

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

Sentiero Descrizione
/sys/kernel/dmabuf/buffers La directory /sys/kernel/dmabuf/buffers contiene un'istantanea dello stato interno di ogni DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> contiene le statistiche per DMA-BUF con il numero di inode 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 statistiche per esportatore e per buffer.

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

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 deprecato a favore del framework heap DMA-BUF , che fa parte del kernel Linux upstream.

Le seguenti statistiche ION globali vengono monitorate in Android 11:

  • Dimensione totale dei DMA-BUF esportati da ogni heap ION
  • Dimensione totale della memoria pre-allocata inutilizzata archiviata da ogni heap ION

Non è disponibile alcuna interfaccia per esporre le statistiche dell'heap per ION in Android 11.

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

Android 11 o dispositivi che si avviano con supporto ION in Android 12 Dispositivi che si avviano con heap DMA-BUF in Android 12
Statistiche ION per heap Nessuno Analizzato dalle statistiche sysfs DMA-BUF
Dimensione totale dei DMA-BUF esportati /sys/kernel/ion/total_heap_size_kb
(Non include la dimensione dei DMA-BUF esportati da esportatori non ION)
Analizzato dalle statistiche sysfs DMA-BUF
(include la dimensione di tutti i DMA-BUF esportati).
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 come segue:

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

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

- kernelUsed - memInfo.getZramTotalSizeKb() ;

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

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

Pertanto, i DMA-BUF mappati in memoria nello spazio degli indirizzi della GPU sono stati sottratti due volte quando è stata calcolata la RAM persa. Android 12 implementa una soluzione per calcolare la dimensione dei DMA-BUF mappati nello spazio degli indirizzi della GPU, il che significa che viene preso in considerazione solo una volta nel calcolo della RAM persa.

I dettagli della soluzione sono i seguenti:

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

La soluzione implementata è dettagliata nella sezione successiva.

Rimuovi la variabilità di Memtrack dalla RAM persa

Poiché le implementazioni di Memtrack HAL possono variare tra i partner, la memoria GPU inclusa in totalPSS dall'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 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 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;

Aggiornato il calcolo della RAM persa

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

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

Validazione

I test VTS applicano la regola secondo cui i dispositivi avviati in Android 12 con una versione del kernel Linux 5.4 o successiva supportano l'API getGpuDeviceInfo() .

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

Ciò fornisce una migliore contabilità della memoria e visibilità sul buffer DMA e sull'utilizzo della memoria della GPU. Implementa il memtrack AIDL HAL per una migliore RAM persa e un migliore conteggio della memoria. Questa funzionalità non dipende dai servizi Google.

Implementazione

Questa funzionalità dipende dall'AIDL Memtrack HAL e le indicazioni per implementarla in Android 12 sono incluse nel codice come commenti.

È prevista la conversione di tutti gli HAL HIDL in AIDL nelle versioni 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 garantire che la tua versione funzioni come previsto, integra i tracepoint nei driver GPU e implementa l'API AIDL memtrack HAL getMemory() per restituire correttamente la memoria privata GPU totale globale quando chiamata con PID 0 per MemtrackType::GL e MemtrackRecord:: FLAG_SMAPS_UNACCOUNTED.