Esta página describe las diversas mejoras en la contabilidad de la memoria introducidas en Android 12.
Estadísticas DMA-BUF en sysfs
En Android 11 y Android 12, debugfs
no se pueden montar en compilaciones de usuarios. Por lo tanto, se agregaron estadísticas DMA-BUF a sysfs
en el directorio /sys/kernel/dmabuf/buffers
en Android 12.
Sendero | 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 de DMA-BUF con el número de inodo exclusivo <inode_number> . |
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name | Este archivo de solo lectura contiene el nombre del exportador 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 libdmabufinfo
analiza las estadísticas de DMA-BUF sysfs
para exponer estadísticas por exportador y por búfer.
Tenga en cuenta que los controladores del kernel que exportan DMA-BUF deben establecer correctamente el campo exp_name
de struct dma_buf_export_info
en el nombre del exportador antes de invocar la API dma_buf_export()
para crear un DMA-BUF. Esto es necesario para que libdmabufinfo
y la herramienta dmabuf_dump
obtengan estadísticas por exportador que luego se exponen en bugreport.
La herramienta dmabuf_dump se ha modificado para generar esta información con un nuevo argumento, -b
.
Estadísticas para el marco de pilas DMA-BUF
ION en GKI 2.0 está en desuso en favor del marco de almacenamiento dinámico DMA-BUF , que es parte del kernel de Linux ascendente.
Las siguientes estadísticas globales de ION se rastrean en Android 11:
- Tamaño total de DMA-BUF exportados por cada montón de ION
- Tamaño total de la memoria preasignada no utilizada almacenada por 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 marco de almacenamiento dinámico DMA-BUF en Android 12.
Android 11 o dispositivos que se inician con compatibilidad con ION en Android 12 | Dispositivos que se inician con pilas DMA-BUF en Android 12 | |
---|---|---|
Estadísticas de ION por pila | Ninguna | Analizado a partir de las estadísticas de DMA-BUF sysfs |
Tamaño total de DMA-BUF exportados | /sys/kernel/ion/total_heap_size_kb (No incluye el tamaño de DMA-BUF exportados por exportadores que no son ION) | Analizado a partir de las estadísticas de DMA-BUF sysfs (incluye el tamaño de todos los DMA-BUF exportados). |
Memoria total agrupada por montones | /sys/kernel/ion/total_pool_size_kb | /sys/kernel/dma_heap/total_pool_size_kb |
Mejora de la precisión del cálculo de RAM perdida
Anteriormente, el cálculo de Ram perdido se hacía de la siguiente manera:
RAM perdida larga final = lostRAM
memInfo.getTotalSizeKb(
) - ( totalPss
- totalSwapPss
)
- memInfo.getFreeSizeKb()
- memInfo.getCachedSizeKb()
- kernelUsed
- memInfo.getZramTotalSizeKb()
;
El componente totalPss
incluía el uso de memoria GPU (devuelto por la interfaz getMemory() de Memtrack HAL). El componente kernelUsed
incluía el uso total de memoria DMA-BUF. Sin embargo, para los dispositivos Android, la memoria GPU provino de lo siguiente:
- Asignaciones directas realizadas por el controlador de GPU utilizando el asignador de página físico
- DMA-BUF asignados al espacio de direcciones de la GPU
Por lo tanto, los DMA-BUF que se mapearon en la memoria en el espacio de direcciones de la GPU se restaron dos veces cuando se calculó la pérdida de RAM. Android 12 implementa una solución para calcular el tamaño de los DMA-BUF asignados al espacio de direcciones de la GPU, lo que significa que solo se tiene en cuenta una vez en el cálculo de RAM perdida.
Los detalles de la solución son los siguientes:
- La API
getMemory()
de HAL de Memtrack cuando se llama con PID 0 debe informar la memoria privada de GPU total global, 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 devolver 0. - La solución eBPF/punto de seguimiento de la memoria de la GPU agregada en Android 12 representa la memoria total de la GPU. Restar la memoria privada total de la GPU de la memoria total de la GPU proporciona el tamaño de los DMA-BUF asignados al espacio de direcciones de la GPU. Luego, el valor se puede usar para mejorar la precisión de los cálculos de RAM perdida al contabilizar correctamente el uso de la memoria de la GPU.
- La memoria GPU privada está incluida en
totalPss
en la mayoría de las implementaciones de Memtrack HAL y, por lo tanto, debe desduplicarse antes de eliminarla delostRAM
.
La solución implementada se detalla en la siguiente sección.
Eliminación de la variabilidad de Memtrack de la memoria RAM perdida
Dado que las implementaciones de HAL de Memtrack pueden variar entre socios, la memoria GPU incluida en totalPSS
de HAL no siempre es consistente. Para eliminar la variabilidad de lostRAM
, la memoria contabilizada en MemtrackType::GRAPHICS
y MemtrackType::GL
se elimina de totalPss
durante el cálculo de lostRAM
.
La memoria MemtrackType::GRAPHICS
se elimina de totalPss
y se reemplaza con la memoria totalExportedDmabuf
en el cálculo de 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 elimina de totalPss
y se reemplaza con 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;
El cálculo actualizado de RAM perdida
Tanto la memoria de GPU privada total como la memoria de búfer de DMA exportada total están contenidas en kernelUsed + totalPss
que se elimina de lostRAM
. Esto elimina tanto el conteo doble como la variabilidad de Memtrack del cálculo de RAM perdido.
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 superior son compatibles con la API getGpuDeviceInfo() .
Una nueva API HAL de getGpuDeviceInfo()
debe devolver información sobre el dispositivo GPU en uso.
Esto proporciona una mejor contabilidad de la memoria y visibilidad del búfer de DMA y el uso de la memoria de la GPU. Implemente el memtrack AIDL HAL para mejorar la pérdida de RAM y la contabilidad de la memoria. Esta función no depende de los servicios de Google.
Implementación
Esta función depende de AIDL Memtrack HAL , y las instrucciones para implementarla en Android 12 se incluyen en el código como comentarios.
Está previsto que todas las HAL de HIDL se conviertan a AIDL en versiones futuras.
Se agregaron las siguientes API 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 asegurarse de que su versión funcione según lo previsto, integre los puntos de seguimiento en los controladores de su GPU e implemente la API getMemory()
de AIDL memtrack HAL para devolver correctamente la memoria privada de GPU total global cuando se llame con PID 0 para MemtrackType::GL y MemtrackRecord:: FLAG_SMAPS_UNACCOUNTED.