Implementieren Sie DMABUF und GPU-Speicherabrechnung in Android 12

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

DMA-BUF-Statistiken in sysfs

In Android 11 und Android 12 können debugfs nicht in Benutzer-Builds gemountet werden. Daher wurden DMA-BUF-Statistiken zu sysfs im Verzeichnis /sys/kernel/dmabuf/buffers in Android 12 hinzugefügt.

Weg Beschreibung
/sys/kernel/dmabuf/buffers Das Verzeichnis /sys/kernel/dmabuf/buffers enthält eine Momentaufnahme 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 Bytes an.

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

Bitte beachten Sie, dass Kerneltreiber, die DMA-BUFs exportieren, das exp_name Feld der struct dma_buf_export_info korrekt auf den Namen des Exporteurs setzen müssen, bevor sie die API dma_buf_export() aufrufen, um einen DMA-BUF zu erstellen. Dies ist für libdmabufinfo und das dmabuf_dump Tool erforderlich, um Statistiken pro Exporter abzuleiten, die dann im Fehlerbericht angezeigt werden.

Das dmabuf_dump- Tool wurde geändert, um diese Informationen mit einem neuen Argument, -b auszugeben.

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

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

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

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

In Android 11 ist keine Schnittstelle zum Offenlegen von Heap-Statistiken pro ION verfügbar.

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, die mit ION-Unterstützung in Android 12 starten Geräte, die mit DMA-BUF-Heaps in Android 12 gestartet werden
ION-Statistiken pro Heap Keiner Aus DMA-BUF-Sysfs-Statistiken analysiert
Gesamtgröße der exportierten DMA-BUFs /sys/kernel/ion/total_heap_size_kb
(Beinhaltet nicht die Größe der DMA-BUFs, die von Nicht-ION-Exporteuren exportiert werden)
Aus DMA-BUF-Sysfs-Statistiken analysiert
(beinhaltet die Größe aller exportierten DMA-BUFs).
Gesamtspeicher, gepoolt durch Heaps /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Verbessern Sie die Genauigkeit der Berechnung des verlorenen RAM

Zuvor wurde die Berechnung des verlorenen RAM wie folgt durchgeführt:

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

- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()

- kernelUsed - memInfo.getZramTotalSizeKb() ;

Die totalPss Komponente enthielt die GPU-Speichernutzung (zurückgegeben von der getMemory()- Schnittstelle des Memtrack HAL). Die Komponente kernelUsed enthielt die gesamte DMA-BUF-Speichernutzung. Bei Android-Geräten stammte der GPU-Speicher jedoch von Folgendem:

  • Direkte Zuweisungen durch den GPU-Treiber mithilfe der physischen Seitenzuweisung
  • DMA-BUFs werden dem GPU-Adressraum zugeordnet

Daher wurden DMA-BUFs, die dem GPU-Adressraum speicherzugeordnet waren, bei der Berechnung des RAM-Verlusts zweimal subtrahiert. Android 12 implementiert eine Lösung zur Berechnung der Größe von DMA-BUFs, die dem GPU-Adressraum zugeordnet sind, was bedeutet, dass sie bei der Berechnung des verlorenen RAM nur einmal berücksichtigt werden.

Die Details der Lösung lauten wie folgt:

  • Wenn die Memtrack-HAL-API getMemory() mit PID 0 aufgerufen wird, muss sie den globalen gesamten privaten GPU-Speicher für MemtrackType::GL und MemtrackRecord::FLAG_SMAPS_UNACCOUNTED melden.
  • getMemory() darf beim Aufruf mit PID 0 für einen anderen MemtrackType als GL nicht fehlschlagen. Es muss stattdessen 0 zurückgeben.
  • Die in Android 12 hinzugefügte GPU-Speicher-Tracepoint/eBPF -Lösung berücksichtigt den gesamten GPU-Speicher. Durch Subtrahieren des gesamten privaten GPU-Speichers vom gesamten GPU-Speicher erhält man die Größe der DMA-BUFs, die dem GPU-Adressraum zugeordnet sind. Der Wert kann dann verwendet werden, um die Genauigkeit der Berechnungen des 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 detailliert beschrieben.

Entfernen Sie die Memtrack-Variabilität durch verlorenen RAM

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

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

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 Speicher wird aus totalPss entfernt und durch den privaten GPU-Speicher ( gpuPrivateUsage ) in der lostRAM Berechnung in ActivityManagerService.java 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;

Berechnung des verlorenen RAM aktualisiert

Sowohl der gesamte private GPU-Speicher als auch der gesamte exportierte DMA-Pufferspeicher sind in kernelUsed + totalPss enthalten, das aus lostRAM entfernt wird. Dies eliminiert sowohl Doppelzählungen als auch Memtrack-Variabilität durch die Berechnung des verlorenen RAM.

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

Validierung

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

Eine neue Memtrack-HAL-API getGpuDeviceInfo() muss Informationen über das verwendete GPU-Gerät zurückgeben.

Dies sorgt für eine bessere Speicherabrechnung und Einblick in die DMA-Puffer- und GPU-Speichernutzung. Implementieren Sie den Memtrack AIDL HAL für eine bessere Abrechnung von RAM-Verlust und Speicher. Diese Funktion ist nicht von Google-Diensten abhängig.

Implementierung

Diese Funktion hängt vom AIDL Memtrack HAL ab und Anweisungen zur Implementierung in Android 12 sind als Kommentare im Code enthalten.

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

Die folgenden APIs wurden zu 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();

Um sicherzustellen, dass Ihre Version wie vorgesehen funktioniert, integrieren Sie die Tracepoints in Ihre GPU-Treiber und implementieren Sie die API AIDL memtrack HAL getMemory() , um den globalen gesamten privaten GPU-Speicher korrekt zurückzugeben, wenn sie mit PID 0 für MemtrackType::GL und MemtrackRecord: aufgerufen wird. FLAG_SMAPS_UNACCOUNTED.