Android 12'de DMABUF ve GPU bellek hesaplamasını uygulayın

Bu sayfada Android 12'de sunulan çeşitli bellek hesaplama iyileştirmeleri açıklanmaktadır.

Sysfs'te DMA-BUF istatistikleri

Android 11 ve Android 12'de debugfs Kullanıcı derlemelerine eklenemez. Bu nedenle Android 12'de /sys/kernel/dmabuf/buffers dizinindeki sysfs DMA-BUF istatistikleri eklendi.

Yol Tanım
/sys/kernel/dmabuf/buffers /sys/kernel/dmabuf/buffers dizini her DMA-BUF'un dahili durumunun anlık görüntüsünü içerir. /sys/kernel/dmabuf/buffers/<inode_number> benzersiz inode numarası <inode_number> ile DMA-BUF istatistiklerini içerir.
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name Bu salt okunur dosya DMA-BUF dışa aktarıcısının adını içerir.
/sys/kernel/dmabuf/buffers/<inode_number>/size Bu salt okunur dosya DMA-BUF'un bayt cinsinden boyutunu belirtir.

libdmabufinfo API, dışa aktarıcı ve arabellek başına istatistikleri ortaya çıkarmak için DMA-BUF sysfs istatistiklerini ayrıştırır.

DMA-BUF'leri dışa aktaran çekirdek sürücülerinin, bir DMA-BUF oluşturmak için dma_buf_export() API'sini çağırmadan önce struct dma_buf_export_info exp_name alanını dışa aktarıcı adına doğru şekilde ayarlaması gerektiğini lütfen unutmayın. Bu, libdmabufinfo ve dmabuf_dump aracının, daha sonra hata raporunda gösterilen ihracatçı başına istatistikleri türetmesi için gereklidir.

dmabuf_dump aracı, bu bilgiyi yeni bir argüman olan -b ile verecek şekilde değiştirildi.

DMA-BUF yığın çerçevesine ilişkin istatistikler

GKI 2.0'daki ION, yukarı akışlı linux çekirdeğinin bir parçası olan DMA-BUF yığın çerçevesi lehine kullanımdan kaldırılıyor.

Aşağıdaki global ION istatistikleri Android 11'de izlenir:

  • Her ION yığını tarafından dışa aktarılan DMA-BUF'lerin toplam boyutu
  • Her ION yığınında depolanan, kullanılmayan, önceden tahsis edilmiş belleğin toplam boyutu

Android 11'de ION başına yığın istatistiklerini ortaya çıkaracak bir arayüz yoktur.

Aşağıdaki tablo, Android 12'de DMA-BUF yığın çerçevesini kullanan cihazlar için ION istatistik arayüzlerini benzerleriyle karşılaştırmaktadır.

Android 11 veya Android 12'de ION desteğiyle başlatılan cihazlar Android 12'de DMA-BUF yığınlarıyla başlatılan cihazlar
Yığın başına ION istatistikleri Hiçbiri DMA-BUF sysfs istatistiklerinden ayrıştırıldı
Dışa aktarılan DMA-BUF'lerin toplam boyutu /sys/kernel/ion/total_heap_size_kb
(ION dışı ihracatçılar tarafından ihraç edilen DMA-BUF'lerin boyutunu içermez)
DMA-BUF sysfs istatistiklerinden ayrıştırıldı
(dışa aktarılan tüm DMA-BUF'lerin boyutunu içerir).
Yığınlara göre havuzlanan toplam bellek /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Kayıp RAM hesaplama doğruluğunu iyileştirin

Daha önce kayıp RAM hesaplaması şu şekilde yapılıyordu:

son uzun lostRAM = memInfo.getTotalSizeKb( ) - ( totalPss - totalSwapPss )

- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()

- kernelUsed - memInfo.getZramTotalSizeKb() ;

totalPss bileşeni, GPU bellek kullanımını içeriyordu (Memtrack HAL'ın getMemory() arayüzü tarafından döndürüldü). kernelUsed bileşeni toplam DMA-BUF bellek kullanımını içeriyordu. Ancak Android cihazlar için GPU belleği aşağıdakilerden geldi:

  • GPU sürücüsü tarafından fiziksel sayfa ayırıcı kullanılarak yapılan doğrudan ayırmalar
  • GPU adres alanına eşlenen DMA-BUF'ler

Bu nedenle, GPU adres alanına bellek eşlemeli DMA-BUF'ler, kayıp RAM hesaplanırken iki kez çıkarıldı. Android 12, GPU adres alanına eşlenen DMA-BUF'lerin boyutunu hesaplamak için bir çözüm uygular; bu, Kayıp RAM hesaplamasında bunun yalnızca bir kez hesaba katıldığı anlamına gelir.

Çözümün detayları şu şekilde:

  • Memtrack HAL API getMemory() PID 0 ile çağrıldığında, MemtrackType::GL ve MemtrackRecord::FLAG_SMAPS_UNACCOUNTED için genel toplam GPU-özel belleğini raporlamalıdır.
  • getMemory(), GL dışında bir MemtrackType için PID 0 ile çağrıldığında başarısız olmamalıdır. Bunun yerine 0 döndürmesi gerekir.
  • Android 12'ye eklenen GPU bellek izleme noktası/eBPF çözümü, toplam GPU belleğini oluşturur. Toplam GPU özel belleğinin toplam GPU belleğinden çıkarılması, GPU adres alanına eşlenen DMA-BUF'lerin boyutunu sağlar. Değer daha sonra GPU bellek kullanımını doğru şekilde hesaba katarak Kayıp RAM hesaplamalarının doğruluğunu artırmak için kullanılabilir.
  • Özel GPU belleği, çoğu Memtrack HAL uygulamasında totalPss dahil edilir ve bu nedenle, lostRAM çıkarılmadan önce tekilleştirilmesi gerekir.

Uygulanan çözüm bir sonraki bölümde ayrıntılı olarak anlatılmıştır.

Memtrack değişkenliğini kayıp RAM'den kaldırın

Memtrack HAL uygulamaları iş ortakları arasında değişiklik gösterebileceğinden, HAL'den totalPSS dahil edilen GPU belleği her zaman tutarlı değildir. lostRAM değişkenliği ortadan kaldırmak için, MemtrackType::GRAPHICS ve MemtrackType::GL hesaplanan bellek, lostRAM hesaplaması sırasında totalPss kaldırılır.

MemtrackType::GRAPHICS belleği totalPss kaldırılır ve aşağıda gösterildiği gibi ActivityManagerService.java'daki lostRAM hesaplamasında totalExportedDmabuf belleğiyle değiştirilir:

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;

MemtrackType::GL belleği totalPss kaldırılır ve aşağıda gösterildiği gibi ActivityManagerService.java'daki lostRAM hesaplamasında özel GPU belleği ( gpuPrivateUsage ) ile değiştirilir:

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;

Kayıp RAM hesaplaması güncellendi

Hem toplam özel GPU belleği hem de toplam dışa aktarılan DMA ara belleği, lostRAM kaldırılan kernelUsed + totalPss içinde bulunur. Bu, kayıp RAM hesaplamasında hem çift sayımı hem de Memtrack değişkenliğini ortadan kaldırır.

final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();

Doğrulama

VTS testleri, Android 12'de Linux çekirdeği sürüm 5.4 veya daha yüksek bir sürümle başlatılan cihazların getGpuDeviceInfo() API'sini desteklemesi kuralını uygular.

Yeni bir Memtrack HAL API'si getGpuDeviceInfo() kullanılan GPU cihazı hakkında bilgi döndürmelidir.

Bu, daha iyi bellek hesaplaması ve DMA arabellek ve GPU bellek kullanımına ilişkin görünürlük sağlar. Daha iyi kayıp RAM ve bellek hesaplaması için memtrack AIDL HAL'i uygulayın. Bu özellik Google hizmetlerine bağlı değildir.

Uygulama

Bu özellik AIDL Memtrack HAL'a bağlıdır ve bunu Android 12'de uygulamaya yönelik talimatlar kodda yorum olarak yer almaktadır.

Gelecek sürümlerde tüm HIDL HAL'lerin AIDL'ye dönüştürülmesi planlanmaktadır.

Aşağıdaki API'ler core/java/android/os/Debug.java dosyasına eklenmiştir:

   /**
     * 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();

Sürümünüzün amaçlandığı gibi çalıştığından emin olmak için, izleme noktalarını GPU sürücülerinize entegre edin ve MemtrackType::GL ve MemtrackRecord:: için PID 0 ile çağrıldığında genel toplam GPU-özel belleğini doğru şekilde döndürmek için AIDL memtrack HAL getMemory() API'sini uygulayın. FLAG_SMAPS_UNACCOUNTED.