Questa pagina descrive i vari miglioramenti della contabilizzazione 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 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 le dimensioni 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 richiamare l'API dma_buf_export()
per creare un DMA-BUF.
Questo è necessario per libdmabufinfo
e per lo strumento dmabuf_dump
per derivare statistiche per esportatore che
vengono poi esposte nel report 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 verrà ritirato a favore del framework DMA-BUF heaps, che fa parte del kernel Linux upstream.
In Android 11 vengono monitorate le seguenti statistiche globali ION:
- Dimensione totale dei DMA-BUF esportati da ogni heap ION
- Dimensione totale della memoria preallocata inutilizzata archiviata da ogni heap ION
In Android 11 non è disponibile alcuna interfaccia per esporre le statistiche dell'heap per ION.
La seguente tabella confronta le interfacce delle statistiche ION con le corrispondenti per i dispositivi che utilizzano il framework heap DMA-BUF in Android 12.
Android 11 o dispositivi lanciati con il supporto di ION in Android 12 | Dispositivi lanciati con heap DMA-BUF in Android 12 | |
---|---|---|
Statistiche ION per heap | Nessuno | Analizzato da statistiche sysfs DMA-BUF |
Dimensione totale dei buffer DMA esportati | /sys/kernel/ion/total_heap_size_kb
(non include le dimensioni dei buffer DMA esportati da esportatori non ION) |
Analizzato dalle statistiche sysfs DMA-BUF
(include le dimensioni 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 |
Migliorare l'accuratezza del calcolo della RAM persa
In precedenza, il calcolo della RAM persa veniva eseguito nel seguente modo:
final long 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() di Memtrack HAL). Il componente kernelUsed
includeva l'utilizzo totale della memoria DMA-BUF.
Tuttavia, per i dispositivi Android, la memoria GPU proveniva da:
- Allocazioni dirette effettuate dal driver GPU utilizzando l'allocatore di pagine fisico
- DMA-BUFs mappati nello spazio di indirizzi della GPU
Pertanto, i DMA-BUF mappati nella memoria GPU sono stati sottratti due volte durante il calcolo della RAM persa. Android 12 implementa una soluzione per calcolare le dimensioni dei DMA-BUF mappati nello spazio di indirizzi della GPU, il che significa che vengono conteggiati una sola volta nel calcolo della RAM persa.
I dettagli della soluzione sono i seguenti:
- L'API Memtrack HAL
getMemory()
quando viene chiamata con PID 0 deve segnalare la memoria privata totale della GPU globale per MemtrackType::GL e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED. - getMemory() chiamato con
PID
0
per unMemtrackType
diverso daGL
non deve non riuscire. Deve invece restituire 0. - La soluzione GPU memory tracepoint/eBPF aggiunta in Android 12 tiene conto della memoria GPU totale. Sottraendo la memoria privata totale della GPU dalla memoria GPU totale si ottiene la dimensione dei DMA-BUF mappati nello spazio degli indirizzi della GPU. Il valore può quindi 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 essere rimossa dalostRAM
.
La soluzione implementata è descritta in dettaglio nella sezione successiva.
Rimuovere la variabilità di Memtrack dalla RAM persa
Poiché le implementazioni di Memtrack HAL possono variare a seconda dei partner, la memoria GPU
inclusa in totalPSS
da HAL non è sempre coerente. Per rimuovere la variabilità da lostRAM
, la memoria contabilizzata 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 che la memoria buffer DMA totale esportata sono
contenute in kernelUsed + totalPss
, che viene rimosso da lostRAM
. In questo modo
vengono eliminati sia il doppio conteggio sia la variabilità di 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 secondo cui i dispositivi lanciati in Android 12 con una versione del kernel Linux 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, si ottiene una migliore contabilità della memoria e visibilità sull'utilizzo del buffer DMA e della memoria GPU. Implementa l'HAL AIDL memtrack per una migliore contabilità della RAM e della memoria perse. Questa funzionalità non dipende dai servizi Google.
Implementazione
Questa funzionalità dipende dall'HAL AIDL Memtrack e le istruzioni per implementarla in Android 12 sono incluse nel codice come commenti.
È previsto che tutte le HAL HIDL vengano convertite 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 punti di tracciamento nei driver della GPU e implementa l'API AIDL memtrack HAL getMemory()
per restituire correttamente la memoria privata totale globale della GPU quando viene chiamata con PID 0 per MemtrackType::GL e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.