Zaimplementuj rozliczanie pamięci DMABUF i GPU w systemie Android 12

Na tej stronie opisano różne ulepszenia rozliczania pamięci wprowadzone w systemie Android 12.

Statystyki DMA-BUF w sysfs

W systemach Android 11 i Android 12 debugfs nie można montować w kompilacjach użytkownika. Dlatego statystyki DMA-BUF zostały dodane do sysfs w katalogu /sys/kernel/dmabuf/buffers w systemie Android 12.

Ścieżka Opis
/sys/kernel/dmabuf/buffers Katalog /sys/kernel/dmabuf/buffers zawiera migawkę wewnętrznego stanu każdego DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> zawiera statystyki dla DMA-BUF z unikalnym numerem i-węzła <inode_number> .
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name Ten plik tylko do odczytu zawiera nazwę eksportera DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number>/size Ten plik tylko do odczytu określa rozmiar DMA-BUF w bajtach.

Interfejs API libdmabufinfo analizuje statystyki sysfs DMA-BUF, aby wyświetlić statystyki według eksportera i bufora.

Należy pamiętać, że sterowniki jądra, które eksportują DMA-BUF, muszą poprawnie ustawić pole exp_name struct dma_buf_export_info na nazwę eksportera przed wywołaniem funkcji API dma_buf_export() w celu utworzenia DMA-BUF. Jest to wymagane, aby libdmabufinfo i narzędzie dmabuf_dump mogły uzyskać statystyki dotyczące poszczególnych eksporterów, które następnie są prezentowane w raporcie o błędach.

Narzędzie dmabuf_dump zostało zmodyfikowane tak, aby wyświetlać te informacje z nowym argumentem -b .

Statystyki dla struktury stert DMA-BUF

ION w GKI 2.0 jest przestarzały na rzecz struktury stert DMA-BUF , która jest częścią jądra Linuksa.

W systemie Android 11 śledzone są następujące globalne statystyki ION:

  • Całkowity rozmiar DMA-BUF eksportowanych przez każdą stertę ION
  • Całkowity rozmiar niewykorzystanej, wstępnie przydzielonej pamięci przechowywanej przez każdą stertę ION

W systemie Android 11 nie jest dostępny interfejs umożliwiający wyświetlenie statystyk sterty na ION.

Poniższa tabela porównuje interfejsy statystyczne ION z ich odpowiednikami dla urządzeń korzystających ze struktury sterty DMA-BUF w systemie Android 12.

Android 11 lub Urządzenia uruchamiane z obsługą ION w Androidzie 12 Urządzenia uruchamiane ze stertami DMA-BUF w systemie Android 12
Statystyki ION na stertę Nic Przeanalizowano na podstawie statystyk sysfs DMA-BUF
Całkowity rozmiar wyeksportowanych plików DMA-BUF /sys/kernel/ion/total_heap_size_kb
(Nie obejmuje wielkości DMA-BUF eksportowanych przez eksporterów spoza ION)
Przeanalizowano na podstawie statystyk sysfs DMA-BUF
(obejmuje rozmiar wszystkich eksportowanych DMA-BUF).
Całkowita pamięć zgromadzona przez sterty /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Popraw dokładność obliczeń utraconej pamięci RAM

Poprzednio obliczenia utraconej pamięci RAM wykonywano w następujący sposób:

końcowa długa lostRAM = memInfo.getTotalSizeKb( ) - ( totalPss - totalSwapPss )

- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()

- kernelUsed - memInfo.getZramTotalSizeKb() ;

Komponent totalPss uwzględniał wykorzystanie pamięci GPU (zwracane przez interfejs getMemory() Memtrack HAL). Komponent kernelUsed uwzględniał całkowite wykorzystanie pamięci DMA-BUF. Jednak w przypadku urządzeń z Androidem pamięć GPU pochodziła z następujących źródeł:

  • Bezpośrednie alokacje dokonywane przez sterownik GPU przy użyciu fizycznego alokatora stron
  • DMA-BUF mapowane na przestrzeń adresową GPU

Dlatego też DMA-BUF, które zostały zmapowane w pamięci w przestrzeni adresowej GPU, zostały odjęte dwukrotnie podczas obliczania utraconej pamięci RAM. W Androidzie 12 zaimplementowano rozwiązanie obliczające wielkość DMA-BUF mapowanych w przestrzeń adresową GPU, co oznacza, że ​​jest ona uwzględniana tylko raz w kalkulacji utraconej pamięci RAM.

Szczegóły rozwiązania są następujące:

  • Funkcja getMemory() API Memtrack HAL po wywołaniu z PID 0 musi raportować globalną całkowitą pamięć prywatną GPU dla MemtrackType::GL i MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • getMemory() wywołana z PID 0 dla MemtrackType innego niż GL nie może zakończyć się niepowodzeniem. Zamiast tego musi zwrócić 0.
  • Rozwiązanie Tracepoint/eBPF pamięci GPU dodane w systemie Android 12 uwzględnia całkowitą pamięć GPU. Odjęcie całkowitej pamięci prywatnej GPU od całkowitej pamięci GPU daje rozmiar DMA-BUF odwzorowanych w przestrzeni adresowej GPU. Wartości można następnie użyć do poprawy dokładności obliczeń utraconej pamięci RAM poprzez prawidłowe uwzględnienie wykorzystania pamięci GPU.
  • Prywatna pamięć GPU jest zawarta w totalPss w większości implementacji Memtrack HAL i dlatego należy ją zdeduplikować przed usunięciem z lostRAM .

Wdrożone rozwiązanie opisano szczegółowo w następnej sekcji.

Usuń zmienność Memtrack z utraconej pamięci RAM

Ponieważ implementacje Memtrack HAL mogą się różnić u poszczególnych partnerów, pamięć GPU zawarta w totalPSS z HAL nie zawsze jest spójna. Aby usunąć zmienność z lostRAM , pamięć uwzględniana w MemtrackType::GRAPHICS i MemtrackType::GL jest usuwana z totalPss podczas obliczania lostRAM .

Pamięć MemtrackType::GRAPHICS jest usuwana z totalPss i zastępowana pamięcią totalExportedDmabuf w obliczeniach lostRAM w ActivityManagerService.java , jak pokazano poniżej:

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;

Pamięć MemtrackType::GL jest usuwana z totalPss i zastępowana prywatną pamięcią GPU ( gpuPrivateUsage ) podczas obliczania lostRAM w ActivityManagerService.java , jak pokazano poniżej:

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;

Zaktualizowano obliczenia utraconej pamięci RAM

Zarówno całkowita prywatna pamięć GPU, jak i całkowita wyeksportowana pamięć bufora DMA są zawarte w kernelUsed + totalPss , które są usuwane z lostRAM . Eliminuje to zarówno podwójne liczenie, jak i zmienność Memtrack wynikającą z obliczeń utraconej pamięci RAM.

final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();

Walidacja

Testy VTS egzekwują zasadę, że urządzenia uruchamiane w systemie Android 12 z jądrem Linux w wersji 5.4 lub wyższej obsługują API getGpuDeviceInfo() .

Nowe API Memtrack HAL getGpuDeviceInfo() musi zwracać informacje o używanym urządzeniu GPU.

Zapewnia to lepsze rozliczanie pamięci i wgląd w wykorzystanie bufora DMA i pamięci GPU. Zaimplementuj memtrack AIDL HAL, aby uzyskać lepsze rozliczanie utraconej pamięci RAM i pamięci. Ta funkcja nie jest zależna od usług Google.

Realizacja

Ta funkcja zależy od AIDL Memtrack HAL , a wskazówki dotyczące jej implementacji w systemie Android 12 są zawarte w kodzie jako komentarze.

Planuje się, że w przyszłych wersjach wszystkie warstwy HIDL HAL zostaną przekonwertowane na AIDL.

Do core/java/android/os/Debug.java dodano następujące interfejsy 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();

Aby mieć pewność, że Twoja wersja działa zgodnie z oczekiwaniami, zintegruj punkty śledzenia ze sterownikami GPU i zaimplementuj API AIDL memtrack HAL getMemory() , aby poprawnie zwrócić globalną całkowitą pamięć prywatną GPU po wywołaniu z PID 0 dla MemtrackType::GL i MemtrackRecord:: FLAG_SMAPS_UNACCOUNTED.