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

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

สถิติ DMA-BUF ใน sysfs

ใน Android 11 และ Android 12 ไม่สามารถติดตั้ง debugfs ใน User builds ได้ ดังนั้นจึงมีการเพิ่มสถิติ 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_number>
/sys/kernel/dmabuf/buffers/<inode_number>/exporter_name ไฟล์แบบอ่านอย่างเดียวนี้มีชื่อของผู้ส่งออก DMA-BUF
/sys/kernel/dmabuf/buffers/<inode_number>/size ไฟล์แบบอ่านอย่างเดียวนี้ระบุขนาดของ DMA-BUF ในหน่วยไบต์

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

โปรดทราบว่าไดรเวอร์เคอร์เนลที่ส่งออก 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 อัปสตรีม

สถิติ 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 ต่อฮีป ไม่มี แยกวิเคราะห์จาก สถิติ DMA-BUF sysfs
ขนาดรวมของ DMA-BUF ที่ส่งออก /sys/kernel/ion/total_heap_size_kb
(ไม่รวมขนาดของ DMA-BUF ที่ส่งออกโดยผู้ส่งออกที่ไม่ใช่ ION)
แยกวิเคราะห์จากสถิติ DMA-BUF sysfs
(รวมขนาดของ 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 จะถูกลบออกสองครั้งเมื่อมีการคำนวณ 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/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

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