Wdrożenie obsługi DMABUF i pamięci GPU w Androidzie 12

Na tej stronie opisujemy różne ulepszenia dotyczące zarządzania pamięcią wprowadzone w Androidzie 12.

Statystyki DMA-BUF w sysfs

W Androidzie 11 i 12 nie można zamontować debugfs w kompilacji użytkownika. W Androidzie 12 statystyki DMA-BUF zostały dodane do sysfs w katalogu /sys/kernel/dmabuf/buffers.

Ścieżka Opis
/sys/kernel/dmabuf/buffers Katalog /sys/kernel/dmabuf/buffers zawiera migawkę stanu wewnętrznego każdego DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> zawiera statystyki dotyczące DMA-BUF z unikalnym numerem inode <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 libdmabufinfo API analizuje statystyki DMA-BUF sysfs, aby udostępnić statystyki dla eksportera i bufora.

Pamiętaj, że sterowniki jądra, które eksportują DMA-BUF, muszą przed wywołaniem interfejsu API dma_buf_export(), aby utworzyć DMA-BUF, prawidłowo ustawić pole exp_namestruct dma_buf_export_info na nazwę eksportera. Jest to wymagane, aby narzędzia libdmabufinfodmabuf_dump mogły uzyskać statystyki dotyczące poszczególnych eksporterów, które są następnie wyświetlane w bugreport.

Narzędzie dmabuf_dump zostało zmodyfikowane, aby wyświetlać te informacje za pomocą nowego argumentu -b.

Statystyki dotyczące ramki stosów DMA-BUF

ION w GKI 2.0 jest wycofywany na rzecz ramy zbiorów danych DMA-BUF, która jest częścią upstreamowego jądra Linux.

W Androidzie 11 śledzone są te globalne statystyki ION:

  • Łączny rozmiar buforów DMA-BUF eksportowanych przez każdą pamięć ION
  • Łączny rozmiar niewykorzystanej pamięci przydzielonej wstępnie i przechowywanej przez każdą stos ION

W Androidzie 11 nie ma interfejsu, który umożliwiałby wyświetlanie statystyk dotyczącej poszczególnych stosów ION.

W tabeli poniżej porównano interfejsy statystyk ION z ich odpowiednikami na urządzeniach, które korzystają z ramycu stosu DMA-BUF w Androidzie 12.

Android 11 lub urządzenia z obsługą ION w Androidzie 12 Urządzenia uruchamiane z użyciem stosu DMA-BUF w Androidzie 12
Statystyki ION dotyczące poszczególnych stosów Brak Przetworzone z statystyk sysfs DMA-BUF
Łączny rozmiar wyeksportowanych buforów DMA-BUF /sys/kernel/ion/total_heap_size_kb
(Nie uwzględnia rozmiaru buforów DMA-BUF wyeksportowanych przez narzędzia do eksportu innych niż ION)
Zanalizowane statystyki sysfs DMA-BUF
(zawiera rozmiar wszystkich wyeksportowanych buforów DMA-BUF).
Łączna pamięć przypisana stosowi /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Poprawić dokładność obliczania utraconej pamięci RAM

Wcześniej utrata pamięci RAM była obliczana w ten sposób:

final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)

memInfo.getFreeSizeKb()memInfo.getCachedSizeKb()

kernelUsedmemInfo.getZramTotalSizeKb();

Komponent totalPss uwzględnia wykorzystanie pamięci GPU (zwracane przez interfejs getMemory() interfejsu Memtrack HAL). Komponent kernelUsed obejmuje łączne wykorzystanie pamięci DMA-BUF. W przypadku urządzeń z Androidem pamięć GPU pochodzi z:

  • bezpośrednie przydzielenia dokonane przez sterownik GPU za pomocą przydzielacza stron fizycznych;
  • Bufory DMA zmapowane w przestrzeni adresowej GPU

Dlatego podczas obliczania utraconej pamięci RAM z pamięci przypisanej do pamięci adresowej GPU odjęto dwukrotnie bufory DMA. Android 12 wdraża rozwiązanie do obliczania rozmiaru buforów DMA mapowanych do przestrzeni adresowej GPU, co oznacza, że jest on uwzględniany tylko raz w obliczeniach utraconej pamięci RAM.

Szczegóły rozwiązania:

  • Interfejs API Memtrack HAL getMemory(), gdy jest wywoływany z PID 0, musi przekazywać globalną łączną pamięć prywatną GPU w przypadku MemtrackType::GL i MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • getMemory() wywoływany z parametrami PID 0 dla MemtrackType innych niż GL nie może się nie udać. Zamiast tego musi zwracać 0.
  • Rozwiązanie punktu śledzenia pamięci GPU/eBPF dodane w Androidzie 12 uwzględnia łączną pamięć GPU. Odejmowanie łącznej prywatnej pamięci GPU od łącznej pamięci GPU daje rozmiar DMA-BUF mapowanych do przestrzeni adresowej GPU. Wartość ta może być następnie wykorzystana do zwiększenia dokładności obliczeń utraconej pamięci RAM przez prawidłowe uwzględnienie wykorzystania pamięci GPU.
  • W większości implementacji HAL Memtrack prywatna pamięć GPU jest uwzględniona w totalPss, dlatego przed usunięciem z lostRAM należy ją usunąć.

Szczegóły wdrożonego rozwiązania znajdziesz w następnej sekcji.

Usuwanie zmienności Memtracka z utraconego RAM-u

Implementacje HAL Memtrack mogą się różnić w zależności od partnera, dlatego pamięć GPU uwzględniona w wartości totalPSS w HAL nie jest zawsze spójna. Aby usunąć zmienność z poziomu lostRAM, pamięć uwzględniona w funkcji MemtrackType::GRAPHICSMemtrackType::GL jest usuwana z poziomu totalPss podczas obliczenia lostRAM.

Pamięć MemtrackType::GRAPHICS jest usuwana z funkcji totalPss i zastępowana pamięcią totalExportedDmabuf w obliczeniach lostRAM w pliku 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 funkcji totalPss i zastępowana przez prywatną pamięć GPU (gpuPrivateUsage) w obliczeniach funkcji lostRAM w pliku 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 łączna prywatna pamięć GPU, jak i łączna wyeksportowana pamięć bufora DMA znajdują się w wartości kernelUsed + totalPss, która jest usuwana z wartości lostRAM. Dzięki temu można wyeliminować podwójne zliczanie i zmienność Memtracka z obliczeń utraconej pamięci RAM.

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

Weryfikacja

Testy VTS egzekwują zasadę, że urządzenia uruchamiane w Androidzie 12 z jądrem Linuksa w wersji 5.4 lub nowszej obsługują interfejs API getGpuDeviceInfo().

Nowy interfejs API Memtrack HAL getGpuDeviceInfo() musi zwracać informacje o urządzeniu GPU, którego używasz.

Zapewnia to lepszy podgląd i kontrolę pamięci oraz wykorzystanie bufora DMA i pamięci GPU. Zaimplementuj interfejs HAL memtrack AIDL, aby lepiej zarządzać pamięcią RAM i pamięcią. Ta funkcja nie zależy od usług Google.

Implementacja

Ta funkcja wymaga interfejsu API Memtrack HAL, a instrukcje implementacji w Androidzie 12 są zawarte w kodzie jako komentarze.

W przyszłych wersjach wszystkie interfejsy HIDL HAL zostaną przekształcone w interfejsy AIDL.

Do usługi core/java/android/os/Debug.java dodaliśmy te 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 prawidłowo, zintegruj punkty śledzenia w sterownikach GPU i zaimplementuj interfejs API memtrack HAL getMemory() AIDL, aby poprawnie zwracać globalną łączną pamięć prywatną GPU, gdy wywołanie nastąpi z PID 0 dla MemtrackType::GL i MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.