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 activar en compilaciones de usuario. Por lo tanto, se agregaron las estadísticas de DMA-BUF a sysfs
en el directorio /sys/kernel/dmabuf/buffers
de 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 de dmabuf_dump
deriven estadísticas por exportador que luego se exponen en el informe de errores.
Se modificó la herramienta dmabuf_dump para generar esta información con un nuevo argumento, -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:
- Tamaño total de los DMA-BUF exportados por cada montón de ION
- Tamaño total de la memoria asignada previamente sin usar almacenada por cada montón de ION
No hay una interfaz disponible para exponer estadísticas del montón por ION en Android 11.
En la siguiente tabla, se comparan las interfaces de estadísticas de ION con sus counterparts 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 | Analizado a partir de las estadísticas de DMA-BUF sysfs |
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 |
Cómo mejorar la precisión del cálculo de la pérdida de RAM
Anteriormente, el cálculo de la pérdida de RAM se realizaba de la siguiente manera:
largo final, lostRAM
= 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 la llama con el PID 0, la API de HAL de Memtrack
getMemory()
debe informar el total global de memoria privada de GPU para MemtrackType::GL y MemtrackRecord::FLAG_SMAPS_UNACCOUNTED. - getMemory() cuando se llama con
PID
0
para unMemtrackType
distinto deGL
no debe fallar. En su lugar, debe mostrar 0. - La solución de punto de seguimiento de memoria de GPU/eBPF agregada en Android 12 representa la memoria total de GPU. Restar la memoria privada total de la GPU de la memoria total de GPU proporciona el tamaño de los DMA-BUF asignados al espacio de direcciones de la GPU. El valor se puede usar para mejorar la precisión de los cálculos de memoria RAM perdidas, ya que se considera correctamente el uso de memoria de la GPU.
- La memoria privada de GPU se incluye en
totalPss
en la mayoría de las implementaciones de HAL de Memtrack y, por lo tanto, se debe anular el duplicado antes de quitarla delostRAM
.
En la siguiente sección, se detalla la solución implementada.
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
, se quita la memoria registrada en MemtrackType::GRAPHICS
y MemtrackType::GL
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 de GPU privada (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 de búfer de DMA exportada total se encuentran en kernelUsed + totalPss
, que se quita de lostRAM
. De esta manera, se elimina la variabilidad del recuento doble y la variabilidad de Memtrack del cálculo de la pérdida de RAM.
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();
Validación
Las pruebas de VTS aplican la regla que establece que los dispositivos que se lanzan en Android 12 con kernel de Linux 5.4 o una versión 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 del búfer de DMA y el uso de la memoria de la GPU. Implementa la HAL del AIDL de memtrack para mejorar la pérdida de RAM y el registro de memoria. Esta función no depende de los servicios de Google.
Implementación
Esta función depende de la HAL del AIDL Memtrack, y las instrucciones para implementarla 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 getMemory()
de la HAL del memtrack del AIDL para mostrar de forma correcta la memoria global total de GPU privada cuando se la llama con PID 0 para MemtrackType::GL y MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.