Implementa el registro de memoria de DMABUF y GPU en Android 12

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, 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 el 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 libdmabufinfo La API analiza las estadísticas de sysfs de DMA-BUF para exponer las estadísticas por exportador y por búfer.

Ten en cuenta que los controladores de kernel que exportan DMA-BUF deben establecer el exp_name de struct dma_buf_export_info correctamente al nombre del exportador antes 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.

El dmabuf_dump se modificó para mostrar 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
  • 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 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 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)
Análisis de las estadísticas del sistema DMA-BUF
(incluye el tamaño de todos los DMA-BUF exportados).
Memoria total agrupada por montón /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:

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 provenía de lo siguiente:

  • Asignaciones directas que realiza el controlador de GPU mediante un asignador de página físico
  • 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 un MemtrackType que no sea GL 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. El valor se puede usar para mejorar la precisión de los cálculos de pérdida de RAM teniendo en cuenta correctamente el uso de 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 de lostRAM.

La solución implementada se detalla en la siguiente sección.

Quita la variabilidad de Memtrack de la memoria 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;

Se quitó la memoria MemtrackType::GL de totalPss y se reemplazó por 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;

Actualización del cálculo de la pérdida de RAM

Tanto la memoria de GPU privada total como la memoria de búfer de DMA exportada se incluido en kernelUsed + totalPss, que se quitó de lostRAM. Esta Elimina la variabilidad de recuento doble y Memtrack de la memoria RAM perdida. cálculo.

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 del búfer de DMA y la GPU. el uso de memoria. 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 de la HAL del Memtrack de AIDL. 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 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.