Cette page décrit les différentes améliorations apportées à la comptabilisation de la mémoire dans Android 12.
Statistiques DMA-BUF dans sysfs
Sous Android 11 et Android 12, debugfs
ne peut pas être installé dans les builds utilisateur. Par conséquent, des statistiques DMA-BUF ont été ajoutées à sysfs
dans le répertoire /sys/kernel/dmabuf/buffers
d'Android 12.
Chemin d'accès | Description |
---|---|
/sys/kernel/dmabuf/buffers
|
Le répertoire /sys/kernel/dmabuf/buffers contient un instantané de l'état interne de chaque DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number> contient les statistiques du DMA-BUF avec le numéro d'inode unique <inode_number> .
|
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name
|
Ce fichier en lecture seule contient le nom de l'exportateur DMA-BUF. |
/sys/kernel/dmabuf/buffers/<inode_number>/size
|
Ce fichier en lecture seule spécifie la taille du DMA-BUF en octets. |
L'API libdmabufinfo
analyse les statistiques sysfs
DMA-BUF pour afficher des statistiques par exportateur et par tampon.
Notez que les pilotes du kernel qui exportent des DMA-BUF doivent définir correctement le champ exp_name
de struct dma_buf_export_info
sur le nom de l'exportateur avant d'appeler l'API dma_buf_export()
pour créer un DMA-BUF.
Cela est nécessaire pour que libdmabufinfo
et l'outil dmabuf_dump
puissent dériver des statistiques par exportateur, qui sont ensuite exposées dans le bugreport.
L'outil dmabuf_dump a été modifié pour afficher ces informations avec un nouvel argument, -b
.
Statistiques pour le framework de tas DMA-BUF
ION dans GKI 2.0 est abandonné et remplacé par le framework de tas DMA-BUF, qui fait partie du kernel Linux en amont.
Les statistiques ION globales suivantes sont suivies dans Android 11:
- Taille totale des DMA-BUF exportés par chaque tas ION
- Taille totale de la mémoire préallouée inutilisée stockée par chaque tas ION
Aucune interface n'est disponible pour exposer les statistiques par tas ION dans Android 11.
Le tableau suivant compare les interfaces de statistiques ION à leurs homologues pour les appareils qui utilisent le framework de tas DMA-BUF dans Android 12.
Android 11 ou appareils avec prise en charge d'ION sous Android 12 | Appareils lancés avec des tas DMA-BUF sous Android 12 | |
---|---|---|
Statistiques ION par tas de mémoire | Aucune | Extrait des statistiques sysfs DMA-BUF |
Taille totale des DMA-BUF exportés | /sys/kernel/ion/total_heap_size_kb
(n'inclut pas la taille des DMA-BUF exportés par des exportateurs autres qu'ION) |
Analysé à partir des statistiques sysfs DMA-BUF
(inclut la taille de tous les DMA-BUF exportés). |
Mémoire totale mise en commun par tas | /sys/kernel/ion/total_pool_size_kb |
/sys/kernel/dma_heap/total_pool_size_kb |
Améliorer la précision du calcul de la RAM perdue
Auparavant, le calcul de la RAM perdue était effectué comme suit:
lostRAM
long final = memInfo.getTotalSizeKb(
) - (totalPss
- totalSwapPss
)
– memInfo.getFreeSizeKb()
– memInfo.getCachedSizeKb()
– kernelUsed
– memInfo.getZramTotalSizeKb()
;
Le composant totalPss
incluait l'utilisation de la mémoire GPU (rendue par l'interface getMemory() du HAL Memtrack). Le composant kernelUsed
incluait l'utilisation totale de la mémoire DMA-BUF.
Toutefois, pour les appareils Android, la mémoire GPU provient des éléments suivants:
- Allocations directes effectuées par le pilote du GPU à l'aide de l'outil d'allocation de pages physiques
- DMA-BUF mappés dans l'espace d'adressage du GPU
Par conséquent, les DMA-BUF mappés en mémoire dans l'espace d'adressage du GPU étaient soustraits deux fois lors du calcul de la RAM perdue. Android 12 implémente une solution pour calculer la taille des DMA-BUF mappés dans l'espace d'adressage du GPU, ce qui signifie qu'ils ne sont pris en compte qu'une seule fois dans le calcul de la RAM perdue.
La solution détaillée est la suivante:
- L'API HAL Memtrack
getMemory()
, lorsqu'elle est appelée avec PID 0, doit indiquer la mémoire globale privée du GPU, pour MemtrackType::GL et MemtrackRecord::FLAG_SMAPS_UNACCOUNTED. - getMemory() lorsqu'il est appelé avec
PID
0
pour unMemtrackType
autre queGL
ne doit pas échouer. Il doit plutôt renvoyer 0. - La solution tracepoint/eBPF de mémoire GPU ajoutée dans Android 12 tient compte de la mémoire GPU totale. En soustrayant la mémoire privée GPU totale de la mémoire GPU totale, vous obtenez la taille des DMA-BUF mappés dans l'espace d'adressage du GPU. La valeur peut ensuite être utilisée pour améliorer la précision des calculs de RAM perdue en tenant compte correctement de l'utilisation de la mémoire GPU.
- La mémoire GPU privée est incluse dans
totalPss
dans la plupart des implémentations HAL Memtrack et doit donc être dédupliquée avant d'être supprimée delostRAM
.
La solution implémentée est détaillée dans la section suivante.
Supprimer la variabilité Memtrack de la RAM perdue
Étant donné que les implémentations du HAL Memtrack peuvent varier d'un partenaire à l'autre, la mémoire GPU incluse dans totalPSS
à partir du HAL n'est pas toujours cohérente. Pour supprimer la variabilité de lostRAM
, la mémoire comptabilisée dans MemtrackType::GRAPHICS
et MemtrackType::GL
est supprimée de totalPss
lors du calcul de lostRAM
.
La mémoire MemtrackType::GRAPHICS
est supprimée de totalPss
et remplacée par la mémoire totalExportedDmabuf
dans le calcul lostRAM
dans ActivityManagerService.java , comme indiqué ci-dessous:
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;
La mémoire MemtrackType::GL
est supprimée de totalPss
et remplacée par la mémoire GPU privée (gpuPrivateUsage
) dans le calcul lostRAM
dans ActivityManagerService.java , comme indiqué ci-dessous:
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;
Mise à jour du calcul de la RAM perdue
La mémoire GPU privée totale et la mémoire tampon DMA exportée totale sont contenues dans kernelUsed + totalPss
, qui est supprimée de lostRAM
. Cela élimine à la fois le double comptage et la variabilité de Memtrack du calcul de la RAM perdue.
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();
Validation
Les tests VTS appliquent la règle selon laquelle les appareils lancés sous Android 12 avec un kernel Linux version 5.4 ou ultérieure sont compatibles avec l'API getGpuDeviceInfo().
Une nouvelle API HAL Memtrack getGpuDeviceInfo()
doit renvoyer des informations sur l'appareil GPU utilisé.
Cela permet une meilleure comptabilisation et visibilité de la mémoire dans le tampon DMA et l'utilisation de la mémoire du GPU. Implémentez le HAL AIDL memtrack pour une meilleure comptabilité de la RAM et de la mémoire perdues. Cette fonctionnalité ne dépend pas des services Google.
Implémentation
Cette fonctionnalité dépend du HAL Memtrack AIDL, et les instructions d'implémentation dans Android 12 sont incluses dans le code sous forme de commentaires.
Tous les HAL HIDL devraient être convertis en AIDL dans les prochaines versions.
Les API suivantes ont été ajoutées à core/java/android/os/Debug.java
:
/**
* 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();
Pour vous assurer que votre version fonctionne comme prévu, intégrez les tracepoints dans vos pilotes GPU et implémentez l'API AIDL memtrack HAL getMemory()
pour renvoyer correctement la mémoire privée globale du GPU lorsqu'elle est appelée avec PID 0 pour MemtrackType::GL et MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.