בדף הזה מתוארות השיפורים השונים בדיווח על שימוש בזיכרון שנוספו ב-Android 12.
נתונים סטטיסטיים של DMA-BUF ב-sysfs
ב-Android 11 וב-Android 12, אי אפשר לטעון את debugfs
ב-builds של משתמשים. לכן, הנתונים הסטטיסטיים של 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
כדי לחשוף נתונים סטטיסטיים לכל ייצוא ולכל מאגר.
חשוב לזכור שמנהלי ליבה שמייצאים DMA-BUFs חייבים להגדיר את השדה 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 הוצא משימוש והוחלף על ידי מסגרת DMA-BUF heaps, שמהווה חלק מליבת Linux במקור.
ב-Android 11 מתבצע מעקב אחרי הנתונים הסטטיסטיים הגלובליים הבאים של ION:
- הגודל הכולל של DMA-BUFs שיוצאו על ידי כל ערימה (heap) של ION
- הגודל הכולל של הזיכרון שהוקצה מראש ולא נמצא בשימוש, שנשמר בכל אשכול ION
אין ממשק זמין לחשיפת נתונים סטטיסטיים לכל ערימה של ION ב-Android 11.
בטבלה הבאה מוצגת השוואה בין ממשקי הנתונים הסטטיסטיים של ION לבין הממשקים המקבילים שלהם במכשירים שמשתמשים במסגרת ה-heap של DMA-BUF ב-Android 12.
Android 11 או מכשירים שיושקו עם תמיכה ב-ION ב-Android 12 | מכשירי Android 12 שפועלים עם אשכולות DMA-BUF | |
---|---|---|
נתונים סטטיסטיים של ION לכל אשכול | ללא | ניתוח מנתונים סטטיסטיים של sysfs ב-DMA-BUF |
הגודל הכולל של DMA-BUFs שמיוצאים | /sys/kernel/ion/total_heap_size_kb
(לא כולל את הגודל של DMA-BUFs שיוצאו על ידי גורמים מייצאים שאינם ION) |
ניתוח מנתוני sysfs של DMA-BUF
(כולל את הגודל של כל ה-DMA-BUFs שיוצאו). |
סך כל הזיכרון שנאסף בערימה | /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 הופחתו פעמיים. ב-Android 12 מוטמעת פתרון לחישוב הגודל של DMA-BUFs שממופים למרחב הכתובות של ה-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-BUFs שממופים למרחב הכתובות של ה-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 כלולות בקוד בתור תגובות.
כל ממשקי ה-HAL של HIDL צפויים להפוך ל-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.