이 페이지에서는 Android 12에 도입된 다양한 메모리 계정 개선 사항에 대해 설명합니다.
sysfs의 DMA-BUF 통계
Android 11 및 Android 12에서는 사용자 빌드에 debugfs 를 탑재할 수 없습니다. 따라서 DMA-BUF 통계는 Android 12의 /sys/kernel/dmabuf/buffers 디렉터리에 있는 sysfs 에 추가되었습니다.
| 길 | 설명 |
|---|---|
/sys/kernel/dmabuf/buffers | /sys/kernel/dmabuf/buffers 디렉토리에는 모든 DMA-BUF의 내부 상태에 대한 스냅샷이 들어 있습니다. /sys/kernel/dmabuf/buffers/<inode_number> 에는 고유한 inode 번호가 <inode_number> 인 DMA-BUF에 대한 통계가 포함되어 있습니다. |
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name | 이 읽기 전용 파일에는 DMA-BUF 내보내기의 이름이 포함되어 있습니다. |
/sys/kernel/dmabuf/buffers/<inode_number>/size | 이 읽기 전용 파일은 DMA-BUF의 크기를 바이트 단위로 지정합니다. |
libdmabufinfo API는 DMA-BUF sysfs 통계를 구문 분석하여 내보내기별 및 버퍼별 통계를 표시합니다.
DMA-BUF를 내보내는 커널 드라이버는 DMA-BUF를 생성하기 위해 dma_buf_export() API를 호출하기 전에 struct dma_buf_export_info 의 exp_name 필드를 내보내기 이름으로 올바르게 설정해야 합니다. 이는 libdmabufinfo 및 dmabuf_dump 도구가 버그 보고서에 노출되는 내보내기별 통계를 도출하는 데 필요합니다.
dmabuf_dump 도구는 새로운 인수 -b 와 함께 이 정보를 출력하도록 수정되었습니다.
DMA-BUF 힙 프레임워크에 대한 통계
GKI 2.0의 ION은 업스트림 Linux 커널의 일부인 DMA-BUF 힙 프레임워크 를 위해 더 이상 사용되지 않습니다.
다음 글로벌 ION 통계는 Android 11에서 추적됩니다.
- 모든 ION 힙에서 내보낸 DMA-BUF의 총 크기
- 모든 ION 힙에 저장된 사용되지 않은 사전 할당된 메모리의 총 크기
Android 11에는 ION별 힙 통계를 표시하는 데 사용할 수 있는 인터페이스가 없습니다.
다음 표에서는 ION 통계 인터페이스를 Android 12에서 DMA-BUF 힙 프레임워크를 사용하는 기기의 해당 인터페이스와 비교합니다.
| Android 11 또는 Android 12에서 ION 지원으로 출시되는 기기 | Android 12에서 DMA-BUF 힙으로 출시되는 기기 | |
|---|---|---|
| 힙당 ION 통계 | 없음 | DMA-BUF sysfs 통계 에서 구문 분석 |
| 내보낸 DMA-BUF의 총 크기 | /sys/kernel/ion/total_heap_size_kb(비 ION 내보내기에서 내보낸 DMA-BUF의 크기는 포함하지 않음) | DMA-BUF sysfs 통계에서 구문 분석 (내보낸 모든 DMA-BUF의 크기 포함). |
| 힙에서 풀링된 총 메모리 | /sys/kernel/ion/total_pool_size_kb | /sys/kernel/dma_heap/total_pool_size_kb |
손실된 RAM 계산 정확도 개선
이전에는 손실된 램 계산이 다음과 같이 수행되었습니다.
최종 long lostRAM = memInfo.getTotalSizeKb( ) - ( totalPss - totalSwapPss )
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb() ;
totalPss 구성 요소에는 GPU 메모리 사용량이 포함되었습니다(Memtrack HAL의 getMemory() 인터페이스에서 반환됨). kernelUsed 구성 요소에는 총 DMA-BUF 메모리 사용량이 포함되었습니다. 그러나 Android 장치의 경우 GPU 메모리는 다음에서 가져왔습니다.
- 물리적 페이지 할당자를 사용하여 GPU 드라이버에서 직접 할당
- GPU 주소 공간에 매핑된 DMA-BUF
따라서 GPU 주소 공간에 메모리 매핑된 DMA-BUF는 손실된 RAM을 계산할 때 두 번 뺍니다. Android 12는 GPU 주소 공간에 매핑된 DMA-BUF의 크기를 계산하는 솔루션을 구현합니다. 즉, Lost RAM 계산에서 한 번만 고려됩니다.
솔루션의 세부 사항은 다음과 같습니다.
- PID 0으로 호출될 때 Memtrack HAL API
getMemory()는 MemtrackType::GL 및 MemtrackRecord::FLAG_SMAPS_UNACCOUNTED에 대한 전역 총 GPU 전용 메모리를 보고해야 합니다. -
GL이외의MemtrackType에 대해PID0으로 호출될 때 getMemory()가 실패해서는 안 됩니다. 대신 0을 반환해야 합니다. - Android 12에 추가된 GPU 메모리 tracepoint/eBPF 솔루션은 총 GPU 메모리를 설명합니다. 총 GPU 메모리에서 총 GPU 전용 메모리를 빼면 GPU 주소 공간에 매핑된 DMA-BUF의 크기가 제공됩니다. 그런 다음 이 값을 사용하여 GPU 메모리 사용량을 올바르게 계산하여 Lost RAM 계산의 정확도를 높일 수 있습니다.
- 개인 GPU 메모리는 대부분의 Memtrack HAL 구현에서
totalPss에 포함되어 있으므로lostRAM에서 제거하기 전에 중복 제거해야 합니다.
구현된 솔루션은 다음 섹션에서 자세히 설명합니다.
손실된 RAM에서 Memtrack 변동성 제거
Memtrack HAL 구현은 파트너에 따라 다를 수 있으므로 HAL의 totalPSS 에 포함된 GPU 메모리가 항상 일관성이 있는 것은 아닙니다. lostRAM 에서 변동성을 제거하기 위해 MemtrackType::GRAPHICS 및 MemtrackType::GL 에서 설명된 메모리는 lostRAM 계산 중에 totalPss 에서 제거됩니다.
MemtrackType::GRAPHICS 메모리는 totalExportedDmabuf 에서 제거되고 아래와 같이 ActivityManagerService.java 의 lostRAM 계산에서 totalPss 메모리로 대체됩니다.
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 메모리는 totalPss 에서 제거되고 아래와 같이 ActivityManagerService.java 의 lostRAM 계산에서 개인 GPU 메모리( gpuPrivateUsage )로 대체됩니다.
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;
업데이트된 손실된 RAM 계산
총 개인 GPU 메모리와 총 내보낸 DMA 버퍼 메모리는 모두 kernelUsed + totalPss 에 포함되어 있으며 이는 lostRAM 에서 제거됩니다. 이것은 손실된 RAM 계산에서 이중 계산 및 Memtrack 변동성을 모두 제거합니다.
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();
확인
VTS 테스트는 Android 12에서 Linux 커널 버전 5.4 이상을 실행하는 기기가 getGpuDeviceInfo() API를 지원한다는 규칙을 적용합니다.
새로운 Memtrack HAL API getGpuDeviceInfo() 는 사용 중인 GPU 장치에 대한 정보를 반환해야 합니다.
이는 DMA 버퍼 및 GPU 메모리 사용에 대한 더 나은 메모리 계정 및 가시성을 제공합니다. 더 나은 손실된 RAM 및 메모리 계정을 위해 memtrack AIDL HAL을 구현합니다. 이 기능은 Google 서비스에 종속되지 않습니다.
구현
이 기능은 AIDL Memtrack HAL 에 따라 다르며 Android 12에서 이를 구현하기 위한 지침이 코드에 주석으로 포함되어 있습니다.
모든 HIDL HAL은 향후 릴리스에서 AIDL로 변환될 예정입니다.
core/java/android/os/Debug.java 에 다음 API가 추가되었습니다.
/**
* 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();
버전이 의도한 대로 작동하는지 확인하려면 GPU 드라이버에 추적점을 통합하고 AIDL memtrack HAL getMemory() API를 구현하여 MemtrackType::GL 및 MemtrackRecord:에 대해 PID 0으로 호출할 때 전체 GPU 전용 메모리를 올바르게 반환합니다. FLAG_SMAPS_UNACCOUNTED.