ใช้ DMABUF และการบัญชีหน่วยความจำ GPU ใน Android 12

หน้านี้อธิบายการปรับปรุงการบัญชีหน่วยความจำต่างๆ ที่เปิดตัวใน Android 12

สถิติ DMA-BUF ใน sysfs

ใน Android 11 และ Android 12 debugfs จะ เมานต์ในบิลด์ของผู้ใช้ไม่ได้ เราจึงเพิ่มสถิติ DMA-BUF ลงใน sysfs ในไดเรกทอรี /sys/kernel/dmabuf/buffers ใน Android 12

เส้นทาง คำอธิบาย
/sys/kernel/dmabuf/buffers ไดเรกทอรี /sys/kernel/dmabuf/buffers มีสแนปชอตของ สถานะภายในของ DMA-BUF ทุกรายการ /sys/kernel/dmabuf/buffers/<inode_number> มีสถิติสำหรับ DMA-BUF ที่มีหมายเลข inode ที่ไม่ซ้ำกัน <inode_number>
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name ไฟล์แบบอ่านอย่างเดียวนี้มีชื่อของโปรแกรมส่งออก DMA-BUF
/sys/kernel/dmabuf/buffers/<inode_number>/size ไฟล์แบบอ่านอย่างเดียวนี้จะระบุขนาดของ DMA-BUF ในหน่วยไบต์

libdmabufinfo API จะแยกวิเคราะห์สถิติ DMA-BUF sysfs เพื่อแสดงสถิติต่อผู้ส่งออกและต่อบัฟเฟอร์

โปรดทราบว่าไดรเวอร์เคอร์เนลที่ส่งออก DMA-BUF ต้องตั้งค่าฟิลด์ exp_name ของ struct dma_buf_export_info ให้ถูกต้องเป็นชื่อผู้ส่งออกก่อน เรียกใช้ API dma_buf_export() เพื่อสร้าง DMA-BUF ซึ่งจำเป็นสำหรับ libdmabufinfo และเครื่องมือ dmabuf_dump เพื่อรับสถิติต่อผู้ส่งออก ซึ่งจะแสดงในรายงานข้อบกพร่อง

เราได้แก้ไขเครื่องมือ dmabuf_dump เพื่อแสดงข้อมูลนี้ด้วยอาร์กิวเมนต์ใหม่ -b

สถิติสำหรับเฟรมเวิร์กฮีป DMA-BUF

เราจะเลิกใช้งาน ION ใน GKI 2.0 เพื่อใช้เฟรมเวิร์กฮีป DMA-BUF แทน ซึ่งเป็นส่วนหนึ่งของเคอร์เนล Linux ต้นทาง

Android 11 จะติดตามสถิติ ION ทั่วโลกต่อไปนี้

  • ขนาดรวมของ DMA-BUF ที่ส่งออกโดยกอง ION ทุกกอง
  • ขนาดรวมของหน่วยความจำที่จัดสรรล่วงหน้าที่ไม่ได้ใช้ซึ่งจัดเก็บโดยฮีป ION ทุกรายการ

ไม่มีอินเทอร์เฟซที่พร้อมใช้งานเพื่อแสดงสถิติฮีปต่อ ION ใน Android 11

ตารางต่อไปนี้เปรียบเทียบอินเทอร์เฟซสถิติ ION กับอินเทอร์เฟซที่เทียบเท่าสำหรับอุปกรณ์ที่ใช้เฟรมเวิร์กฮีป DMA-BUF ใน Android 12

Android 11 หรืออุปกรณ์ที่เปิดตัวพร้อมรองรับ ION ใน Android 12 อุปกรณ์ที่เปิดตัวพร้อมฮีป DMA-BUF ใน Android 12
สถิติ ION ต่อฮีป ไม่มี แยกวิเคราะห์จากสถิติ sysfs ของ DMA-BUF
ขนาดรวมของ DMA-BUF ที่ส่งออก /sys/kernel/ion/total_heap_size_kb
(ไม่รวมขนาดของ DMA-BUF ที่ส่งออกโดยผู้ส่งออกที่ไม่ใช่ ION)
แยกวิเคราะห์จากสถิติ sysfs ของ DMA-BUF
(รวมขนาดของ DMA-BUF ทั้งหมดที่ส่งออก)
หน่วยความจำทั้งหมดที่จัดกลุ่มตามฮีป /sys/kernel/ion/total_pool_size_kb /sys/kernel/dma_heap/total_pool_size_kb

ปรับปรุงความแม่นยำในการคำนวณ RAM ที่สูญเสียไป

ก่อนหน้านี้ การคำนวณ RAM ที่สูญเสียไปทำได้ดังนี้

lostRAM สุดท้าย = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)

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

- kernelUsed - memInfo.getZramTotalSizeKb()

คอมโพเนนต์ totalPss มีการใช้งานหน่วยความจำ GPU (ส่งคืนโดย อินเทอร์เฟซ getMemory() ของ Memtrack HAL) คอมโพเนนต์ kernelUsed มีการใช้งานหน่วยความจำ DMA-BUF ทั้งหมด อย่างไรก็ตาม สำหรับอุปกรณ์ Android หน่วยความจำ GPU มาจากแหล่งที่มาต่อไปนี้

  • การจัดสรรโดยตรงที่ไดรเวอร์ GPU ทำโดยใช้ตัวจัดสรรหน้าจริง
  • แมป DMA-BUF ลงในพื้นที่ที่อยู่ GPU

ดังนั้น DMA-BUF ที่แมปหน่วยความจำลงในพื้นที่ที่อยู่ GPU จึงถูกหักออก 2 ครั้งเมื่อคำนวณ RAM ที่สูญเสียไป Android 12 ใช้โซลูชันในการคำนวณขนาดของ DMA-BUF ที่แมปกับพื้นที่ที่อยู่ของ GPU ซึ่งหมายความว่าระบบจะนับรวม เพียงครั้งเดียวในการคำนวณ RAM ที่สูญเสียไป

รายละเอียดของโซลูชันมีดังนี้

  • API ของ Memtrack HAL getMemory() เมื่อเรียกใช้ด้วย PID 0 ต้องรายงานหน่วยความจำส่วนตัวของ GPU ทั้งหมดทั่วโลกสำหรับ MemtrackType::GL และ MemtrackRecord::FLAG_SMAPS_UNACCOUNTED
  • getMemory() เมื่อเรียกใช้กับ PID 0 สำหรับ MemtrackType อื่นที่ไม่ใช่ GL ต้องไม่ล้มเหลว แต่ต้องแสดงผลเป็น 0 แทน
  • โซลูชันจุดติดตามหน่วยความจำ GPU/eBPF ที่เพิ่มใน Android 12 จะพิจารณาหน่วยความจำ GPU ทั้งหมด การลบหน่วยความจำส่วนตัวทั้งหมดของ GPU ออกจากหน่วยความจำทั้งหมดของ GPU จะได้ขนาดของ DMA-BUF ที่แมปกับพื้นที่ที่อยู่ของ GPU จากนั้นจะใช้ค่าดังกล่าว เพื่อปรับปรุงความแม่นยำของการคำนวณ RAM ที่สูญเสียไปได้โดยการพิจารณา การใช้งานหน่วยความจำ GPU อย่างถูกต้อง
  • หน่วยความจำ GPU ส่วนตัวรวมอยู่ใน totalPss ในการติดตั้งใช้งาน Memtrack HAL ส่วนใหญ่ จึงต้องขจัดข้อมูลที่ซ้ำกันก่อนที่จะนำออกจาก lostRAM

โปรดดูรายละเอียดโซลูชันที่ใช้ในส่วนถัดไป

นำความแปรปรวนของ Memtrack ออกจาก RAM ที่สูญเสียไป

เนื่องจากการติดตั้งใช้งาน Memtrack HAL อาจแตกต่างกันไปในแต่ละพาร์ทเนอร์ หน่วยความจำ GPU ที่รวมอยู่ใน totalPSS จาก HAL จึงอาจไม่สอดคล้องกันเสมอไป หากต้องการนำความแปรปรวนออกจาก lostRAM ระบบจะนำหน่วยความจำที่พิจารณาใน MemtrackType::GRAPHICS และ MemtrackType::GL ออกจาก totalPss ในระหว่างการคำนวณ lostRAM

ระบบจะนำMemtrackType::GRAPHICSหน่วยความจำออกจาก totalPss และแทนที่ด้วย totalExportedDmabufหน่วยความจำในlostRAMการคำนวณใน ActivityManagerService.java ดังที่แสดงด้านล่าง

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 ออกจาก totalPss และแทนที่ด้วย หน่วยความจำ GPU ส่วนตัว (gpuPrivateUsage) ในการคำนวณ lostRAM ใน ActivityManagerService.java ดังที่แสดงด้านล่าง

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;

การคำนวณ RAM ที่สูญเสียไปที่อัปเดตแล้ว

ทั้งหน่วยความจำ GPU ส่วนตัวทั้งหมดและหน่วยความจำบัฟเฟอร์ DMA ที่ส่งออกทั้งหมดจะ อยู่ใน kernelUsed + totalPss ซึ่งนำออกจาก lostRAM ซึ่งจะ ขจัดการนับซ้ำและความแปรปรวนของ Memtrack จากการคำนวณ RAM ที่สูญเสียไป

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

การตรวจสอบความถูกต้อง

การทดสอบ VTS จะบังคับใช้กฎที่ว่าอุปกรณ์ที่เปิดตัวใน Android 12 ที่ใช้เคอร์เนล Linux เวอร์ชัน 5.4 ขึ้นไปต้องรองรับ getGpuDeviceInfo() API

API ของ Memtrack HAL ใหม่ getGpuDeviceInfo() ต้องแสดงข้อมูลเกี่ยวกับอุปกรณ์ GPU ที่ใช้งานอยู่

ซึ่งจะช่วยให้การบัญชีหน่วยความจำและการมองเห็นบัฟเฟอร์ DMA และการใช้หน่วยความจำ GPU ดีขึ้น ใช้ memtrack AIDL HAL เพื่อการบัญชี RAM และหน่วยความจำที่สูญหายที่ดีขึ้น ฟีเจอร์นี้ไม่ได้ขึ้นอยู่กับบริการของ Google

การใช้งาน

ฟีเจอร์นี้ขึ้นอยู่กับ AIDL Memtrack HAL และวิธีการติดตั้งใช้งานใน Android 12 รวมอยู่ในโค้ดเป็นความคิดเห็น

เราวางแผนที่จะแปลง HIDL HAL ทั้งหมดเป็น AIDL ในรุ่นต่อๆ ไป

เราได้เพิ่ม API ต่อไปนี้ลงใน 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();

หากต้องการให้เวอร์ชันของคุณทำงานตามที่ต้องการ ให้ผสานรวมจุดติดตามในไดรเวอร์ GPU และใช้ AIDL memtrack HAL getMemory() API เพื่อแสดงผลหน่วยความจำส่วนตัวทั้งหมดของ GPU ทั่วโลกอย่างถูกต้องเมื่อเรียกใช้ด้วย PID 0 สำหรับ MemtrackType::GL และ MemtrackRecord::FLAG_SMAPS_UNACCOUNTED