Esta página descreve as diversas melhorias de contabilidade de memória introduzidas no Android 12.
Estatísticas DMA-BUF em sysfs
No Android 11 e no Android 12, debugfs
não podem ser montados em builds de usuário. Portanto, as estatísticas DMA-BUF foram adicionadas ao sysfs
no diretório /sys/kernel/dmabuf/buffers
no Android 12.
Caminho | Descrição |
---|---|
/sys/kernel/dmabuf/buffers | O diretório /sys/kernel/dmabuf/buffers contém um instantâneo do estado interno de cada DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> contém as estatísticas para o DMA-BUF com o número de inode exclusivo <inode_number> . |
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name | Este arquivo somente leitura contém o nome do exportador DMA-BUF. |
/sys/kernel/dmabuf/buffers/<inode_number>/size | Este arquivo somente leitura especifica o tamanho do DMA-BUF em bytes. |
A API libdmabufinfo
analisa as estatísticas sysfs
DMA-BUF para expor estatísticas por exportador e por buffer.
Observe que os drivers do kernel que exportam DMA-BUFs devem definir o campo exp_name
da struct dma_buf_export_info
corretamente para o nome do exportador antes de invocar a API dma_buf_export()
para criar um DMA-BUF. Isto é necessário para que libdmabufinfo
e a ferramenta dmabuf_dump
obtenham estatísticas por exportador que são então expostas no relatório de bug.
A ferramenta dmabuf_dump foi modificada para gerar essas informações com um novo argumento, -b
.
Estatísticas para a estrutura de heaps DMA-BUF
O ION no GKI 2.0 está sendo descontinuado em favor da estrutura de heaps DMA-BUF , que faz parte do kernel Linux upstream.
As seguintes estatísticas globais do ION são rastreadas no Android 11:
- Tamanho total de DMA-BUFs exportados por cada heap ION
- Tamanho total de memória pré-alocada não utilizada armazenada por cada heap ION
Não há interface disponível para expor estatísticas de heap por ION no Android 11.
A tabela a seguir compara as interfaces estatísticas do ION com suas contrapartes para dispositivos que usam a estrutura de heap DMA-BUF no Android 12.
Android 11 ou dispositivos lançados com suporte ION no Android 12 | Dispositivos lançados com pilhas DMA-BUF no Android 12 | |
---|---|---|
Estatísticas ION por heap | Nenhum | Analisado a partir de estatísticas sysfs DMA-BUF |
Tamanho total de DMA-BUFs exportados | /sys/kernel/ion/total_heap_size_kb (Não inclui o tamanho dos DMA-BUFs exportados por exportadores não-ION) | Analisado a partir de estatísticas sysfs DMA-BUF (inclui o tamanho de todos os DMA-BUFs exportados). |
Memória total agrupada por heaps | /sys/kernel/ion/total_pool_size_kb | /sys/kernel/dma_heap/total_pool_size_kb |
Melhore a precisão do cálculo de RAM perdida
Anteriormente o cálculo da RAM perdida era feito da seguinte forma:
final longo lostRAM
= memInfo.getTotalSizeKb(
) - ( totalPss
- totalSwapPss
)
- memInfo.getFreeSizeKb()
- memInfo.getCachedSizeKb()
- kernelUsed
- memInfo.getZramTotalSizeKb()
;
O componente totalPss
incluía o uso de memória da GPU (retornado pela interface getMemory() do Memtrack HAL). O componente kernelUsed
incluiu o uso total de memória DMA-BUF. No entanto, para dispositivos Android, a memória GPU veio do seguinte:
- Alocações diretas feitas pelo driver GPU usando alocador de página física
- DMA-BUFs mapeados no espaço de endereço GPU
Portanto, os DMA-BUFs mapeados na memória no espaço de endereço da GPU foram subtraídos duas vezes quando a RAM perdida foi calculada. O Android 12 implementa uma solução para calcular o tamanho dos DMA-BUFs mapeados no espaço de endereço da GPU, o que significa que ele é contabilizado apenas uma vez no cálculo de RAM perdida.
Os detalhes da solução são os seguintes:
- A API
getMemory()
do Memtrack HAL quando chamada com PID 0 deve relatar o total global de memória privada da GPU, para MemtrackType::GL e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED. - getMemory() quando chamado com
PID
0
para umMemtrackType
diferente deGL
não deve falhar. Em vez disso, deve retornar 0. - A solução tracepoint/eBPF de memória GPU adicionada no Android 12 contabiliza a memória total da GPU. Subtrair a memória privada total da GPU da memória total da GPU fornece o tamanho dos DMA-BUFs mapeados no espaço de endereço da GPU. O valor pode então ser usado para melhorar a precisão dos cálculos de RAM perdida, contabilizando corretamente o uso de memória da GPU.
- A memória GPU privada está incluída no
totalPss
na maioria das implementações HAL do Memtrack e, portanto, deve ser desduplicada antes de ser removida dalostRAM
.
A solução implementada é detalhada na próxima seção.
Remova a variabilidade do Memtrack da RAM perdida
Como as implementações do Memtrack HAL podem variar entre os parceiros, a memória GPU incluída no totalPSS
do HAL nem sempre é consistente. Para remover a variabilidade de lostRAM
, a memória contabilizada em MemtrackType::GRAPHICS
e MemtrackType::GL
é removida de totalPss
durante o cálculo lostRAM
.
A memória MemtrackType::GRAPHICS
é removida de totalPss
e substituída pela memória totalExportedDmabuf
no cálculo lostRAM
em ActivityManagerService.java conforme mostrado abaixo:
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;
A memória MemtrackType::GL
é removida do totalPss
e substituída pela memória GPU privada ( gpuPrivateUsage
) no cálculo lostRAM
em ActivityManagerService.java conforme mostrado abaixo:
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;
Cálculo de RAM perdida atualizado
Tanto a memória GPU privada total quanto a memória buffer DMA exportada total estão contidas em kernelUsed + totalPss
que é removido de lostRAM
. Isso elimina a contagem dupla e a variabilidade do Memtrack devido ao cálculo de perda de RAM.
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();
Validação
Os testes VTS aplicam a regra de que os dispositivos lançados no Android 12 com um kernel Linux versão 5.4 ou superior suportam a API getGpuDeviceInfo() .
Uma nova API Memtrack HAL getGpuDeviceInfo()
deve retornar informações sobre o dispositivo GPU em uso.
Isso fornece melhor contabilidade de memória e visibilidade do buffer DMA e do uso de memória da GPU. Implemente o memtrack AIDL HAL para melhor RAM perdida e contabilidade de memória. Este recurso não depende dos serviços do Google.
Implementação
Esse recurso depende do AIDL Memtrack HAL e as instruções para implementá-lo no Android 12 estão incluídas no código como comentários.
Todos os HALs HIDL estão planejados para serem convertidos para AIDL em versões futuras.
As seguintes APIs foram adicionadas 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 garantir que sua versão funcione conforme o esperado, integre os pontos de rastreamento em seus drivers de GPU e implemente a API AIDL memtrack HAL getMemory()
para retornar corretamente o total global de memória privada da GPU quando chamado com PID 0 para MemtrackType::GL e MemtrackRecord:: FLAG_SMAPS_UNACCOUNTED.