ใช้ 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เป็นชื่อผู้ส่งออกอย่างถูกต้องก่อนเรียกใช้ dma_buf_export() API เพื่อสร้าง DMA-BUF ซึ่งจำเป็นสำหรับ libdmabufinfo และเครื่องมือ dmabuf_dump เพื่อดึงข้อมูลสถิติต่อผู้ส่งออก ซึ่งจะแสดงในรายงานข้อบกพร่อง

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

สถิติสำหรับเฟรมเวิร์กกอง DMA-BUF

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

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

  • ขนาดรวมของ 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 ที่เสียไปมีดังนี้

final long 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 ที่สูญหาย

รายละเอียดของวิธีแก้ปัญหามีดังนี้

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

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

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

เนื่องจากการใช้งาน HAL ของ Memtrack อาจแตกต่างกันไปในแต่ละพาร์ทเนอร์ หน่วยความจำ 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 ขึ้นไปต้องรองรับ API getGpuDeviceInfo()

Memtrack HAL API ใหม่ 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