En esta página, se describen las diversas mejoras en el registro de memoria que se introdujeron en Android 12.
Estadísticas de DMA-BUF en sysfs
En Android 11 y Android 12, debugfs
no se puede montar en compilaciones de usuario. Por lo tanto, las estadísticas de DMA-BUF se agregaron a sysfs
en el directorio /sys/kernel/dmabuf/buffers
en Android 12.
Ruta | Descripción |
---|---|
/sys/kernel/dmabuf/buffers
|
El directorio /sys/kernel/dmabuf/buffers contiene una instantánea del estado interno de cada DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number> contiene las estadísticas del DMA-BUF con el número de inodo único <inode_number> .
|
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name
|
Este archivo de solo lectura contiene el nombre del exportador de DMA-BUF. |
/sys/kernel/dmabuf/buffers/<inode_number>/size
|
Este archivo de solo lectura especifica el tamaño del DMA-BUF en bytes. |
La API de libdmabufinfo
analiza las estadísticas de sysfs
de DMA-BUF para exponer estadísticas por exportador y por búfer.
Ten en cuenta que los controladores de kernel que exportan DMA-BUF deben configurar el campo exp_name
de struct dma_buf_export_info
correctamente en el nombre del exportador antes de invocar la API de dma_buf_export()
para crear un DMA-BUF.
Esto es necesario para que libdmabufinfo
y la herramienta dmabuf_dump
deriven estadísticas por exportador que luego se exponen en bugreport.
Se modificó la herramienta dmabuf_dump para que muestre esta información con un argumento nuevo, -b
.
Estadísticas del framework de los montones de DMA-BUF
ION en GKI 2.0 dejará de estar disponible a favor del framework de montones de DMA-BUF, que forma parte del kernel de Linux upstream.
En Android 11, se realiza un seguimiento de las siguientes estadísticas globales de ION:
- Es el tamaño total de los DMA-BUF exportados por cada montón de ION.
- Es el tamaño total de la memoria preasignada sin usar que almacena cada montón de ION.
No hay una interfaz disponible para exponer estadísticas de montón por ION en Android 11.
En la siguiente tabla, se comparan las interfaces de estadísticas de ION con sus contrapartes para dispositivos que usan el framework de montón DMA-BUF en Android 12.
Android 11 o dispositivos que se lanzan con compatibilidad con ION en Android 12 | Dispositivos que se lanzan con montones de DMA-BUF en Android 12 | |
---|---|---|
Estadísticas de ION por montón | Ninguno | Se analiza a partir de las estadísticas de sysfs de DMA-BUF. |
Tamaño total de los DMA-BUF exportados | /sys/kernel/ion/total_heap_size_kb
(no incluye el tamaño de los DMA-BUF exportados por exportadores que no son de ION) |
Se analiza a partir de las estadísticas de sysfs de DMA-BUF
(incluye el tamaño de todos los DMA-BUF exportados). |
Memoria total agrupada por grupos | /sys/kernel/ion/total_pool_size_kb |
/sys/kernel/dma_heap/total_pool_size_kb |
Mejora la precisión del cálculo de la RAM perdida
Anteriormente, el cálculo de la RAM perdida se realizaba de la siguiente manera:
lostRAM
final largo = memInfo.getTotalSizeKb(
) - (totalPss
- totalSwapPss
)
- memInfo.getFreeSizeKb()
- memInfo.getCachedSizeKb()
- kernelUsed
- memInfo.getZramTotalSizeKb()
;
El componente totalPss
incluía el uso de memoria de la GPU (que muestra la interfaz getMemory() del HAL de Memtrack). El componente kernelUsed
incluía el uso total de memoria de DMA-BUF.
Sin embargo, en el caso de los dispositivos Android, la memoria de la GPU proviene de lo siguiente:
- Asignaciones directas que realiza el controlador de la GPU con el asignador de páginas físicas
- DMA-BUF asignados al espacio de direcciones de la GPU
Por lo tanto, los DMA-BUF que se asignaron a la memoria en el espacio de direcciones de la GPU se restaron dos veces cuando se calculó la RAM perdida. Android 12 implementa una solución para calcular el tamaño de los DMA-BUF asignados en el espacio de direcciones de la GPU, lo que significa que se registra solo una vez en el cálculo de RAM perdida.
Los detalles de la solución son los siguientes:
- Cuando se llama a la API de HAL de Memtrack
getMemory()
con el PID 0, debe informar la memoria privada total global de la GPU para MemtrackType::GL y MemtrackRecord::FLAG_SMAPS_UNACCOUNTED. - getMemory() cuando se llama con
PID
0
para unMemtrackType
que no seaGL
no debe fallar. En su lugar, debe mostrar 0. - La solución de punto de seguimiento de memoria de GPU/eBPF que se agregó en Android 12 tiene en cuenta la memoria total de la GPU. Si se resta la memoria privada total de la GPU de la memoria total de la GPU, se obtiene el tamaño de los DMA-BUF asignados en el espacio de direcciones de la GPU. Luego, se puede usar el valor para mejorar la precisión de los cálculos de RAM perdida, ya que se registra correctamente el uso de la memoria de la GPU.
- La memoria privada de la GPU se incluye en
totalPss
en la mayoría de las implementaciones de HAL de Memtrack y, por lo tanto, se debe anular antes de quitarla delostRAM
.
La solución implementada se detalla en la siguiente sección.
Se quitó la variabilidad de Memtrack de la RAM perdida.
Dado que las implementaciones de HAL de Memtrack pueden variar entre los socios, la memoria de la GPU incluida en totalPSS
del HAL no siempre es coherente. Para quitar la variabilidad de lostRAM
, la memoria registrada en MemtrackType::GRAPHICS
y MemtrackType::GL
se quita de totalPss
durante el cálculo de lostRAM
.
La memoria MemtrackType::GRAPHICS
se quita de totalPss
y se reemplaza por la memoria totalExportedDmabuf
en el cálculo lostRAM
en ActivityManagerService.java , como se muestra a continuación:
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
se quita de totalPss
y se reemplaza por la memoria privada de la GPU (gpuPrivateUsage
) en el cálculo de lostRAM
en ActivityManagerService.java , como se muestra a continuación:
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;
Se actualizó el cálculo de RAM perdida
Tanto la memoria privada total de la GPU como la memoria total del búfer de DMA exportado se encuentran en kernelUsed + totalPss
, que se quita de lostRAM
. Esto elimina el recuento doble y la variabilidad de Memtrack del cálculo de RAM perdida.
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();
Validación
Las pruebas de VTS aplican la regla de que los dispositivos que se inician en Android 12 con un kernel de Linux versión 5.4 o posterior admiten la API de getGpuDeviceInfo().
Una nueva API de HAL de Memtrack getGpuDeviceInfo()
debe mostrar información sobre el dispositivo de GPU en uso.
Esto proporciona una mejor contabilización de la memoria y visibilidad en el uso de la memoria del búfer de DMA y de la GPU. Implementa el HAL de AIDL de memtrack para mejorar el registro de RAM y memoria perdidos. Esta función no depende de los servicios de Google.
Implementación
Esta función depende del HAL de Memtrack de AIDL, y las instrucciones para implementarlo en Android 12 se incluyen en el código como comentarios.
Se planea que todos los HAL de HIDL se conviertan a AIDL en versiones futuras.
Se agregaron las siguientes APIs 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();
Para asegurarte de que tu versión funcione según lo previsto, integra los puntos de seguimiento en los controladores de la GPU y, luego, implementa la API de getMemory()
de HAL de memtrack de AIDL para mostrar correctamente la memoria privada total global de la GPU cuando se llame con PID 0 para MemtrackType::GL y MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.