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
Dans Android 11 et Android 12, debugfs ne peut pas être monté dans les builds utilisateur. Les statistiques DMA-BUF ont donc é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 exposer les statistiques par exportateur et par tampon.
Les pilotes de noyau 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 obtenir des statistiques par exportateur, qui sont ensuite exposées dans le rapport de bug.
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é au profit du framework de tas DMA-BUF, qui fait partie du noyau Linux en amont.
Les statistiques ION globales suivantes sont suivies dans Android 11 :
- Taille totale des DMA-BUFs 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 de tas par 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 lancés avec la prise en charge d'ION dans Android 12 | Appareils lancés avec des tas DMA-BUF dans Android 12 | |
|---|---|---|
| Statistiques ION par tas | Aucun | Analysé à partir des statistiques sysfs DMA-BUF |
| Taille totale des Bufs DMA exportés | /sys/kernel/ion/total_heap_size_kb
(n'inclut pas la taille des DMA-BUFs exportés par les exportateurs non ION) |
Analysé à partir des statistiques sysfs DMA-BUF
(inclut la taille de tous les DMA-BUF exportés). |
| Mémoire totale regroupée 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, la RAM perdue était calculée comme suit :
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
– memInfo.getFreeSizeKb() – memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb() ;
Le composant totalPss incluait l'utilisation de la mémoire GPU (renvoyée par l'interface getMemory() de Memtrack HAL). Le composant kernelUsed inclut l'utilisation totale de la mémoire DMA-BUF.
Toutefois, pour les appareils Android, la mémoire GPU provenait des éléments suivants :
- Allocations directes effectuées par le pilote GPU à l'aide de l'allocateur de pages physiques
- DMA-BUFs mappés dans l'espace d'adressage du GPU
Par conséquent, les DMA-BUFs mappés en mémoire dans l'espace d'adressage du GPU ont été soustraits deux fois lors du calcul de la RAM perdue. Android 12 implémente une solution pour calculer la taille des DMA-BUFs mappés dans l'espace d'adressage du GPU, ce qui signifie qu'ils ne sont comptabilisés qu'une seule fois dans le calcul de la RAM perdue.
Voici les détails de la solution :
- L'API HAL Memtrack
getMemory(), lorsqu'elle est appelée avec le PID 0, doit indiquer la mémoire privée totale du GPU global pourMemtrackType::GLetMemtrackRecord::FLAG_SMAPS_UNACCOUNTED. getMemory()ne doit pas échouer lorsqu'il est appelé avecPID 0pour unMemtrackTypeautre queGL. Il doit plutôt renvoyer 0.- La solution tracepoint/eBPF de mémoire GPU ajoutée dans Android 12 comptabilise la mémoire GPU totale. En soustrayant la mémoire privée totale du GPU de la mémoire totale du GPU, on obtient la taille des DMA-BUFs 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 correctement compte de l'utilisation de la mémoire GPU.
- La mémoire GPU privée est incluse dans
totalPssdans la plupart des implémentations Memtrack HAL 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 Memtrack HAL peuvent varier d'un partenaire à l'autre, la mémoire GPU incluse dans totalPSS à partir de 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é dans le code suivant :
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é dans le code suivant :
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;
Calcul modifié 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é 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 une version du noyau Linux 5.4 ou ultérieure sont compatibles avec l'API getGpuDeviceInfo().
Une nouvelle API HAL Memtrack getGpuDeviceInfo() doit renvoyer des informations sur le périphérique GPU utilisé.
Cela permet une meilleure comptabilisation de la mémoire et une meilleure visibilité sur l'utilisation de la mémoire GPU et du tampon DMA. Implémentez le HAL AIDL memtrack pour une meilleure comptabilisation de la mémoire et de la RAM perdues. Cette fonctionnalité ne dépend pas des services Google.
Implémentation
Cette fonctionnalité dépend du HAL Memtrack AIDL. Les instructions pour l'implémenter dans Android 12 sont incluses dans le code sous forme de commentaires. Toutes les HAL HIDL devraient être converties 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 vérifier que votre version fonctionne comme prévu, intégrez les points de trace dans vos pilotes de GPU et implémentez l'API AIDL memtrack HAL getMemory() pour renvoyer correctement la mémoire privée totale du GPU lorsqu'elle est appelée avec le PID 0 pour MemtrackType::GL et MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.