מסמך זה מספק הנחיות לשותפים לשיפור זמני האתחול עבור מכשירי Android ספציפיים. זמן האתחול הוא מרכיב חשוב בביצועי המערכת מכיוון שמשתמשים צריכים לחכות לסיום האתחול לפני שהם יכולים להשתמש במכשיר. עבור מכשירים כגון מכוניות שבהן אתחול קר מתרחש בתדירות גבוהה יותר, זמן אתחול מהיר הוא קריטי (אף אחד לא אוהב לחכות עשרות שניות רק כדי להזין יעד ניווט).
אנדרואיד 8.0 מאפשר זמני אתחול מופחתים על ידי תמיכה במספר שיפורים במגוון רכיבים. הטבלה הבאה מסכמת את שיפורי הביצועים הללו (כפי שנמדד במכשירי Google Pixel ו-Pixel XL).
רְכִיב | הַשׁבָּחָה |
---|---|
טוען אתחול |
|
ליבת המכשיר |
|
כוונון I/O |
|
init.*.rc |
|
אתחול אנימציה |
|
מדיניות SELinux | נשמר 0.2 שניות על ידי genfscon |
אופטימיזציה של טוען האתחול
כדי לייעל את טוען האתחול לזמני אתחול משופרים:
- לרישום:
- השבת כתיבת יומן ל-UART מכיוון שזה יכול לקחת הרבה זמן עם רישום רב. (במכשירי גוגל פיקסל, מצאנו שזה מאט את טוען האתחול 1.5s).
- רשום רק מצבי שגיאה ושקול אחסון מידע אחר בזיכרון עם מנגנון נפרד לאחזור.
- עבור פירוק ליבה, שוקל להשתמש ב-LZ4 עבור חומרה עכשווית במקום ב-GZIP ( תיקון לדוגמה). זכור שלאפשרויות דחיסה שונות של ליבה יכולות להיות זמני טעינה ופירוק דחיסה שונים, ואפשרויות מסוימות עשויות לעבוד טוב יותר מאחרות עבור החומרה הספציפית שלך.
- בדוק זמני המתנה מיותרים ליציאה/כניסה למצב מיוחד ומזער אותם.
- העבירו את זמן האתחול שבילה ב-bootloader לקרנל כ-cmdline.
- בדוק את שעון המעבד ושקול מקבילה (דורש תמיכה מרובת ליבות) לטעינת ליבה ולאתחול I/O.
אופטימיזציה של יעילות I/O
שיפור יעילות ה-I/O הוא קריטי להפיכת זמן האתחול מהיר יותר, ויש לדחות את הקריאה של כל דבר שאינו נחוץ עד לאחר האתחול (ב-Google Pixel, כ-1.2GB של נתונים נקראים בעת האתחול).
כוונון מערכת הקבצים
קריאת ליבת לינוקס מתחילה כאשר קובץ נקרא מתחילתו או כאשר בלוקים נקראים ברצף, מה שהופך את הצורך לכוונן פרמטרים של מתזמן I/O במיוחד לאתחול (שיש לו אפיון עומס עבודה שונה מאשר יישומים רגילים).
מכשירים התומכים בעדכונים חלקים (A/B) נהנים מאוד מכוונון מערכת הקבצים באתחול בפעם הראשונה (למשל 20s ב-Google Pixel). כדוגמה, כיוונו את הפרמטרים הבאים עבור Google Pixel:
on late-fs # boot time fs tune # boot time fs tune write /sys/block/sda/queue/iostats 0 write /sys/block/sda/queue/scheduler cfq write /sys/block/sda/queue/iosched/slice_idle 0 write /sys/block/sda/queue/read_ahead_kb 2048 write /sys/block/sda/queue/nr_requests 256 write /sys/block/dm-0/queue/read_ahead_kb 2048 write /sys/block/dm-1/queue/read_ahead_kb 2048 on property:sys.boot_completed=1 # end boot time fs tune write /sys/block/sda/queue/read_ahead_kb 512 ...
שונות
- הפעל את גודל האחזור המוקדם של dm-verity באמצעות תצורת הליבה DM_VERITY_HASH_PREFETCH_MIN_SIZE (גודל ברירת המחדל הוא 128).
- ליציבות טובה יותר של מערכת הקבצים ובדיקה מאולצת שנפסלה המתרחשת בכל אתחול, השתמש בכלי הדור החדש של ext4 על ידי הגדרת TARGET_USES_MKE2FS ב- BoardConfig.mk.
ניתוח I/O
כדי להבין את פעילויות ה-I/O במהלך האתחול, השתמש בנתוני Ftrace של ליבה (בשימוש גם על ידי Systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
כדי לפרק את הגישה לקובץ עבור כל קובץ, בצע את השינויים הבאים בקרנל (ליבת הפיתוח בלבד; אין להשתמש בגרעיני הייצור):
diff --git a/fs/open.c b/fs/open.c index 1651f35..a808093 100644 --- a/fs/open.c +++ b/fs/open.c @@ -981,6 +981,25 @@ } EXPORT_SYMBOL(file_open_root); +static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd) +{ + char *buf; + char *fname; + + buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return; + fname = d_path(&filp-<f_path, buf, PAGE_SIZE); + + if (IS_ERR(fname)) + goto out; + + trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n", + current-<comm, fname, flags, mode, fd, filp-<f_inode-<i_ino); +out: + kfree(buf); +} + long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; @@ -1003,6 +1022,7 @@ } else { fsnotify_open(f); fd_install(fd, f); + _trace_do_sys_open(f, flags, mode, fd);
השתמש בסקריפטים הבאים כדי לעזור בניתוח ביצועי האתחול.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
מודד את זמן האתחול עם פירוט שלבים חשובים בתהליך האתחול. -
system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
מספק מידע גישה לכל קובץ. -
system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
נותן פירוט ברמת המערכת.
אופטימיזציה של init.*.rc
Init הוא הגשר מהקרנל ועד להקמת המסגרת, והתקנים בדרך כלל מבלים כמה שניות בשלבי אינט שונים.
הפעלת משימות במקביל
בעוד שה-Init הנוכחי של אנדרואיד הוא פחות או יותר תהליך משורשר בודד, אתה עדיין יכול לבצע כמה משימות במקביל.
- בצע פקודות איטיות בשירות סקריפטים של מעטפת והצטרף אליו מאוחר יותר על ידי המתנה למאפיין ספציפי. אנדרואיד 8.0 תומך במקרה שימוש זה עם פקודת
wait_for_property
חדשה. - זהה פעולות איטיות ב-init. המערכת רושמת את הפקודה init exec/wait_for_prop או כל פעולה שלוקחת זמן רב (באנדרואיד 8.0, כל פקודה לוקחת יותר מ-50 אלפיות השנייה). לדוגמה:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
עיון ביומן זה עשוי להצביע על הזדמנויות לשיפורים.
- התחל שירותים ואפשר התקנים היקפיים בנתיב קריטי מוקדם. לדוגמה, חלק מה-SOCs דורשים הפעלת שירותים הקשורים לאבטחה לפני הפעלת SurfaceFlinger. עיין ביומן המערכת כאשר ServiceManager מחזיר "המתנה לשירות" - זה בדרך כלל סימן לכך שיש להפעיל תחילה שירות תלוי.
- הסר שירותים ופקודות שאינם בשימוש ב-init.*.rc. כל דבר שלא נעשה בו שימוש בשלב מוקדם יש לדחות לסיום האתחול.
הערה: שירות נכסים הוא חלק מתהליך init, כך שקריאה ל- setproperty
במהלך האתחול עלולה להוביל לעיכוב ארוך אם init תפוס בפקודות מובנות.
שימוש בכוונון מתזמן
השתמש בכוונון מתזמן לאתחול מוקדם. דוגמה מ-Google Pixel:
on init # boottime stune write /dev/stune/schedtune.prefer_idle 1 write /dev/stune/schedtune.boost 100 on property:sys.boot_completed=1 # reset stune write /dev/stune/schedtune.prefer_idle 0 write /dev/stune/schedtune.boost 0 # or just disable EAS during boot on init write /sys/kernel/debug/sched_features NO_ENERGY_AWARE on property:sys.boot_completed=1 write /sys/kernel/debug/sched_features ENERGY_AWARE
שירותים מסוימים עשויים להזדקק לחיזוק עדיפות במהלך האתחול. דוגמא:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
התחלת זיגוטה מוקדם
מכשירים עם הצפנה מבוססת קבצים יכולים להתחיל את ה-zygote מוקדם יותר בטריגר ה-zygote-start (כברירת מחדל, zygote מופעל ב-class main, שהוא הרבה יותר מאוחר מה-zygote-start). כאשר אתה עושה זאת, הקפד לאפשר לזיגוטה לפעול בכל המעבדים (כיוון שהגדרת cpuset שגויה עלולה לאלץ את הזיגוטה לפעול במעבדים ספציפיים).
בטל חיסכון בחשמל
במהלך אתחול המכשיר, ניתן להשבית את הגדרת החיסכון בחשמל עבור רכיבים כמו UFS ו/או מושל מעבד.
זהירות: חיסכון בחשמל צריך להיות מופעל במצב מטען לצורך יעילות.
on init # Disable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0 write /sys/module/lpm_levels/parameters/sleep_disabled Y on property:sys.boot_completed=1 # Enable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1 write /sys/module/lpm_levels/parameters/sleep_disabled N on charger # Enable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1 write /sys/class/typec/port0/port_type sink write /sys/module/lpm_levels/parameters/sleep_disabled N
דחה אתחול לא קריטי
ניתן לדחות אתחול לא קריטי כגון ZRAM ל-boot_complete.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
אופטימיזציה של אנימציית אתחול
השתמש בעצות הבאות כדי לייעל את הנפשת האתחול.
הגדרת התחלה מוקדמת
אנדרואיד 8.0 מאפשר התחלת אנימציית אתחול מוקדם, לפני הטעינה של מחיצת נתוני משתמש. עם זאת, גם בעת שימוש בשרשרת הכלים החדשה ext4 באנדרואיד 8.0, fsck עדיין מופעל מעת לעת מסיבות בטיחות, מה שגורם לעיכוב בהפעלת שירות האתחול.
כדי לגרום לאתחול להתחיל מוקדם, פצל את ה-fstab mount לשני שלבים:
- בשלב המוקדם, העלה רק את המחיצות (כגון
system/
vendor/
) שאינן דורשות בדיקות הפעלה, ואז התחל את שירותי הנפשת האתחול והתלות שלהם (כגון servicemanager ו-surfaceflinger). - בשלב השני, טען מחיצות (כגון
data/
) שאכן דורשות בדיקות הפעלה.
אנימציית האתחול תופעל הרבה יותר מהר (ובזמן קבוע) ללא קשר ל-fsck.
מסיים נקי
לאחר קבלת אות היציאה, Bootanimation משחק את החלק האחרון, שאורכו יכול להאט את זמן האתחול. למערכת שמאוחלת במהירות אין צורך בהנפשות ארוכות שיכולות להסתיר ביעילות כל שיפורים שבוצעו. אנו ממליצים לעשות גם את הלולאה החוזרת וגם את הסיום קצרים.
אופטימיזציה של SELinux
השתמש בעצות הבאות כדי לייעל את SELinux לזמני אתחול משופרים.
- השתמש בביטויים רגולריים נקיים (רגקס) . ביטוי רגולרי בעל מבנה גרוע יכול להוביל לתקורה רבה בעת התאמת מדיניות SELinux עבור
sys/devices
ב-file_contexts
. לדוגמה, הביטוי הרגולרי/sys/devices/.*abc.*(/.*)?
מאלץ בטעות סריקה של כל ספריות המשנה/sys/devices
המכילות "abc", מה שמאפשר התאמות הן עבור/sys/devices/abc
והן/sys/devices/xyz/abc
. משפר את הביטוי הרגולרי הזה ל-/sys/devices/[^/]*abc[^/]*(/.*)?
יאפשר התאמה רק עבור/sys/devices/abc
. - העבר תוויות ל- genfscon . תכונת SELinux קיימת מעבירה קידומות תואמות קבצים לתוך הליבה בבינארי SELinux, כאשר הליבה מחילה אותן על מערכות קבצים שנוצרו על ידי ליבה. זה גם עוזר לתקן קבצים שנוצרו בליבה עם תיוג שגוי, ולמנוע תנאי מירוץ שיכולים להתרחש בין תהליכים של מרחב משתמש המנסים לגשת לקבצים האלה לפני שהתיוג מחדש מתרחש.
כלי ושיטות
השתמש בכלים הבאים כדי לעזור לך לאסוף נתונים עבור יעדי אופטימיזציה.
Bootchart
Bootchart מספק פירוט עומסי CPU ו-I/O של כל התהליכים עבור המערכת כולה. זה לא מצריך בנייה מחדש של תמונת המערכת ויכול לשמש כבדיקת שפיות מהירה לפני הצלילה ל-systrace.
כדי להפעיל את תרשים האתחול:
adb shell 'touch /data/bootchart/enabled'
adb reboot
לאחר האתחול, אחזר את טבלת האתחול:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
בסיום, מחק /data/bootchart/enabled
כדי למנוע איסוף הנתונים בכל פעם.
bootchart.png
לא קיים, בצע את הפעולות הבאות:- הפעל את הפקודות הבאות:
sudo apt install python-is-python3
cd ~/Documents
git clone https://github.com/xrmx/bootchart.git
cd bootchart/pybootchartgui
mv main.py.in main.py
- עדכן את
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
כדי להצביע על העותק המקומי שלpybootchartgui
(נמצא בכתובת~/Documents/bootchart/pybootchartgui.py
)
סיסטרס
Systrace מאפשרת איסוף עקבות ליבה וגם אנדרואיד במהלך האתחול. ויזואליזציה של systrace יכולה לעזור בניתוח בעיה ספציפית במהלך האתחול. (עם זאת, כדי לבדוק את המספר הממוצע או המספר המצטבר במהלך כל האתחול, קל יותר לבדוק ישירות את מעקב ליבה).
כדי להפעיל את systrace במהלך האתחול:
-
frameworks/native/cmds/atrace/atrace.rc
, שנה:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
ל:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
- בקובץ
device.mk
, הוסף את השורה הבאה:PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- בקובץ
BoardConfig.mk
של המכשיר, הוסף את הדברים הבאים:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- בקובץ
init.rc
הספציפי למכשיר, הוסף את הדברים הבאים:on property:sys.boot_completed=1 // This stops tracing on boot complete write /d/tracing/tracing_on 0 write /d/tracing/events/ext4/enable 0 write /d/tracing/events/f2fs/enable 0 write /d/tracing/events/block/enable 0
לאחר האתחול, אחזר מעקב:
adb root && adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
adb pull /data/local/tmp/boot_trace
$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace
זה מאפשר מעקב (שמושבת כברירת מחדל).
לניתוח קלט/פלט מפורט, הוסף גם בלוק ו-ext4 ו-f2fs.