In questa pagina vengono descritti i vari miglioramenti alla contabilità della memoria introdotti in Android 12.
Statistiche DMA-BUF in sysfs
In Android 11 e Android 12, non è possibile eseguire debugfs
montate nelle build dell'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 del
stato interno di ogni DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number> contiene le statistiche per
il 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 le dimensioni del DMA-BUF in byte. |
La libdmabufinfo
L'API analizza le statistiche DMA-BUF sysfs
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.
Questa operazione è necessaria per consentire a libdmabufinfo
e allo strumento dmabuf_dump
di ricavare le statistiche per singolo esportatore,
vengono quindi mostrate nella segnalazione di bug.
Lo strumento dmabuf_dump è stato modificato per stampare 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 heap DMA-BUF. che fa parte del kernel Linux upstream.
In Android 11 vengono monitorate le seguenti statistiche globali di ION:
- Dimensione totale dei DMA-BUF esportati da ogni heap ION
- Dimensioni totali della memoria preallocata inutilizzata memorizzata 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 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 | Analizzati dalle statistiche sysfs DMA-BUF |
Dimensioni totali dei DMA-BUF esportati | /sys/kernel/ion/total_heap_size_kb
(non sono incluse le dimensioni dei DMA-BUF esportati da esportatori non ION) |
Analizzati dalle statistiche sysfs di 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 perdita di RAM 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 dal
getMemory() di Memtrack HAL
a riga di comando). 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 GPU utilizzando l'allocatore di pagine fisiche
- DMA-BUF mappati nello spazio indirizzi della GPU
Di conseguenza, i DMA-BUF mappati dalla 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 Memtrack HAL
getMemory()
quando la chiamata con PID 0 deve indicare la memoria privata totale GPU globale, per MemtrackType::GL e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED. - getMemory() quando viene chiamata con
PID
0
per unMemtrackType
diverso daGL
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 GPU totale dalla memoria GPU totale si ottiene dimensioni delle DMA-BUF mappate nello spazio di indirizzi 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 dell'HAL Memtrack implementazioni e deve quindi essere deduplicata prima di rimuoverla dalostRAM
.
La soluzione implementata è descritta in dettaglio nella sezione successiva.
Rimuovere la variabilità di Memtrack dalla RAM persa
Poiché le implementazioni dell'HAL Memtrack possono variare in base ai 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 di lostRAM
.
La memoria MemtrackType::GRAPHICS
è stata 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
è stata rimossa da totalPss
e sostituita con il
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
. In questo modo viene eliminato 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 che prevede l'avvio di dispositivi con Android 12 con un kernel Linux versione 5.4 o successiva supportano getGpuDeviceInfo() tramite Google Cloud CLI o tramite l'API Compute Engine.
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. Implementare il memtrack AIDL HAL per una migliore perdita di RAM e memoria e la contabilità. 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 come 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 nella GPU
e implementare l'API AIDL memtrack HAL getMemory()
per restituire
la memoria privata totale GPU globale quando la chiamata viene effettuata con PID 0 per MemtrackType::GL
e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.