Android 12'de DMABUF ve GPU bellek muhasebesini uygulama

Bu sayfada, Android 12'de kullanıma sunulan çeşitli bellek hesabı iyileştirmeleri açıklanmaktadır.

sysfs'teki DMA-BUF istatistikleri

Android 11 ve Android 12'de debugfs, kullanıcı derlemelerine monte edilemez. Bu nedenle, DMA-BUF istatistikleri Android 12'deki /sys/kernel/dmabuf/buffers dizininde sysfs dosyasına eklendi.

Yol Açıklama
/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>, <inode_number> benzersiz inode numarasına sahip 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 göstermek için DMA-BUF sysfs istatistiklerini ayrıştırır.

DMA-BUF'ları dışa aktaran çekirdek sürücülerinin, DMA-BUF oluşturmak için dma_buf_export() API'yi çağırmadan önce struct dma_buf_export_info exp_name alanının dışa aktarıcı adına doğru şekilde ayarlanması gerektiğini lütfen unutmayın. Bu, libdmabufinfo ve dmabuf_dump aracının dışa aktarıcı başına istatistikler oluşturması için gereklidir. Bu istatistikler daha sonra bugreport'ta gösterilir.

dmabuf_dump aracı, bu bilgileri yeni bir bağımsız değişkenle (-b) döndürecek şekilde değiştirildi.

DMA-BUF yığınları çerçevesi için istatistikler

GKI 2.0'daki ION'un desteği sonlandırılıyor ve yerine, yayın öncesi Linux çekirdeğinin bir parçası olan DMA-BUF yığınları çerçevesi kullanılacak.

Android 11'de aşağıdaki küresel ION istatistikleri izlenir:

  • Her ION yığını tarafından dışa aktarılan DMA-BUF'ların toplam boyutu
  • Her ION yığını tarafından depolanan kullanılmayan önceden ayrılmış belleğin toplam boyutu

Android 11'de ION yığın başına istatistikleri göstermek için kullanılabilecek bir arayüz yoktur.

Aşağıdaki tabloda, ION istatistik arayüzleri Android 12'de DMA-BUF yığın çerçevesini kullanan cihazlardaki benzerleriyle karşılaştırılmaktadır.

Android 11 veya Android 12'de ION desteğiyle kullanıma sunulan cihazlar Android 12'de DMA-BUF yığınlarıyla kullanıma sunulan cihazlar
Her yığın için ION istatistikleri Yok DMA-BUF sysfs istatistiklerinden ayrıştırılır.
Dışa aktarılan DMA-BUF'ların toplam boyutu /sys/kernel/ion/total_heap_size_kb
(ION olmayan dışa aktarıcılar tarafından dışa aktarılan DMA-BUF'ların boyutunu içermez)
DMA-BUF sysfs istatistiklerinden ayrıştırılır
(dışa aktarılan tüm DMA-BUF'ların boyutunu içerir).
Toplu olarak ayrılan toplam bellek /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Kayıp RAM hesaplamasının doğruluğunu iyileştirme

Daha önce, kaybedilen RAM hesaplaması aşağıdaki ş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ı (Memtrack HAL'ın getMemory() arayüzü tarafından döndürülür) içeriyordu. kernelUsed bileşeni, toplam DMA-BUF bellek kullanımını içeriyordu. Ancak Android cihazlarda GPU belleği aşağıdaki kaynaklardan alınmıştır:

  • Fiziksel sayfa ayırıcıyı kullanarak GPU sürücüsü tarafından yapılan doğrudan ayırmalar
  • GPU adres alanına eşlenen DMA-BUF'lar

Bu nedenle, GPU adres alanına bellek eşlenen DMA-BUF'lar, kaybedilen RAM hesaplanırken iki kez çıkarıldı. Android 12, GPU adres alanına eşlenen DMA-BUF'ların boyutunu hesaplamak için bir çözüm uygular. Bu, kayıp RAM hesaplamasında yalnızca bir kez hesaba katılması anlamına gelir.

Çözümün ayrıntıları aşağıda verilmiştir:

  • Memtrack HAL API'si getMemory(), PID 0 ile çağrıldığında MemtrackType::GL ve MemtrackRecord::FLAG_SMAPS_UNACCOUNTED için küresel toplam GPU özel belleğini bildirmelidir.
  • GL dışında bir MemtrackType için PID 0 ile çağrılan getMemory() başarısız olmamalıdır. Bunun yerine 0 döndürmelidir.
  • Android 12'de eklenen GPU bellek izleme noktası/eBPF çözümü, toplam GPU belleğini hesaba katar. Toplam GPU özel belleği toplam GPU belleğinden çıkarılarak GPU adres alanına eşlenen DMA-BUF'ların boyutu elde edilir. Bu değer daha sonra GPU bellek kullanımını doğru şekilde hesaba katarak kayıp RAM hesaplamalarının doğruluğunu iyileştirmek için kullanılabilir.
  • Özel GPU belleği, çoğu Memtrack HAL uygulamasında totalPss'e dahil olduğundan lostRAM'ten kaldırılmadan önce tekilleştirilmelidir.

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

Kayıp RAM'den Memtrack değişkenliğini kaldırma

Memtrack HAL uygulamaları iş ortakları arasında farklılık gösterebileceğinden, HAL'den totalPSS içine eklenen GPU belleği her zaman tutarlı değildir. lostRAM'teki değişkenliği kaldırmak için lostRAM hesaplaması sırasında MemtrackType::GRAPHICS ve MemtrackType::GL'de hesaba katılan bellek totalPss'ten kaldırılır.

MemtrackType::GRAPHICS belleği totalPss'dan kaldırılır ve aşağıdaki 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'dan kaldırılır ve ActivityManagerService.java 'daki lostRAM hesaplamasında aşağıdaki gibi ö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;

Güncellenen kayıp RAM hesaplaması

Hem toplam özel GPU belleği hem de toplam dışa aktarılan DMA arabellek belleği, lostRAM'ten kaldırılan kernelUsed + totalPss içinde bulunur. Bu sayede, kaybedilen RAM hesaplamasında hem çifte sayma hem de Memtrack değişkenliği ortadan kaldırılır.

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

Doğrulama

VTS testleri, Android 12'de 5.4 veya daha yeni bir Linux çekirdeği sürümüyle kullanıma sunulan cihazların getGpuDeviceInfo() API'sini desteklemesi kuralını zorunlu kılar.

Yeni bir Memtrack HAL API'si getGpuDeviceInfo(), kullanılan GPU cihazıyla ilgili bilgileri döndürmelidir.

Bu sayede DMA arabelleği ve GPU bellek kullanımıyla ilgili daha iyi bir bellek muhasebesi ve görünürlük elde edilir. Kaybedilen RAM ve bellek hesaplarını daha iyi yönetmek için memtrack AIDL HAL'i uygulayın. Bu özellik Google hizmetlerine bağlı değildir.

Uygulama

Bu özellik, AIDL Memtrack HAL'e bağlıdır ve Android 12'de uygulama talimatları koda yorum olarak eklenmiştir.

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

Aşağıdaki API'ler core/java/android/os/Debug.java'e eklendi:

   /**
     * 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ığı şekilde çalıştığından emin olmak için izleme noktalarını GPU sürücülerinize entegre edin ve MemtrackType::GL ve MemtrackRecord::FLAG_SMAPS_UNACCOUNTED için PID 0 ile çağrıldığında global toplam GPU özel belleğini doğru şekilde döndürmek üzere AIDL memtrack HAL getMemory() API'sini uygulayın.