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_name w struct 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 dlaMemtrackType::GLiMemtrackRecord::FLAG_SMAPS_UNACCOUNTED. getMemory()wywołana z parametremPID 0dlaMemtrackTypeinnego niżGLnie 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
totalPssw większości implementacji Memtrack HAL, dlatego przed usunięciem jej zlostRAMnależ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::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 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::GL i MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.