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

Na tej stronie opisujemy różne ulepszenia w zakresie rozliczania pamięci wprowadzone w Androidzie 12.

Statystyki DMA-BUF w sysfs

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

Ścieżka Opis
/sys/kernel/dmabuf/buffers Katalog /sys/kernel/dmabuf/buffers zawiera migawkę stanu wewnętrznego każdego bufora 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-BUFsysfs, aby udostępniać statystyki dotyczące poszczególnych eksporterów i buforów.

Sterowniki jądra, które eksportują DMA-BUF, muszą przed wywołaniem interfejsu dma_buf_export() API w celu utworzenia DMA-BUF prawidłowo ustawić pole exp_namestruct dma_buf_export_info na nazwę eksportera. Jest to wymagane, aby libdmabufinfo i narzędzie dmabuf_dump mogły uzyskiwać statystyki poszczególnych eksporterów, które są następnie udostępniane w raporcie o błędach.

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

Statystyki dotyczące struktury stert DMA-BUF

ION w GKI 2.0 jest wycofywany na rzecz struktury stert DMA-BUF, która jest częścią jądra systemu Linux.

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

  • Łączny rozmiar wyeksportowanych buforów DMA-BUF z każdego stogu ION
  • Łączny rozmiar niewykorzystanej wstępnie przydzielonej pamięci przechowywanej przez każdy stos ION.

W Androidzie 11 nie ma interfejsu, który udostępnia statystyki sterty ION.

W tabeli poniżej porównujemy interfejsy statystyk ION z ich odpowiednikami na urządzeniach z Androidem 12, które korzystają z platformy sterty DMA-BUF.

Android 11 lub urządzenia z obsługą ION w Androidzie 12 Urządzenia wprowadzane na rynek z pamięcią DMA-BUF w Androidzie 12
Statystyki ION dotyczące poszczególnych stert Brak Dane pochodzą z statystyk sysfs DMA-BUF
Łączny rozmiar wyeksportowanych buforów DMA /sys/kernel/ion/total_heap_size_kb
(Nie obejmuje rozmiaru buforów DMA-BUF wyeksportowanych przez eksportery inne niż ION)
Dane przeanalizowane ze statystyk sysfs DMA-BUF
(obejmuje rozmiar wszystkich wyeksportowanych DMA-BUF).
Łączna ilość pamięci w puli stert /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Zwiększanie dokładności obliczania utraconej pamięci RAM

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

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

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

- kernelUsed - memInfo.getZramTotalSizeKb();

Komponent totalPss obejmował wykorzystanie pamięci GPU (zwracane przez interfejs getMemory() Memtrack HAL). Komponent kernelUsed obejmował łączne wykorzystanie pamięci DMA-BUF. W przypadku urządzeń z Androidem pamięć GPU pochodzi z tych źródeł:

  • Bezpośrednie przydziały dokonywane przez sterownik GPU za pomocą alokatora stron fizycznych
  • Bufory DMA zmapowane w przestrzeni adresowej procesora graficznego

Dlatego bufory DMA-BUF, które zostały zmapowane do przestrzeni adresowej GPU, były odejmowane dwukrotnie podczas obliczania utraconej pamięci RAM. Android 12 zawiera rozwiązanie do obliczania rozmiaru buforów DMA-BUF mapowanych na przestrzeń adresową GPU, co oznacza, że w obliczeniach utraconej pamięci RAM jest on uwzględniany tylko raz.

Szczegóły rozwiązania:

  • Interfejs Memtrack HAL API getMemory() wywoływany z identyfikatorem PID 0 musi zgłaszać globalną łączną pamięć prywatną procesora graficznego dla MemtrackType::GLMemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • getMemory() wywołana z parametrem PID 0 dla MemtrackType innego niż GL nie może zakończyć się niepowodzeniem. Zamiast tego musi zwrócić wartość 0.
  • Rozwiązanie punkt śledzenia pamięci GPU/eBPF dodane w Androidzie 12 uwzględnia całkowitą pamięć GPU. Odjęcie łącznej prywatnej pamięci GPU od łącznej pamięci GPU daje rozmiar buforów DMA zmapowanych w przestrzeni adresowej GPU. Wartość ta może być następnie używana do zwiększania dokładności obliczeń utraconej pamięci RAM przez prawidłowe uwzględnianie wykorzystania pamięci GPU.
  • Prywatna pamięć GPU jest uwzględniana w totalPss w większości implementacji Memtrack HAL, dlatego przed usunięciem jej z lostRAM należy ją zduplikować.

Wdrożone rozwiązanie zostało opisane w następnej sekcji.

Usuwanie zmienności Memtrack z utraconej pamięci RAM

Implementacje Memtrack HAL mogą się różnić w zależności od partnera, dlatego pamięć GPU uwzględniona w totalPSS z HAL nie zawsze jest spójna. Aby usunąć zmienność z lostRAM, pamięć uwzględnioną w MemtrackType::GRAPHICSMemtrackType::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 pliku ActivityManagerService.java, jak pokazano w tym kodzie:

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 pamięci totalPss i zastępowana prywatną pamięcią GPU (gpuPrivateUsage) w obliczeniach lostRAM w pliku ActivityManagerService.java, jak pokazano w tym kodzie:

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;

Zaktualizowane obliczanie utraconej pamięci RAM

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

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

Weryfikacja

Testy VTS wymuszają regułę, zgodnie z którą urządzenia wprowadzane na rynek z Androidem 12 i jądrem systemu Linux w wersji 5.4 lub nowszej obsługują interfejs API getGpuDeviceInfo().

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

Zapewnia to lepsze rozliczanie pamięci i wgląd w bufor DMA oraz wykorzystanie pamięci GPU. Zaimplementuj interfejs HAL memtrack AIDL, aby lepiej śledzić utraconą pamięć RAM i pamięć. Ta funkcja nie jest zależna od usług Google.

Implementacja

Ta funkcja jest zależna od AIDL Memtrack HAL, a instrukcje jej wdrażania w Androidzie 12 są zawarte w kodzie w postaci komentarzy. W przyszłych wersjach wszystkie interfejsy HAL HIDL zostaną przekonwertowane na AIDL.

Do 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 sprawdzić, czy Twoja wersja działa zgodnie z oczekiwaniami, zintegruj punkty śledzenia ze sterownikami GPU i wdroż interfejs AIDL memtrack HAL getMemory() API, aby prawidłowo zwracać globalną łączną pamięć prywatną GPU po wywołaniu z identyfikatorem PID 0 dla MemtrackType::GLMemtrackRecord::FLAG_SMAPS_UNACCOUNTED.