Implémenter DMABUF et la comptabilisation de la mémoire 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

Sous 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 le répertoire /sys/kernel/dmabuf/buffers sous 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 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.

Veuillez noter que 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 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 des segments de mémoire 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 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ée inutilisée stockée par chaque tas 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 à 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 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 des exportateurs autres qu'ION)
Analyse des statistiques système DMA-BUF
(inclut la taille de toutes les DMA-BUF exportées).
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 mémoire 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 incluait l'utilisation totale de la mémoire DMA-BUF. Cependant, 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 GPU

Par conséquent, les DMA-BUF qui étaient mappés en mémoire dans l'espace d'adressage du GPU ont été soustraits deux fois lors du calcul de la perte de RAM. 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.

Les détails de la solution sont les suivants:

  • L'API HAL Memtrack getMemory(), lorsqu'elle est appelée avec PID 0, doit indiquer la mémoire privée globale du GPU, pour MemtrackType::GL et MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • La méthode getMemory() lorsqu'elle est appelée avec PID 0 pour une MemtrackType autre que GL ne doit pas échouer. Il doit plutôt renvoyer 0.
  • La solution tracepoint/eBPF de la mémoire GPU ajoutée dans Android 12 prend en compte 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. Cette valeur peut ensuite être utilisée pour améliorer la précision des calculs de la mémoire 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.

Suppression de la variabilité Memtrack de la RAM perdue

Étant donné que les implémentations HAL Memtrack peuvent varier d'un partenaire à l'autre, la mémoire GPU incluse dans totalPSS à partir de la 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 totale de la zone de marché désignée 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 un noyau Linux 5.4 ou une version ultérieure sont compatibles avec l'API getGpuDeviceInfo().

Une nouvelle API HAL Memtrack getGpuDeviceInfo() doit renvoyer des informations sur l'appareil GPU utilisé.

Cela améliore la comptabilisation de la mémoire et la visibilité sur la mémoire tampon de la zone de marché désignée et l'utilisation de la mémoire 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 AIDL Memtrack et les instructions pour l'implémenter 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 points de trace dans vos pilotes de GPU et implémentez l'API AIDL memtrack HAL getMemory() afin de renvoyer correctement la mémoire globale privée du GPU lorsqu'elle est appelée avec le PID 0 pour MemtrackType::GL et MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.