เอกสารนี้ให้คำแนะนำของพาร์ทเนอร์ในการปรับปรุงเวลาเปิดเครื่องสำหรับ อุปกรณ์ Android เวลาบูตเป็นองค์ประกอบสำคัญของประสิทธิภาพของระบบเนื่องจาก ผู้ใช้ต้องรอให้การบูตเสร็จสิ้นก่อนจึงจะใช้อุปกรณ์ได้ สำหรับอุปกรณ์ เช่น รถยนต์ที่ Cold Boot เปิดเครื่องบ่อยกว่า การเปิดเครื่องที่รวดเร็ว เวลาเป็นสิ่งสำคัญ (ไม่มีใครชอบรอเป็นสิบๆ วินาทีเพื่อใส่ ปลายทางการนำทาง)
Android 8.0 ช่วยลดเวลาเปิดเครื่องได้ด้วยการรองรับการปรับปรุงหลายประการ สำหรับคอมโพเนนต์ที่หลากหลาย ตารางต่อไปนี้จะสรุปประสิทธิภาพดังกล่าว (ตามที่วัดในอุปกรณ์ Google Pixel และ Pixel XL)
ส่วนประกอบ | การปรับปรุง |
---|---|
Bootloader |
|
เคอร์เนลของอุปกรณ์ |
|
การปรับแต่ง I/O |
|
init.*.rc |
|
ภาพเคลื่อนไหวขณะเปิดเครื่อง |
|
นโยบาย SELinux | บันทึก 0.2 วินาทีโดย genfscon |
เพิ่มประสิทธิภาพ Bootloader
วิธีเพิ่มประสิทธิภาพ Bootloader เพื่อปรับปรุงเวลาเปิดเครื่อง:
- สำหรับการบันทึก:
- ปิดใช้งานการเขียนบันทึกไปยัง UART เนื่องจากอาจใช้เวลานานโดยมี การเข้าสู่ระบบ (ในอุปกรณ์ Google Pixel เราพบว่าโหมดนี้ทำให้ Bootloader ทำงานช้าลง 1.5s)
- บันทึกเฉพาะสถานการณ์ข้อผิดพลาดและพิจารณาเก็บข้อมูลอื่นๆ ไว้ในหน่วยความจำ โดยมีกลไกแยกต่างหากในการดึงข้อมูล
- สำหรับการยกเลิกการบีบอัดเคอร์เนล ให้พิจารณาใช้ LZ4 สำหรับฮาร์ดแวร์ร่วมสมัย แทน GZIP (ตัวอย่าง patch) โปรดทราบว่า ตัวเลือกการบีบอัดเคอร์เนลที่แตกต่างกัน อาจมีการโหลดและ เวลาในการบีบอัด และบางตัวเลือกอาจทำงานได้ดีกว่าตัวเลือกอื่นๆ สำหรับ ฮาร์ดแวร์ที่เฉพาะเจาะจง
- ตรวจสอบเวลารอที่ไม่จำเป็นสำหรับการดีตีกลับ/เข้าโหมดพิเศษและลดเวลาให้น้อยที่สุด ให้พวกเขา
- ส่งผ่านเวลาเปิดเครื่องใน Bootloader ไปยังเคอร์เนลเป็น cmdline
- ตรวจสอบนาฬิกา CPU และพิจารณาการทำงานพร้อมกัน (ต้องมีการรองรับหลายแกน) สำหรับการโหลดเคอร์เนลและการเริ่มต้น I/O
เพิ่มประสิทธิภาพ I/O
การปรับปรุงประสิทธิภาพ I/O เป็นสิ่งสำคัญที่ช่วยให้เปิดเครื่องได้เร็วขึ้น และการอ่าน ทุกสิ่งที่ไม่จำเป็นควรมีการเลื่อนเวลาออกไป หลังการเปิดเครื่อง (ใน Google Pixel ข้อมูลประมาณ 1.2 GB จะอ่านเมื่อเปิดเครื่อง)
ปรับระบบไฟล์
การอ่านเคอร์เนลของ Linux ล่วงหน้าจะทำงานเมื่อมีการอ่านไฟล์ตั้งแต่ต้นหรือเมื่อ บล็อกต่างๆ ถูกอ่านตามลำดับ ทำให้จำเป็นต้องปรับเครื่องจัดตารางเวลา I/O พารามิเตอร์สำหรับการเปิดเครื่องโดยเฉพาะ (ซึ่งมีภาระงานที่แตกต่างกัน ที่ไม่เหมือนกันในแอปปกติ)
อุปกรณ์ที่รองรับการอัปเดตที่ราบรื่น (A/B) จะได้ประโยชน์จากระบบไฟล์อย่างมาก ปรับแต่งเมื่อเปิดเครื่องครั้งแรก (เช่น 20 วินาทีใน 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 ระหว่างการเปิดเครื่อง ให้ใช้ข้อมูลการติดตามเคอร์เนล (รวมถึงใช้โดย 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 เป็นบริดจ์จากเคอร์เนลจนกระทั่งมีการสร้างเฟรมเวิร์ก และ อุปกรณ์มักจะใช้เวลา 2-3 วินาทีในระยะเริ่มต้นต่างๆ
เรียกใช้งานพร้อมกัน
แม้ว่า Android init ปัจจุบันจะเป็นกระบวนการแบบแยกชุดข้อความเดี่ยวมากกว่าหรือน้อยกว่า ยังคงทำงานบางอย่างได้ควบคู่กัน
- เรียกใช้คำสั่งช้าในบริการสคริปต์ Shell แล้วรวมคำสั่งดังกล่าวในภายหลังโดย
กำลังรอพร็อพเพอร์ตี้ที่ระบุ Android 8.0 สนับสนุนกรณีการใช้งานนี้พร้อมด้วย
คำสั่ง
wait_for_property
- ระบุการดำเนินการที่ช้าใน init ระบบจะบันทึกคำสั่ง init
exec/wait_for_prop หรือการดําเนินการใดๆ ที่ใช้เวลานาน (ใน Android 8.0 ใช้คําสั่งใดก็ได้
ที่ใช้เวลามากกว่า 50 มิลลิวินาที) ดังตัวอย่างต่อไปนี้
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
การตรวจสอบบันทึกนี้อาจบ่งบอกถึงโอกาสในการปรับปรุง
- เริ่มบริการและเปิดใช้อุปกรณ์ต่อพ่วงในเส้นทางวิกฤติตั้งแต่เนิ่นๆ สำหรับ เช่น SOC บางรายการกำหนดให้เริ่มใช้บริการที่เกี่ยวข้องกับการรักษาความปลอดภัยก่อนเริ่มต้น 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 ทำงานบน CPU ทุกตัว (เป็น การตั้งค่า CPU ที่ไม่ถูกต้องอาจทำให้ zygote ทำงานใน CPU ที่เฉพาะเจาะจง)
ปิดใช้การประหยัดพลังงาน
ในระหว่างการเปิดเครื่องอุปกรณ์ การตั้งค่าการประหยัดพลังงานสำหรับคอมโพเนนต์ต่างๆ เช่น UFS และ/หรือ CPU สามารถปิดใช้งานผู้ว่าการรัฐได้
ข้อควรระวัง: ควรเปิดใช้การประหยัดพลังงานใน เพื่อประหยัดพลังงาน
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}
เพิ่มประสิทธิภาพภาพเคลื่อนไหวสำหรับการเปิดเครื่อง
ใช้เคล็ดลับต่อไปนี้เพื่อเพิ่มประสิทธิภาพภาพเคลื่อนไหวสำหรับการเปิดเครื่อง
กำหนดค่าการเริ่มต้นใช้งานตั้งแต่เริ่มต้น
Android 8.0 จะเปิดใช้ภาพเคลื่อนไหวสำหรับการเปิดเครื่องตั้งแต่เนิ่นๆ ก่อนต่อเชื่อมข้อมูลผู้ใช้ พาร์ติชัน อย่างไรก็ตาม แม้ว่าจะใช้เครื่องมือ ext4 แบบใหม่ใน Android 8.0 แล้วก็ตาม fsck ยังคงเรียกใช้เป็นระยะๆ เนื่องจากเหตุผลด้านความปลอดภัย ทำให้เกิดความล่าช้าใน กำลังเริ่มบริการ Bootanimation
หากต้องการให้ Bootanimation เริ่มต้นตั้งแต่เนิ่นๆ ให้แยกการต่อเชื่อม fstab เป็น 2 ระยะดังนี้
- ในระยะแรก ให้ต่อเชื่อมเฉพาะพาร์ติชัน (เช่น
system/
และvendor/
) ที่ไม่จำเป็นต้องเรียกใช้ ตรวจสอบ จากนั้นเริ่มบริการภาพเคลื่อนไหวสำหรับการเปิดเครื่องและ Dependency (เช่น Service Manager และ Surfaceflinger) - ในขั้นตอนที่ 2 ให้ต่อเชื่อมพาร์ติชัน (เช่น
data/
) ที่ ต้องมีการตรวจสอบ
ภาพเคลื่อนไหวสำหรับการบูตจะเริ่มต้นเร็วขึ้นมาก (และเกิดขึ้นต่อเนื่อง) ไม่ว่า fsck
ทำความสะอาดพื้นผิว
หลังจากได้รับสัญญาณให้ออก Bootanimation จะเล่นส่วนสุดท้ายคือความยาว ซึ่งอาจทำให้เปิดเครื่องได้ช้าลง ระบบที่เปิดเครื่องได้เร็วโดยไม่จำเป็นต้องใช้เวลานาน ภาพเคลื่อนไหวที่สามารถซ่อนการปรับปรุงใดๆ ที่ทำไว้ได้อย่างมีประสิทธิภาพ คำแนะนำจากเรา ทำให้ทั้งการเล่นซ้ำ และตอนจบสั้น
เพิ่มประสิทธิภาพ SELinux
ใช้เคล็ดลับต่อไปนี้ในการเพิ่มประสิทธิภาพ SELinux ให้เปิดเครื่องได้เร็วยิ่งขึ้น
- ใช้นิพจน์ทั่วไปที่สะอาด (regex) นิพจน์ทั่วไปที่มีรูปแบบไม่ถูกต้อง
อาจทำให้เกิดค่าใช้จ่ายอย่างมากเมื่อจับคู่นโยบาย 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 ซึ่งเคอร์เนลนำเคอร์เนลไปใช้กับเคอร์เนล ของระบบไฟล์ได้อีกด้วย นอกจากนี้ ยังช่วยคุณแก้ไขไฟล์ที่สร้างเคอร์เนลซึ่งติดป้ายกำกับไม่ถูกต้อง และป้องกัน เงื่อนไขการแข่งขันที่อาจเกิดขึ้นระหว่างขั้นตอน Userspace ที่พยายามเข้าถึง ไฟล์เหล่านี้ก่อนที่จะทำการติดป้ายกำกับใหม่
เครื่องมือและวิธีการ
ใช้เครื่องมือต่อไปนี้เพื่อช่วยคุณรวบรวมข้อมูลสำหรับเป้าหมายการเพิ่มประสิทธิภาพ
แผนภูมิบูต
Bootchart แสดงรายละเอียดภาระงาน CPU และ I/O ของกระบวนการทั้งหมดโดยรวม ระบบ ไม่จำเป็นต้องสร้างอิมเมจระบบใหม่และสามารถใช้เป็น การตรวจสอบความเรียบร้อยก่อนเข้าสู่ Systrace
วิธีเปิดใช้ Bootchart
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 อนุญาตให้รวบรวมทั้งเคอร์เนลและการติดตาม Android ระหว่างการเปิดเครื่อง การแสดงภาพ 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
การดำเนินการนี้จะเปิดใช้การติดตาม (ซึ่งจะปิดใช้โดยค่าเริ่มต้น)
หากต้องการการวิเคราะห์ I/O โดยละเอียด ให้เพิ่มบล็อกและ ext4 และ f2fs