DMABUF und GPU-Arbeitsspeicherabrechnung in Android 12 implementieren

Auf dieser Seite werden die verschiedenen Verbesserungen bei der Speicherverwaltung beschrieben, die in Android 12 eingeführt wurden.

DMA-BUF-Statistiken in sysfs

In Android 11 und Android 12 kann debugfs nicht in Nutzer-Builds bereitgestellt werden. Daher wurden DMA-BUF-Statistiken in Android 12 dem Dateinamen sysfs im Verzeichnis /sys/kernel/dmabuf/buffers hinzugefügt.

Pfad Beschreibung
/sys/kernel/dmabuf/buffers Das Verzeichnis /sys/kernel/dmabuf/buffers enthält einen Snapshot des internen Status jedes DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> enthält die Statistiken für den DMA-BUF mit der eindeutigen Inode-Nummer <inode_number>.
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name Diese schreibgeschützte Datei enthält den Namen des DMA-BUF-Exporteurs.
/sys/kernel/dmabuf/buffers/<inode_number>/size In dieser schreibgeschützten Datei wird die Größe des DMA-BUF in Byte angegeben.

Die libdmabufinfo API analysiert die DMA-BUF-sysfs-Statistiken, um Statistiken pro Exporteur und pro Puffer bereitzustellen.

Kerneltreiber, die DMA-BUFs exportieren, müssen das exp_name-Feld von struct dma_buf_export_info korrekt auf den Namen des Exporteurs festlegen, bevor sie die dma_buf_export() API aufrufen, um einen DMA-BUF zu erstellen. Dies ist erforderlich, damit libdmabufinfo und das dmabuf_dump-Tool Statistiken pro Exporteur ableiten können, die dann im Fehlerbericht angezeigt werden.

Das Tool dmabuf_dump wurde so geändert, dass diese Informationen mit einem neuen Argument, -b, ausgegeben werden.

Statistiken für das DMA-BUF-Heap-Framework

ION wird in GKI 2.0 zugunsten des DMA-BUF-Heap-Frameworks eingestellt, das Teil des Upstream-Linux-Kernels ist.

Die folgenden globalen ION-Statistiken werden in Android 11 erfasst:

  • Gesamtgröße der von jedem ION-Heap exportierten DMA-BUFs
  • Gesamtgröße des nicht verwendeten vorab zugewiesenen Arbeitsspeichers, der von jedem ION-Heap gespeichert wird

In Android 11 gibt es keine Benutzeroberfläche, über die Statistiken pro ION-Heap verfügbar gemacht werden können.

In der folgenden Tabelle werden die ION-Statistikschnittstellen mit ihren Gegenstücken für Geräte verglichen, die das DMA-BUF-Heap-Framework in Android 12 verwenden.

Android 11 oder Geräte mit ION-Unterstützung in Android 12 Geräte, die mit DMA-BUF-Haufen in Android 12 gestartet werden
ION-Statistiken pro Heap Keine Aus DMA-BUF-sysfs-Statistiken geparst
Gesamtgröße der exportierten DMA-BUFs /sys/kernel/ion/total_heap_size_kb
(Enthält nicht die Größe der DMA-BUFs, die von Nicht-ION-Exportern exportiert wurden)
Geparst aus DMA-BUF-sysfs-Statistiken
(einschließlich der Größe aller exportierten DMA-BUFs).
Nach Heaps zusammengefasster Arbeitsspeicher insgesamt /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Genauigkeit der Berechnung des verlorenen RAM verbessern

Zuvor wurde die RAM-Verlust berechnet:

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

memInfo.getFreeSizeKb()memInfo.getCachedSizeKb()

kernelUsedmemInfo.getZramTotalSizeKb();

Die Komponente totalPss enthielt die GPU-Arbeitsspeichernutzung, die von der getMemory()-Schnittstelle von Memtrack HAL zurückgegeben wird. Die Komponente kernelUsed enthielt die Gesamtnutzung des DMA-BUF-Speichers. Bei Android-Geräten stammte der GPU-Speicher jedoch aus folgenden Quellen:

  • Direkte Zuweisungen durch den GPU-Treiber über die Zuordnung für physische Seiten
  • DMA-BUFs, die dem GPU-Adressbereich zugeordnet sind

Daher wurden DMA-BUFs, die dem GPU-Adressbereich zugeordnet wurden, bei der Berechnung des verlorenen RAM doppelt subtrahiert. In Android 12 wird eine Lösung implementiert, um die Größe von DMA-BUFs zu berechnen, die in den GPU-Adressraum zugeordnet sind. Das bedeutet, dass sie bei der Berechnung des verlorenen RAM nur einmal berücksichtigt wird.

Die Details der Lösung sind:

  • Wenn die Memtrack HAL API getMemory() mit PID 0 aufgerufen wird, muss sie den gesamten globalen GPU-privaten Arbeitsspeicher für MemtrackType::GL und MemtrackRecord::FLAG_SMAPS_UNACCOUNTED angeben.
  • getMemory() darf nicht fehlschlagen, wenn es mit PID 0 für einen anderen MemtrackType als GL aufgerufen wird. Stattdessen muss 0 zurückgegeben werden.
  • Die in Android 12 hinzugefügte GPU-Arbeitsspeicher-Tracepoint/eBPF-Lösung berücksichtigt den gesamten GPU-Arbeitsspeicher. Wenn Sie den gesamten privaten GPU-Arbeitsspeicher vom gesamten GPU-Arbeitsspeicher subtrahieren, erhalten Sie die Größe der DMA-BUFs, die dem GPU-Adressbereich zugeordnet sind. Der Wert kann dann verwendet werden, um die Genauigkeit der Berechnungen für verlorenen RAM zu verbessern, indem die GPU-Speichernutzung korrekt berücksichtigt wird.
  • Der private GPU-Speicher ist in den meisten Memtrack HAL-Implementierungen in totalPss enthalten und muss daher dedupliziert werden, bevor er aus lostRAM entfernt wird.

Die implementierte Lösung wird im nächsten Abschnitt beschrieben.

Memtrack-Variabilität aus verlorenem RAM entfernen

Da sich die Memtrack HAL-Implementierungen von Partner zu Partner unterscheiden können, ist der in totalPSS aus der HAL enthaltene GPU-Speicher nicht immer konsistent. Um die Variabilität aus lostRAM zu entfernen, wird der in MemtrackType::GRAPHICS und MemtrackType::GL berücksichtigte Arbeitsspeicher während der lostRAM-Berechnung aus totalPss entfernt.

Der MemtrackType::GRAPHICS-Speicher wird aus totalPss entfernt und durch den totalExportedDmabuf-Speicher in der lostRAM-Berechnung in ActivityManagerService.java ersetzt, wie unten dargestellt:

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;

MemtrackType::GL-Arbeitsspeicher wird aus totalPss entfernt und bei der Berechnung von lostRAM in ActivityManagerService.java durch den privaten GPU-Arbeitsspeicher (gpuPrivateUsage) ersetzt, wie unten gezeigt:

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;

Aktualisierte Berechnung des verlorenen Arbeitsspeichers

Sowohl der gesamte private GPU-Arbeitsspeicher als auch der gesamte exportierte DMA-Pufferspeicher sind in kernelUsed + totalPss enthalten, der von lostRAM entfernt wird. Dadurch werden sowohl Doppelzählungen als auch die Memtrack-Variabilität bei der Berechnung des verlorenen RAM eliminiert.

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

Zertifizierungsstufe

VTS-Tests erzwingen die Regel, dass Geräte, die unter Android 12 mit einer Linux-Kernel-Version 5.4 oder höher gestartet werden, die getGpuDeviceInfo() API unterstützen.

Eine neue Memtrack HAL API getGpuDeviceInfo() muss Informationen zum verwendeten GPU-Gerät zurückgeben.

Dies bietet eine bessere Speicherbilanz und Einblick in die DMA-Zwischenspeicher- und GPU-Arbeitsspeichernutzung. Implementieren Sie Memtrack AIDL HAL, um die Analyse von RAM und Arbeitsspeicher zu optimieren. Diese Funktion ist nicht von Google-Diensten abhängig.

Implementierung

Diese Funktion hängt von der AIDL Memtrack HAL ab. Eine Anleitung zur Implementierung in Android 12 ist im Code als Kommentar enthalten.

Alle HIDL HALs sollen in zukünftigen Releases in AIDL konvertiert werden.

Die folgenden APIs wurden core/java/android/os/Debug.java hinzugefügt:

   /**
     * 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();

Damit Ihre Version wie vorgesehen funktioniert, integrieren Sie die Tracepoints in Ihre GPU-Treiber und implementieren die AIDL memtrack HAL getMemory() API, damit der gesamte GPU-Gesamtarbeitsspeicher korrekt zurückgegeben wird, wenn mit PID 0 für MemtrackType::GL und MemtrackRecord::FLAG_SMAPS_UNACCOUNTED aufgerufen wird.