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

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

Sur Android 11 et Android 12, debugfs ne peut pas être installé dans les builds utilisateur. Les statistiques DMA-BUF ont donc été ajoutées à sysfs dans Répertoire /sys/kernel/dmabuf/buffers dans 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 pour le DMA-BUF avec le numéro de nœud d'index 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 libdmabufinfo et l'outil dmabuf_dump afin de dériver des statistiques par exportateur sont ensuite exposés dans le rapport de bug.

La méthode dmabuf_dump L'outil a été modifié pour générer 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 de mémoire DMA-BUF, qui fait partie du noyau Linux en amont.

Les statistiques ION globales suivantes sont suivies dans Android 11 :

  • Taille totale des DMA-BUF exportés par chaque tas de mémoire ION
  • Taille totale de la mémoire préallouée inutilisée stockée par chaque tas de mémoire ION

Il n'existe pas d'interface permettant d'exposer des statistiques sur les segments de mémoire par ION dans Android 11.

Le tableau suivant compare les interfaces de statistiques ION avec leurs équivalents pour les appareils qui utilisent le framework de tas de mémoire DMA-BUF sous Android 12.

Android 11 ou appareils avec prise en charge d'ION sous Android 12 Appareils lancés avec des tas de mémoire 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 les exportateurs autres que ION)
Analysé à partir des statistiques sysfs DMA-BUF
(inclut la taille de tous les DMA-BUF exportés).
Mémoire totale allouée par les segments de mémoire /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 :

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

memInfo.getFreeSizeKb()memInfo.getCachedSizeKb()

kernelUsedmemInfo.getZramTotalSizeKb() ;

Le composant totalPss incluait l'utilisation de la mémoire GPU (rendue par l'interface getMemory() du HAL Memtrack). Le composant kernelUsed comprenait l'utilisation totale de la mémoire du DMA-BUF. Toutefois, pour les appareils Android, la mémoire du 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 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 met en œuvre une solution pour calculer la taille des DMA-BUF mappés au GPU ce qui signifie qu'il n'est pris en compte qu'une seule fois dans le rapport Calcul de la RAM.

La solution détaillée est la suivante :

  • L'API HAL Memtrack getMemory() lorsqu'il est appelé avec le PID 0 doit indiquer la mémoire totale globale privée par 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 tient compte de la mémoire GPU totale. La soustraction de la mémoire privée totale du GPU de la mémoire GPU totale donne le résultat la taille des DMA-BUF mappés dans l'espace d'adressage 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 du 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 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 HAL pour Memtrack peuvent varier d'un partenaire à l'autre, la mémoire GPU inclus dans totalPSS à partir du HAL n'est pas toujours cohérent. 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 perte de RAM

La mémoire GPU privée totale et la mémoire tampon totale de la zone de marché désignée contenu dans kernelUsed + totalPss, qui est supprimé de lostRAM. Ce Élimine à la fois la double comptabilisation et la variabilité Memtrack liée à la perte de RAM calcul.

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 dotés d'un noyau Linux 5.4 ou version ultérieure sont compatibles avec getGpuDeviceInfo(). API.

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 instructions de mise en œuvre sous Android 12 sont inclus 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 points de trace dans votre GPU et implémenter l'API HAL getMemory() AIDL memtrack pour renvoyer correctement la mémoire GPU privée totale globale lorsqu'elle est appelée avec le PID 0 pour MemtrackType::GL. et MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.