This page describes the various memory accounting improvements introduced in Android 12.
DMA-BUF statistics in sysfs
In Android 11 and Android 12,
debugfs can’t be
mounted in User builds. So DMA-BUF statistics has been added to
sysfs in the
/sys/kernel/dmabuf/buffers directory in Android 12.
||This read-only file contains the name of the DMA-BUF exporter.|
||This read-only file specifies the size of the DMA-BUF in bytes.|
API parses the DMA-BUF
sysfs stats to expose per-exporter and per-buffer statistics.
Please note that kernel drivers who export DMA-BUFs must set the
struct dma_buf_export_info correctly to the exporter name before
dma_buf_export() API to create a DMA-BUF.
This is required for
libdmabufinfo and the
dmabuf_dump tool to derive per-exporter statistics which
are then exposed in bugreport.
tool has been modified to output this information with a new argument,
Statistics for the DMA-BUF heaps framework
ION in GKI 2.0 is being deprecated in favor of the DMA-BUF heaps framework, which is part of the upstream linux kernel.
The following global ION statistics are tracked in Android 11:
- Total size of DMA-BUFs exported by every ION heap
- Total size of unused pre-allocated memory stored by every ION heap
There is no interface available to expose per-ION heap statistics in Android 11.
The following table compares the ION statistics interfaces with their counterparts for devices that use the DMA-BUF heap framework in Android 12.
|Android 11 or Devices launching with ION support in Android 12||Devices launching with DMA-BUF heaps in Android 12|
|Per-heap ION statistics||None||Parsed from DMA-BUF sysfs stats|
|Total size of DMA-BUFs exported||
(Doesn’t include the size of DMA-BUFs exported by non-ION exporters)
|Parsed from DMA-BUF sysfs stats
(includes the size of all DMA-BUFs exported).
|Total memory pooled by heaps||
Improving the lost RAM calculation accuracy
Previously the lost Ram calculation was done as follows:
memInfo.getTotalSizeKb() - (
totalPss component included the GPU memory usage (returned by the
Memtrack HAL’s getMemory()
kernelUsed component included the total DMA-BUF memory usage.
However, for Android devices, the GPU memory came from the following:
- Direct allocations made by the GPU driver using physical page allocator
- DMA-BUFs mapped into GPU address space
Therefore, DMA-BUFs that were memory-mapped into the GPU address space were subtracted twice when lost RAM was calculated. Android 12 implements a solution to calculate the size of DMA-BUFs mapped into the GPU address space, which means that it’s accounted for only once in the Lost RAM calculation.
The details of the solution are as follows:
- The Memtrack HAL API
getMemory()when called with PID 0 must report the global total GPU-private memory, for MemtrackType::GL and MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
- getMemory() when called with
GLmust not fail. It must instead return 0.
- The GPU memory tracepoint/eBPF solution added in Android 12 accounts for total GPU memory. Subtracting the total GPU private memory from the total GPU memory provides the size of DMA-BUFs mapped into the GPU address space. The value can then be used to improve the accuracy of Lost RAM calculations by correctly accounting for the GPU memory usage.
- The private GPU memory is included in
totalPssin most Memtrack HAL implementations and therefore must be deduplicated before removing it from
The implemented solution is detailed in the next section.
Removing Memtrack variability from lost RAM
Since Memtrack HAL implementations can vary across partners, the GPU memory
totalPSS from the HAL isn't always consistent. To remove the
lostRAM, the memory accounted for in
MemtrackType::GL is removed from
totalPss during the
MemtrackType::GRAPHICS memory is removed from
totalPss and replaced with
totalExportedDmabuf memory in the
lostRAM calculation in
as shown below:
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;
MemtrackType::GL memory is removed from
totalPss and replaced with the
private GPU memory (
lostRAM calculation in
as shown below:
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;
The updated lost RAM calculation
Both the total private GPU memory and the total exported DMA buffer memory are
kernelUsed + totalPss which is removed from
eliminates both double-counting and Memtrack variability from lost RAM
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - kernelUsed - memInfo.getZramTotalSizeKb();
VTS tests enforce the rule that devices launching in Android 12 with a Linux kernel version 5.4 or higher support the getGpuDeviceInfo() API.
A new Memtrack HAL API
getGpuDeviceInfo() must return information about the GPU device in use.
This provides better memory accounting and visibility into DMA buffer and GPU memory usage. Implement the memtrack AIDL HAL for better lost RAM and memory accounting. This feature isn't dependent on Google services.
This feature depends on the AIDL Memtrack HAL, and directions for implementing it in Android 12 are included in the code as comments.
All HIDL HALs are planned to be converted to AIDL in future releases.
The following APIs have been added to
/** * 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();
To ensure your version works as intended, integrate the tracepoints in your GPU
drivers, and implement the AIDL memtrack HAL
getMemory() API to correctly return
the global total GPU-private memory when called with PID 0 for MemtrackType::GL