Implémenter la comptabilité DMABUF et la mémoire GPU dans Android 12

Cette page décrit les différentes améliorations de la comptabilité mémoire introduites dans Android 12.

Statistiques DMA-BUF dans sysfs

Sous Android 11 et Android 12, debugfs ne peuvent pas être montés dans les builds utilisateur. Les statistiques DMA-BUF ont donc été ajoutées à sysfs dans le répertoire /sys/kernel/dmabuf/buffers dans Android 12.

Chemin 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.

Veuillez noter que les pilotes du 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. Ceci est requis pour libdmabufinfo et l'outil dmabuf_dump dérivent 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 obsolète au profit du framework de tas DMA-BUF , qui fait partie du noyau Linux en amont.

Les statistiques globales ION 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é 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 avec 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 de ION sous 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 DMA-BUF exportés /sys/kernel/ion/total_heap_size_kb
(N'inclut pas la taille des DMA-BUF 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, le calcul de la RAM perdue était effectué comme suit :

finale longue 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 incluait l'utilisation totale de la mémoire DMA-BUF. Cependant, 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 page physique
  • DMA-BUF mappés dans l'espace d'adressage GPU

Par conséquent, les DMA-BUF 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-BUF mappés dans l'espace d'adressage du GPU, ce qui signifie qu'elle n'est prise en compte qu'une seule fois dans le calcul de la RAM perdue.

Les détails de la solution sont les suivants :

  • L'API Memtrack HAL getMemory() , lorsqu'elle est appelée avec le PID 0, doit signaler la mémoire privée totale globale du GPU, pour MemtrackType::GL et MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • getMemory() lorsqu'il est appelé avec PID 0 pour un MemtrackType autre que GL ne doit pas échouer. Il doit plutôt renvoyer 0.
  • La solution tracepoint/eBPF de mémoire GPU ajoutée dans Android 12 représente la mémoire GPU totale. La soustraction de la mémoire privée totale du GPU de la mémoire totale du GPU fournit 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 correctement compte de l'utilisation de la mémoire GPU.
  • La mémoire GPU privée est incluse dans totalPss dans la plupart des implémentations Memtrack HAL et doit donc être dédupliquée avant de la supprimer de lostRAM .

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 de Memtrack HAL peuvent varier selon les partenaires, la mémoire GPU incluse dans totalPSS de HAL n'est pas toujours cohérente. Pour supprimer la variabilité de lostRAM , la mémoire prise en compte dans MemtrackType::GRAPHICS et MemtrackType::GL est supprimée de totalPss lors du calcul 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;

Calcul de RAM perdue mis à jour

La mémoire GPU privée totale et la mémoire tampon DMA totale exportée sont contenues dans kernelUsed + totalPss qui est supprimé de lostRAM . Cela élimine à la fois le double comptage et la variabilité 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 noyau Linux version 5.4 ou supérieure prennent en charge l'API getGpuDeviceInfo() .

Une nouvelle API Memtrack HAL getGpuDeviceInfo() doit renvoyer des informations sur le périphérique GPU utilisé.

Cela offre une meilleure comptabilité de la mémoire et une meilleure visibilité sur l’utilisation du tampon DMA et de la mémoire GPU. Implémentez le memtrack AIDL HAL pour une meilleure comptabilité des pertes de RAM et de la mémoire. Cette fonctionnalité ne dépend pas des services Google.

Mise en œuvre

Cette fonctionnalité dépend du AIDL Memtrack HAL , et les instructions pour la mettre en œuvre dans Android 12 sont incluses dans le code sous forme de commentaires.

Il est prévu que tous les HAL HIDL soient convertis en AIDL dans les versions futures.

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 points de trace dans vos pilotes GPU et implémentez l'API AIDL memtrack HAL getMemory() pour renvoyer correctement la mémoire totale globale privée du GPU lorsqu'elle est appelée avec le PID 0 pour MemtrackType::GL et MemtrackRecord:: FLAG_SMAPS_UNACCOUNTED.