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 einMemtrackType
, das nichtGL
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 auslostRAM
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.