Mengimplementasikan DMABUF dan penghitungan memori GPU di Android 12

Halaman ini menjelaskan berbagai peningkatan penghitungan memori yang diperkenalkan di Android 12.

Statistik DMA-BUF di sysfs

Di Android 11 dan Android 12, debugfs tidak dapat dipasang di build Pengguna. Jadi, statistik DMA-BUF telah ditambahkan ke sysfs di direktori /sys/kernel/dmabuf/buffers di Android 12.

Jalur Deskripsi
/sys/kernel/dmabuf/buffers Direktori /sys/kernel/dmabuf/buffers berisi snapshot status internal setiap DMA-BUF. /sys/kernel/dmabuf/buffers/<inode_number> berisi statistik untuk DMA-BUF dengan nomor inode unik <inode_number>.
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name File hanya baca ini berisi nama pengekspor DMA-BUF.
/sys/kernel/dmabuf/buffers/<inode_number>/size File hanya-baca ini menentukan ukuran DMA-BUF dalam byte.

libdmabufinfo API mengurai statistik sysfs DMA-BUF untuk mengekspos statistik per eksportir dan per buffering.

Perhatikan bahwa driver kernel yang mengekspor DMA-BUF harus menetapkan kolom exp_name struct dma_buf_export_info dengan benar ke nama eksportir sebelum memanggil dma_buf_export() API untuk membuat DMA-BUF. Hal ini diperlukan agar libdmabufinfo dan alat dmabuf_dump dapat memperoleh statistik per eksportir yang kemudian ditampilkan dalam bugreport.

Alat dmabuf_dump telah diubah untuk menghasilkan informasi ini dengan argumen baru, -b.

Statistik untuk framework heap DMA-BUF

ION di GKI 2.0 tidak digunakan lagi dan digantikan dengan framework heap DMA-BUF, yang merupakan bagian dari kernel Linux upstream.

Statistik ION global berikut dilacak di Android 11:

  • Total ukuran DMA-BUF yang diekspor oleh setiap heap ION
  • Total ukuran memori yang dialokasikan sebelumnya yang tidak digunakan dan disimpan oleh setiap heap ION

Tidak ada antarmuka yang tersedia untuk mengekspos statistik heap per ION di Android 11.

Tabel berikut membandingkan antarmuka statistik ION dengan pembanding untuk perangkat yang menggunakan framework heap DMA-BUF di Android 12.

Android 11 atau Perangkat yang diluncurkan dengan dukungan ION di Android 12 Perangkat yang diluncurkan dengan heap DMA-BUF di Android 12
Statistik ION per heap Tidak ada Diurai dari statistik sysfs DMA-BUF
Total ukuran DMA-BUF yang diekspor /sys/kernel/ion/total_heap_size_kb
(Tidak termasuk ukuran DMA-BUF yang diekspor oleh pengekspor non-ION)
Ditafsirkan dari statistik sysfs DMA-BUF
(menyertakan ukuran semua DMA-BUF yang diekspor).
Total memori yang digabungkan oleh heap /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

Meningkatkan akurasi penghitungan RAM yang hilang

Sebelumnya perhitungan RAM yang hilang dilakukan sebagai berikut:

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

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

- kernelUsed - memInfo.getZramTotalSizeKb();

Komponen totalPss menyertakan penggunaan memori GPU (yang ditampilkan oleh antarmuka getMemory() Memtrack HAL). Komponen kernelUsed mencakup total penggunaan memori DMA-BUF. Namun, untuk perangkat Android, memori GPU berasal dari hal berikut:

  • Alokasi langsung yang dibuat oleh driver GPU menggunakan alokator halaman fisik
  • DMA-BUF yang dipetakan ke ruang alamat GPU

Oleh karena itu, DMA-BUF yang dipetakan memori ke ruang alamat GPU dikurangi dua kali saat RAM yang hilang dihitung. Android 12 mengimplementasikan solusi untuk menghitung ukuran DMA-BUF yang dipetakan ke dalam ruang alamat GPU, yang berarti hal ini dihitung hanya sekali dalam penghitungan RAM Hilang.

Detail solusinya adalah sebagai berikut:

  • Memtrack HAL API getMemory() saat dipanggil dengan PID 0 harus melaporkan total memori pribadi GPU global, untuk MemtrackType::GL dan MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
  • getMemory() saat dipanggil dengan PID 0 untuk MemtrackType selain GL tidak boleh gagal. Sebagai gantinya, nilai ini harus menampilkan 0.
  • Solusi tracepoint/eBPF memori GPU ditambahkan di akun Android 12 untuk total memori GPU. Mengurangi total memori pribadi GPU dari total memori GPU akan memberikan ukuran DMA-BUF yang dipetakan ke ruang alamat GPU. Nilai tersebut kemudian dapat digunakan untuk meningkatkan akurasi penghitungan RAM yang Hilang dengan memperhitungkan penggunaan memori GPU dengan benar.
  • Memori GPU pribadi disertakan dalam totalPss di sebagian besar implementasi HAL Memtrack sehingga harus dihapus duplikatnya sebelum menghapusnya dari lostRAM.

Solusi yang diimplementasikan dijelaskan di bagian berikutnya.

Menghapus variabilitas Memtrack dari RAM yang hilang

Karena implementasi Memtrack HAL dapat bervariasi di berbagai partner, memori GPU yang disertakan dalam totalPSS dari HAL tidak selalu konsisten. Untuk menghapus variabilitas dari lostRAM, memori yang diperhitungkan dalam MemtrackType::GRAPHICS dan MemtrackType::GL dihapus dari totalPss selama penghitungan lostRAM.

Memori MemtrackType::GRAPHICS dihapus dari totalPss dan diganti dengan memori totalExportedDmabuf dalam penghitungan lostRAM di ActivityManagerService.java seperti yang ditunjukkan di bawah ini:

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;

Memori MemtrackType::GL dihapus dari totalPss dan diganti dengan memori GPU pribadi (gpuPrivateUsage) dalam penghitungan lostRAM di ActivityManagerService.java seperti yang ditunjukkan di bawah:

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;

Memperbarui penghitungan RAM yang hilang

Total memori GPU pribadi dan total memori buffer DMA yang diekspor berisi dalam kernelUsed + totalPss yang dihapus dari lostRAM. Hal ini menghilangkan penghitungan ganda dan variabilitas Memtrack dari penghitungan RAM yang hilang.

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

Validasi

Pengujian VTS menerapkan aturan bahwa perangkat yang diluncurkan di Android 12 dengan kernel Linux versi 5.4 atau yang lebih tinggi mendukung getGpuDeviceInfo() API.

getGpuDeviceInfo() Memtrack HAL API baru harus menampilkan informasi tentang perangkat GPU yang digunakan.

Hal ini memberikan penghitungan dan visibilitas memori yang lebih baik ke buffer DMA dan penggunaan memori GPU. Terapkan HAL AIDL memtrack untuk akun RAM dan memori yang hilang yang lebih baik. Fitur ini tidak bergantung pada layanan Google.

Implementasi

Fitur ini bergantung pada AIDL Memtrack HAL, dan petunjuk untuk menerapkannya di Android 12 disertakan dalam kode sebagai komentar.

Semua HIDL HAL direncanakan akan dikonversi ke AIDL dalam rilis mendatang.

API berikut telah ditambahkan ke 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();

Untuk memastikan versi Anda berfungsi sebagaimana mestinya, integrasikan tracepoint di driver GPU, dan terapkan AIDL memtrack HAL getMemory() API untuk menampilkan total memori pribadi GPU global dengan benar saat dipanggil dengan PID 0 untuk MemtrackType::GL dan MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.