Implementierung von DMABUF- und GPU-Arbeitsspeichererfassung in Android 12

Auf dieser Seite werden die verschiedenen Verbesserungen bei der Speicherabrechnung in Android 12 beschrieben.

DMA-BUF-Statistiken in sysfs

In Android 11 und Android 12 kann debugfs nicht in User-Builds eingebunden werden. Daher wurden DMA-BUF-Statistiken in Android 12 zu 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-Exporters.
/sys/kernel/dmabuf/buffers/<inode_number>/size Diese schreibgeschützte Datei gibt die Größe des DMA-BUF in Byte an.

Die libdmabufinfo-API parst die DMA-BUF-sysfs-Statistiken, um Statistiken pro Exporteur und pro Puffer verfügbar zu machen.

Kernel-Treiber, die DMA-BUFs exportieren, müssen das Feld exp_name von struct dma_buf_export_info korrekt auf den Namen des Exportierenden 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-Heaps-Framework

ION in GKI 2.0 wird zugunsten des DMA-BUF-Heaps-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 ist keine Schnittstelle verfügbar, um Heap-Statistiken pro ION-Heap zu erfassen.

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

Android 11 oder Geräte, die bei Markteinführung ION-Unterstützung in Android 12 nutzen Geräte, die bei Markteinführung DMA-BUF-Heaps in Android 12 nutzen
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 von DMA-BUFs, die von Nicht-ION-Exportern exportiert werden)
Aus DMA-BUF-Sysfs-Statistiken geparst
(einschließlich der Größe aller exportierten DMA-BUFs).
Gesamter Arbeitsspeicher, der von Heaps zusammengefasst wird /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Genauigkeit der Berechnung des verlorenen RAM verbessern

Bisher wurde der verlorene RAM so berechnet:

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

memInfo.getFreeSizeKb() – memInfo.getCachedSizeKb()

kernelUsed – memInfo.getZramTotalSizeKb();

Die Komponente totalPss enthielt die GPU-Arbeitsspeichernutzung (die von der getMemory()-Schnittstelle des Memtrack-HAL zurückgegeben wurde). Die Komponente kernelUsed enthielt die gesamte DMA-BUF-Arbeitsspeichernutzung. Bei Android-Geräten stammt der GPU-Arbeitsspeicher jedoch aus den folgenden Quellen:

  • Direkte Zuweisungen durch den GPU-Treiber mit dem physischen Seitenzuweiser
  • DMA-BUFs, die in den GPU-Adressraum abgebildet werden

Daher wurden DMA-BUFs, die in den GPU-Adressraum gemappt wurden, bei der Berechnung des verlorenen RAM zweimal subtrahiert. In Android 12 wird eine Lösung zur Berechnung der Größe von DMA-BUFs implementiert, die in den GPU-Adressraum gemappt werden. Das bedeutet, dass sie nur einmal in der Berechnung des verlorenen RAM berücksichtigt werden.

Die Details der Lösung sind wie folgt:

  • Die Memtrack HAL API getMemory() muss bei Aufruf mit PID 0 den globalen GPU-privaten Gesamtspeicher für MemtrackType::GL und MemtrackRecord::FLAG_SMAPS_UNACCOUNTED melden.
  • Der Aufruf von „getMemory()“ mit PID 0 für ein MemtrackType, das nicht GL ist, darf nicht fehlschlagen. Stattdessen muss 0 zurückgegeben werden.
  • Die in Android 12 hinzugefügte Lösung GPU-Arbeitsspeicher-Tracepoint/eBPF berücksichtigt den gesamten GPU-Arbeitsspeicher. Wenn Sie den privaten GPU-Arbeitsspeicher vom gesamten GPU-Arbeitsspeicher abziehen, erhalten Sie die Größe der DMA-BUFs, die in den GPU-Adressraum abgebildet sind. Der Wert kann dann verwendet werden, um die Genauigkeit der Berechnungen für „Verlorener RAM“ zu verbessern, indem die GPU-Arbeitsspeichernutzung richtig berücksichtigt wird.
  • Der private GPU-Arbeitsspeicher 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 die Memtrack-HAL-Implementierungen je nach Partner variieren können, ist der im 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 Speicherplatz bei der Berechnung von lostRAM 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;

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

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 RAM

Sowohl der gesamte private GPU-Arbeitsspeicher als auch der gesamte exportierte DMA-Puffer-Arbeitsspeicher sind in kernelUsed + totalPss enthalten, das aus lostRAM entfernt wird. Dadurch werden sowohl Doppelzählungen als auch Memtrack-Variabilität bei der Berechnung des verlorenen Arbeitsspeichers vermieden.

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

Zertifizierungsstufe

VTS-Tests erzwingen die Regel, dass Geräte, die mit Android 12 und einer Linux-Kernel-Version 5.4 oder höher auf den Markt kommen, die API getGpuDeviceInfo() unterstützen.

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

Dies ermöglicht eine bessere Speicherabrechnung und mehr Transparenz bei der Nutzung von DMA-Puffer und GPU-Arbeitsspeicher. Implementieren Sie das memtrack AIDL HAL für eine bessere Erfassung von verlorenem RAM und Arbeitsspeicher. Diese Funktion ist nicht von Google-Diensten abhängig.

Implementierung

Diese Funktion hängt vom 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, müssen Sie die Tracepoints in Ihre GPU-Treiber einbinden und die AIDL-HAL-Schnittstelle getMemory() implementieren, um den globalen privaten GPU-Speicher korrekt zurückzugeben, wenn sie mit PID 0 für MemtrackType::GL und MemtrackRecord::FLAG_SMAPS_UNACCOUNTED aufgerufen wird.