Wdrażanie DMABUF i rejestrowania pamięci GPU w Androidzie 12

Na tej stronie opisujemy różne ulepszenia w zakresie zliczania 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 obiektu DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> zawiera statystyki dla DMA-BUF z unikalnym numerem i-węzłów: <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 DMA-BUF sysfs, aby wyświetlić statystyki dotyczące eksportera i bufora.

Pamiętaj, że sterowniki jądra, które eksportują obiekty DMA-BUF, muszą prawidłowo ustawić w polu exp_name struct dma_buf_export_info nazwę eksportera przed wywołaniem interfejsu API dma_buf_export() w celu utworzenia DMA-BUF. Jest to wymagane przez libdmabufinfo i narzędzie dmabuf_dump do generowania statystyk na temat poszczególnych eksporterów, które są następnie widoczne w raporcie o błędzie.

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

Statystyki platformy DMA-BUF

Procesor ION w GKI 2.0 jest wycofywany i zastępuje platformę stosu DMA-BUF, która jest częścią nadrzędnego jądra systemu Linux.

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

  • Łączny rozmiar buforów DMA-BUF eksportowanych przez każdą stertę ION
  • Łączny rozmiar nieużywanej wstępnie przydzielonej pamięci przechowywanej przez każdą stertę ION

W Androidzie 11 nie ma interfejsu umożliwiającego wyświetlanie statystyk dotyczącej poszczególnych stosów ION.

W poniższej tabeli porównano interfejsy statystyk ION z ich odpowiednikami w przypadku urządzeń korzystających z platformy sterty 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 na stertę 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 plików DMA-BUF wyeksportowanych przez narzędzia do eksportu inne niż ION)
Przeanalizowano ze statystyk sysfs DMA-BUF
(obejmuje rozmiar wszystkich wyeksportowanych plików DMA-BUF).
Łączna ilość pamięci w puli stertów /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:

końcowy długi czas lostRAM = memInfo.getTotalSizeKb() – (totalPsstotalSwapPss)

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;
  • Obiekty DMA-BUF zmapowane na przestrzeń adresową GPU

W związku z tym podczas obliczania utraty pamięci RAM obiekty DMA-BUF zmapowane na przestrzeń adresową GPU były odejmowane dwukrotnie. Android 12 wdraża rozwiązanie służące do obliczania rozmiaru plików DMA-BUF zmapowanych na przestrzeń adresową GPU, co oznacza, że w ramach obliczania utraconej pamięci RAM są one uwzględniane tylko raz.

Szczegóły rozwiązania:

  • Interfejs API Memtrack HAL getMemory() wywoływany z PID 0 musi przekazywać globalną łączną pamięć prywatną GPU w przypadku MemtrackType::GL i MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • Metoda getMemory() w przypadku wywołania funkcji PID 0 w przypadku funkcji MemtrackType innej niż GL nie może kończyć się niepowodzeniem. Zamiast tego musi zwracać wartość 0.
  • Rozwiązanie punktu śledzenia pamięci GPU/eBPF dodane w Androidzie 12 uwzględnia łączną pamięć GPU. Odejmując łączną ilość prywatnej pamięci GPU od łącznej pamięci GPU, uzyskujesz rozmiar DMA-BUF zmapowanych na przestrzeń adresową 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ę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.

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

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 zawsze jest spójna. Aby można było usunąć zmienność z wartości lostRAM, podczas obliczania lostRAM z totalPss zostanie usunięta pamięć uwzględniona w parametrach MemtrackType::GRAPHICS i MemtrackType::GL.

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) w obliczeniach 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 obliczanie utraconej pamięci RAM

Zarówno łączna prywatna pamięć GPU, jak i łączna wyeksportowana pamięć bufora DMA znajdują się w kernelUsed + totalPss, która jest usuwana z lostRAM. Pozwala to wyeliminować zarówno podwójne zliczanie, jak i zmienność w ramach Memtracka z utraty 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 Memtrack HAL API getGpuDeviceInfo() musi zwracać informacje o używanym urządzeniu GPU.

Zapewnia to lepszy podgląd i kontrolę wykorzystania pamięci DMA oraz pamięci GPU. Zaimplementuj memtrack HAL AIDL, aby lepiej zmniejszyć utraconą pamięć RAM i obliczać ilość pamięci. Ta funkcja nie zależy od usług Google.

Implementacja

Ta funkcja zależy od interfejsu AIDL Memtrack HAL, a wskazówki dotyczące jego 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 wersja działa zgodnie z oczekiwaniami, zintegruj punkty śledzenia w sterownikach GPU i zaimplementuj interfejs API AIDL memtrack HAL getMemory(), aby poprawnie zwracać globalną łączną pamięć GPU w przypadku wywołania z PID 0 dla funkcji MemtrackType::GL i MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.