בדף הזה מתוארות השיפורים השונים בדיווח על שימוש בזיכרון שנוספו ב-Android 12.
נתונים סטטיסטיים של DMA-BUF ב-sysfs
בגרסאות Android 11 ו-Android 12, לא ניתן להשתמש ב-debugfs
טעונה בגרסאות build של משתמשים. לכן, הנתונים הסטטיסטיים של DMA-BUF נוספו לקובץ sysfs
בתיקייה /sys/kernel/dmabuf/buffers
ב-Android 12.
נתיב | תיאור |
---|---|
/sys/kernel/dmabuf/buffers
|
הספרייה /sys/kernel/dmabuf/buffers מכילה קובץ snapshot של המצב הפנימי של כל 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 בבייטים. |
ה-API של libdmabufinfo
מפרק את הנתונים הסטטיסטיים של DMA-BUF sysfs
כדי לחשוף נתונים סטטיסטיים לכל ייצוא ולכל מאגר.
חשוב לשים לב שמנהלי התקנים של ליבה (kernel) שמייצאים DMA-BUF חייבים להגדיר את הערך exp_name
שדה struct dma_buf_export_info
בצורה נכונה לשם המייצא לפני
הפעלת ה-API dma_buf_export()
כדי ליצור DMA-BUF.
הרשאה זו נדרשת ל-libdmabufinfo
ולכלי dmabuf_dump
כדי להפיק סטטיסטיקות לכל גורם ייצוא, שיוצגו לאחר מכן ב-bugreport.
הכלי dmabuf_dump השתנה כך שיפיק את המידע הזה עם ארגומנט חדש, -b
.
נתונים סטטיסטיים לגבי מסגרת ה-heaps של DMA-BUF
אנחנו מוציאים משימוש את ION ב-GKI 2.0 לטובת מסגרת הערימה (heaps framework) של DMA-BUF. שהיא חלק מהליבה של Linux ב-upstream.
ב-Android 11 מתבצע מעקב אחר הנתונים הסטטיסטיים הגלובליים הבאים של ION:
- הגודל הכולל של DMA-BUFs שיוצאו על ידי כל ערימה (heap) של ION
- הגודל הכולל של הזיכרון שהוקצה מראש ולא נמצא בשימוש, שנשמר בכל ערימה של ION
אין ממשק זמין לחשיפת נתונים סטטיסטיים לכל ערימה של ION ב-Android 11.
הטבלה הבאה משווה בין ממשקי הנתונים הסטטיסטיים של ION עם מקבילים לאלה של מכשירים שמשתמשים במסגרת הערימה (heap framework) של DMA-BUF ב-Android 12.
Android 11 או מכשירים שיושקו עם תמיכה ב-ION ב-Android 12 | מכשירים שמושקים עם ערימות של DMA-BUF ב-Android 12 | |
---|---|---|
נתונים סטטיסטיים של ION לכל אשכול | ללא | ניתוח מנתונים סטטיסטיים של sysfs ב-DMA-BUF |
הגודל הכולל של DMA-BUFs שמיוצאים | /sys/kernel/ion/total_heap_size_kb
(לא כולל את הגודל של DMA-BUFs שיוצאו על ידי גורמים מייצאים שאינם ION) |
ניתוח מנתוני sysfs של DMA-BUF
(כולל את הגודל של כל DMA-BUFs שיוצאו). |
סך כל הזיכרון שנאסף בקטגוריות של ערימה (heap) | /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-BUFs שממופים למרחב הכתובות של ה-GPU
לכן, כאשר חישבו את נפח ה-RAM שאבד, DMA-BUFs ששויכו למרחב הזיכרון במרחב הכתובות של ה-GPU הופחתו פעמיים. 12 Android משתמשת בפתרון לחישוב הגודל של DMA-BUF שממופים ל-GPU כלומר, הוא נספר רק פעם אחת בדוח 'אבדות חישוב ה-RAM.
פרטי הפתרון הם:
- כשמפעילים את Memtrack HAL API
getMemory()
עם PID 0, הוא צריך לדווח על נפח הזיכרון הכולל ברמת ה-GPU, עבור MemtrackType::GL ו-MemtrackRecord::FLAG_SMAPS_UNACCOUNTED. - כשנשלחת קריאה ל-getMemory() עם
PID
0
עבורMemtrackType
שאינוGL
, אסור שהיא תיכשל. במקום זאת, הוא צריך להחזיר את הערך 0. - פתרון trackingpoint/eBPF של הזיכרון של GPU שנוספו לחשבונות Android 12 כדי ליהנות מהזיכרון הכולל של ה-GPU. מחסרים את סך הזיכרון הפרטי של GPU מהזיכרון הכולל של ה-GPU, הגודל של מזהי DMA-BUF שממופים למרחב הכתובות של ה-GPU. לאחר מכן אפשר להשתמש בערך הזה כדי לשפר את הדיוק של החישובים של זיכרון RAM שאבד, על ידי התייחסות נכונה לשימוש בזיכרון ה-GPU.
- זיכרון ה-GPU הפרטי נכלל ב-
totalPss
ברוב הטמעות ה-HAL של Memtrack, ולכן צריך לבטל את הכפילויות שלו לפני שמסירים אותו מ-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 ואילך תומכים ב-API getGpuDeviceInfo().
ממשק 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();
כדי לוודא שהגרסה פועלת כמצופה, צריך לשלב את נקודות המעקב (tracepoints) בנהגים של ה-GPU ולהטמיע את ה-API של memtrack HAL getMemory()
ב-AIDL כדי להחזיר בצורה נכונה את הזיכרון הכולל הגלובלי של GPU פרטי כשמבצעים קריאה עם PID 0 עבור MemtrackType::GL ו-MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.