Android 12에서 DMABUF 및 GPU 메모리 계산 구현

이 페이지에서는 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_infoexp_name 필드를 내보내기 이름으로 올바르게 설정해야 합니다. 이는 libdmabufinfodmabuf_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 에 대해 PID 0 으로 호출될 때 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::GRAPHICSMemtrackType::GL 에서 설명된 메모리는 lostRAM 계산 중에 totalPss 에서 제거됩니다.

MemtrackType::GRAPHICS 메모리는 totalExportedDmabuf 에서 제거되고 아래와 같이 ActivityManagerService.javalostRAM 계산에서 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.javalostRAM 계산에서 개인 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.