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

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

Statystyki DMA-BUF w sysfs

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

Ś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: obiekt DMA-BUF z unikalnym numerem i-węzełowego <inode_number>.
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name Ten plik tylko do odczytu zawiera nazwę eksportującego DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number>/size Ten plik tylko do odczytu określa rozmiar DMA-BUF w bajtach.

libdmabufinfo Interfejs API analizuje statystyki DMA-BUF sysfs w celu udostępnienia statystyk dotyczących poszczególnych eksporterów i buforów.

Pamiętaj, że sterowniki jądra, które eksportują pliki DMA-BUF, muszą ustawić exp_name struct dma_buf_export_info do nazwy eksportera przed przez wywołanie interfejsu API dma_buf_export() w celu utworzenia DMA-BUF. 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

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

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

  • Łączny rozmiar plików DMA-BUF wyeksportowanych 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, który umożliwiłby wyświetlanie statystyk sterty na ION.

W poniższej tabeli porównano interfejsy statystyk ION z ich w przypadku urządzeń korzystających z platformy sterty DMA-BUF w Androidzie 12.

Android 11 lub urządzenia z obsługą funkcji 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 plików DMA-BUF /sys/kernel/ion/total_heap_size_kb.
(nie obejmuje rozmiaru plików DMA-BUF wyeksportowanych przez eksporterów niebędących 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

Popraw 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 (zwrócone przez Metoda getMemory() w Memtrack HAL ). Komponent kernelUsed obejmuje łączne wykorzystanie pamięci DMA-BUF. W przypadku urządzeń z Androidem pamięć GPU pochodzi z tych źródeł:

  • 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 obiekty DMA-BUF zmapowane na pamięć adresową GPU. były odejmowane dwukrotnie przy obliczaniu utraty pamięci RAM. 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() 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ć 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 zapewnia 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.
  • Prywatna pamięć GPU jest uwzględniona w totalPss w większości plików HAL Memtrack implementacji, z tego powodu przed usunięciem go z lostRAM należy usunąć jego duplikaty.

Szczegółowe informacje na temat 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 parametrach 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) została usunięta z: totalPss i zastąpiona prywatna pamięć GPU (gpuPrivateUsage) w obliczeniach lostRAM w ActivityManagerService.java jak 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 wartości kernelUsed + totalPss, która jest usuwana z wartości lostRAM. Ten eliminuje zmienność podwójnego liczenia i zmienność w Memtrack z utraty pamięci RAM. obliczeń.

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

Weryfikacja

Testy VTS egzekwują regułę, zgodnie z którą urządzenia uruchamiane na urządzeniach z Androidem 12 z jądrem Linuxa w wersji 5.4 lub nowszej obsługuje getGpuDeviceInfo() API.

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

Pozwala to lepiej uwzględniać pamięć i obserwację bufora DMA i GPU. wykorzystanie pamięci. Wdróż memtrack HAL AIDL, aby lepiej zmniejszyć ilość pamięci RAM i pamięci księgowości. Ta funkcja nie zależy od usług Google.

Implementacja

Ta funkcja wymaga interfejsu Memtrack HAL AIDL, 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.

Te interfejsy API zostały dodane do core/java/android/os/Debug.java:

   /**
     * 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 GPU sterowniki i zaimplementuj interfejs API AIDL memtrack HAL getMemory(), aby poprawnie zwrócić globalna łączna ilość prywatnej pamięci GPU wywoływanej z identyfikatorem PID 0 dla MemtrackType::GL i MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.