Esta página descreve as várias melhorias de contabilidade de memória introduzidas no Android 12.
Estatísticas de DMA-BUF no sysfs
No Android 11 e no Android 12, o debugfs
não pode ser
montado em builds do usuário. As estatísticas DMA-BUF foram adicionadas a 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 snapshot 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
|
Esse arquivo somente leitura contém o nome do exportador DMA-BUF. |
/sys/kernel/dmabuf/buffers/<inode_number>/size
|
Esse arquivo somente leitura especifica o tamanho do DMA-BUF em bytes. |
A API libdmabufinfo
analisou as estatísticas sysfs
do DMA-BUF para expor estatísticas por exportador e por buffer.
Os drivers do kernel que exportam DMA-BUFs precisam definir o campo exp_name
de struct dma_buf_export_info
corretamente para o nome do exportador antes
de invocar a API dma_buf_export()
para criar um DMA-BUF.
Isso é necessário para que o libdmabufinfo
e a ferramenta dmabuf_dump
gerem estatísticas por exportador, que
vão ser expostas no relatório do bug.
A ferramenta dmabuf_dump
foi modificada para gerar essas informações com um novo argumento, -b
.
Estatísticas do framework de heaps DMA-BUF
O ION na GKI 2.0 está sendo descontinuado e substituído pelo framework de heaps DMA-BUF, que faz parte do kernel do Linux upstream.
As seguintes estatísticas globais de ION são rastreadas no Android 11:
- Tamanho total de DMA-BUFs exportados por cada heap ION
- Tamanho total da memória pré-alocada não utilizada armazenada por cada heap ION
Não há uma interface disponível para mostrar estatísticas de heap por ION no Android 11.
A tabela abaixo compara as interfaces de estatísticas ION com as equivalentes para dispositivos que usam o framework de heap DMA-BUF no Android 12.
Android 11 ou dispositivos lançados com suporte ao ION no Android 12 | Dispositivos lançados com heaps DMA-BUF no Android 12 | |
---|---|---|
Estatísticas ION por heap | Nenhum | Analisado das estatísticas sysfs de DMA-BUF |
Tamanho total dos DMA-BUFs exportados | /sys/kernel/ion/total_heap_size_kb
(não inclui o tamanho de DMA-BUFs exportados por exportadores não ION) |
Analisado a partir das estatísticas do sysfs da DMA-BUF
(inclui o tamanho de todas as DMA-BUFs exportadas). |
Memória total agrupada por heaps | /sys/kernel/ion/total_pool_size_kb |
/sys/kernel/dma_heap/total_pool_size_kb |
Melhorar a precisão do cálculo de RAM perdida
Anteriormente, o cálculo de RAM perdida era feito da seguinte maneira:
lostRAM
longo final = 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()
da HAL Memtrack. O componente kernelUsed
incluiu o uso total de memória DMA-BUF.
No entanto, para dispositivos Android, a memória da GPU veio do seguinte:
- Alocações diretas feitas pelo driver da GPU usando o alocador de páginas físicas
- DMA-BUFs mapeados no espaço de endereço da GPU
Portanto, os DMA-BUFs que foram mapeados na memória para o 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 Memtrack HAL
getMemory()
, quando chamada com PID 0, precisa informar a memória global total privada da GPU para MemtrackType::GL e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED. - getMemory() quando chamado com
PID
0
para umaMemtrackType
diferente deGL
não pode falhar. Em vez disso, ele deve retornar 0. - A solução de tracepoint de memória da GPU/eBPF adicionada no Android 12 representa 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 ser usado para melhorar a precisão dos cálculos de RAM perdida, considerando corretamente o uso da memória da GPU.
- A memória privada da GPU é incluída em
totalPss
na maioria das implementações do HAL do Memtrack e, portanto, precisa ser desduplicada antes de ser removida delostRAM
.
A solução implementada está detalhada na próxima seção.
Remover a variabilidade do Memtrack da RAM perdida
Como as implementações da HAL da Memtrack podem variar de acordo com o parceiro, a memória da GPU
incluída no totalPSS
da 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 de 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 de totalPss
e substituída pela
memória de GPU privada (gpuPrivateUsage
) no cálculo de lostRAM
em
ActivityManagerService.java ,
como 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;
Atualização do cálculo de RAM perdida
A memória de buffer DMA exportada total e a memória de GPU privada total estão
contidas em kernelUsed + totalPss
, que é removida de lostRAM
. Isso
elimina a contagem dupla e a variabilidade do Memtrack do cálculo de RAM
perdida.
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 iniciados no Android 12 com um kernel do Linux versão 5.4 ou mais recente oferecem suporte à API getGpuDeviceInfo().
Uma nova API HAL do Memtrack getGpuDeviceInfo()
precisa retornar informações sobre o dispositivo de GPU em uso.
Isso melhora a contabilidade da memória e a visibilidade do buffer de DMA e do uso de memória da GPU. Implementamos o HAL de AIDL do memtrack para melhorar a contabilidade de RAM e memória perdida. Esse recurso não depende dos Serviços do Google.
Implementação
Esse recurso depende do HAL do AIDL Memtrack, e as instruções para implementá-lo no Android 12 estão incluídas no código como comentários.
Todas as HALs de HIDL serão convertidas em 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 a versão funcione conforme o esperado, integre os tracepoints nos drivers de GPU
e implemente a API AIDL memtrack HAL getMemory()
para retornar corretamente
a memória global total global da GPU quando chamada com o PID 0 para MemtrackType::GL
e MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.