גודל דף של 16 KB

גודל הדף הוא רמת הפירוט שבה מערכת ההפעלה מנהלת את הזיכרון. רוב מעבדי ה-CPU כיום תומכים בגודל דף של 4KB, ולכן מערכת ההפעלה Android והאפליקציות שלה תוכננו לאופטימיזציה לגודל דף של 4KB. מעבדי ARM תומכים בגודל דף גדול יותר של 16KB, ומ-Android 15 יש ב-AOSP תמיכה גם ב-build של Android עם גודל דף של 16KB. האפשרות הזו משתמשת בנפח זיכרון נוסף, אבל משפרת את ביצועי המערכת. החל מגרסה 15 של Android, האפשרות הזו לא מופעלת כברירת מחדל, אבל היא זמינה כמצב למפתחים או כאפשרות למפתחים, כדי שספקי ציוד מקורי ומפתחי אפליקציות יוכלו להתכונן למעבר למצב 16KB בכל מקום בעתיד.

ב-Android 15 ואילך יש תמיכה ב-build של Android עם יישור ELF בגודל 16KB, שפועל עם ליבות בגודל 4KB ו-16KB החל מ-android14-6.1. כשמשתמשים בהגדרה הזו עם ליבה של 16 KB, היא צורכת יותר זיכרון אבל משפרת את ביצועי המערכת.

הגדרת מרחב המשתמש של Android ל-16 KB

יש תמיכה בדפים בגודל 16KB רק ביעדים של arm64 עם ליבות בגודל 16KB. עם זאת, יש גם אפשרות לסימולציה של מרחב משתמש בנפח 16 KB ב-x86_64 עבור Cuttlefish.

ליעדים מסוג arm64, אם משתמשים ב-Kleaf כדי ליצור את הליבה, --page_size=16k יוצר את הליבה במצב 16KB. אם משתמשים ישירות בהגדרות הליבה של Linux, אפשר לבחור דפים של 16 KB על ידי הגדרת CONFIG_ARM64_16K_PAGES במקום CONFIG_ARM64_4K_PAGES.

כדי להפעיל תמיכה בגודל דף של 16KB במרחב המשתמש של Android, צריך להגדיר את אפשרויות ה-build הבאות במוצר:

  • PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := true מסיר את ההגדרה של PAGE_SIZE, ומאפשר לרכיבים לקבוע את גודל הדף בזמן הריצה.
  • PRODUCT_MAX_PAGE_SIZE_SUPPORTED := 16384, שמבטיח שקובצי ELF של הפלטפורמה נוצרים עם יישור של 16KB. הגודל הזה גדול מהנדרש, כדי לשמור על תאימות בעתיד. עם יישור ELF בגודל 16KB, הליבה יכולה לתמוך בגדלים של דפים בגודל 4KB/16KB.

אימות הדגלים של ה-build

אחרי שבוחרים את היעד lunch, מוודאים שהדגלים של ה-build מוגדרים בצורה נכונה בסביבה:

$ source build/envsetup.sh
$ lunch target

$ get_build_var TARGET_MAX_PAGE_SIZE_SUPPORTED
16384
$ get_build_var TARGET_NO_BIONIC_PAGE_SIZE_MACRO
true

אם שתי הפקודות הקודמות מחזירות את הערכים 16384 ו-true בהתאמה, דגלים ה-build מוגדרים בצורה נכונה לעבודה עם ליבה של 16 KB. עם זאת, גם אם ה-build עובר, עדיין יכולות להיות בעיות בסביבת זמן הריצה בגלל הבדלים בסביבה של 16 KB.

תכנות מערכת בגודל דף של 16KB

רוב הקוד בכל מכשיר עם Android לא מתייחס ישירות לגודל הדף. עם זאת, בקוד שעובד עם דפים, אופן הקצאת הזיכרון בליבה משתנה, וצריך לזכור את זה כדי לכתוב קוד שהוא לא רק תואם, אלא גם בעל ביצועים מרביים ושימוש מינימלי במשאבים.

אם קוראים ל-mmap באזור של 1KB,‏ 2KB או עד 4KB במערכת של 4KB, המערכת שומרת 4KB כדי להטמיע את זה. במילים אחרות, כששולחים בקשה לזיכרון מהליבה, הליבה תמיד צריכה לעגל את הזיכרון המבוקש לגודל הדף הקרוב ביותר. לדוגמה, אם מקצים אזור של 5KB באזור של 4KB, הליבה מקצה 8KB.

בליבה של 16KB, 'הזנבות' הנוספים של הדפים גדולים יותר. לדוגמה, כל ההקצאות האלה, מ-1KB עד 5KB, יוקצו בגודל 16KB כשמשתמשים בליבה בגודל 16KB. אם מבקשים 17KB, המערכת מקצה 32KB.

לדוגמה, במערכת של 4KB, אפשר להקצות שני אזורים אנונימיים של קריאה וכתיבה בגודל 4KB. עם זאת, בליבה (kernel) של 16KB, המשמעות היא הקצאה של שני דפים או 32KB. בליבה (kernel) של 16KB, אם אפשר, אפשר לשלב את האזורים האלה בדף אחד לקריאה או לכתיבה, כך שנעשה שימוש רק ב-16KB, וזהו בזבוז של 8KB בהשוואה למקרה של ליבה (kernel) של 4KB. כדי לצמצם עוד יותר את השימוש בזיכרון, אפשר לשלב עוד דפים. למעשה, במערכת של 16KB שעברה אופטימיזציה מקסימלית, דפים בגודל 16KB דורשים פחות זיכרון מאשר מערכות של 4KB, כי טבלת הדפים היא רבע מהגודל של אותה זיכרון.

בכל פעם שמשתמשים ב-mmap, חשוב לעגל את הגודל המבוקש לגודל הדף הקרוב ביותר. כך ניתן להבטיח שכל נפח הזיכרון שהליבה מקצה גלוי ישירות למרחב המשתמש בערכי זמן הריצה, במקום לבקש אותו באופן משתמע ולאפשר גישה אליו באופן משתמע או בטעות.

פיתוח ספריות משותפות עם יישור ELF בגודל 16KB

כדי ליצור ספריות משותפות שנכללות בפרויקט Android, ההגדרות הקודמות בקטע הפעלת גודל דף של 16KB מספיקות:

  • PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := true
  • PRODUCT_MAX_PAGE_SIZE_SUPPORTED := 16384

כדי ליצור ספריות משותפות שלא נכללות בפרויקט Android, צריך להעביר את הדגל הזה למקשר:

-Wl,-z,max-page-size=16384

אימות קובצי בינאריים ו-prebuilts עם יישור ELF בגודל 16KB

הדרך הטובה ביותר לאמת את ההתאמה ואת ההתנהגות בזמן הריצה היא לבדוק ולהריץ את הליבה בגודל 16KB. עם זאת, כדי לזהות בעיות מסוימות בשלב מוקדם יותר:

  • החל מגרסה 16 של Android, אפשר להגדיר את PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE := true בזמן ה-build. כדי להתעלם מהן באופן זמני, אפשר להשתמש ב-ignore_max_page_size: true ב-Android.bp וב-LOCAL_IGNORE_MAX_PAGE_SIZE := true ב-Android.mk. ההגדרות האלה מאמתות את כל הגרסאות המוכנות מראש ומאפשרות לזהות מתי גרסה אחת מתעדכנת אבל לא מותאמת ל-16KB.

  • אפשר להריץ את atest elf_alignment_test כדי לאמת את ההתאמה של קובצי ELF במכשיר במכשירים שהושקעו עם Android מגרסה 15 ואילך.