Dokumen ini memberikan panduan mitra untuk meningkatkan waktu booting untuk perangkat Android tertentu. Waktu booting merupakan komponen penting dari kinerja sistem karena pengguna harus menunggu booting selesai sebelum mereka dapat menggunakan perangkat. Untuk perangkat seperti mobil di mana cold boot-up lebih sering terjadi, memiliki waktu boot yang cepat sangat penting (tidak ada yang suka menunggu puluhan detik hanya untuk memasukkan tujuan navigasi).
Android 8.0 memungkinkan pengurangan waktu boot dengan mendukung beberapa peningkatan di berbagai komponen. Tabel berikut merangkum peningkatan kinerja ini (seperti yang diukur pada perangkat Google Pixel dan Pixel XL).
Komponen | Peningkatan |
---|---|
Pemuat boot |
|
Kernel perangkat |
|
Penyetelan I/O |
|
init.*.rc |
|
Animasi boot |
|
kebijakan SELinux | Disimpan 0,2 detik oleh genfscon |
Mengoptimalkan Bootloader
Untuk mengoptimalkan bootloader untuk meningkatkan waktu boot:
- Untuk masuk:
- Nonaktifkan penulisan log ke UART karena dapat memakan waktu lama dengan banyak pencatatan. (Di perangkat Google Pixel, kami menemukannya memperlambat bootloader 1.5s).
- Catat hanya situasi kesalahan dan pertimbangkan untuk menyimpan informasi lain ke memori dengan mekanisme terpisah untuk diambil.
- Untuk dekompresi kernel, pertimbangkan untuk menggunakan LZ4 untuk perangkat keras kontemporer alih-alih GZIP (contoh patch ). Ingatlah bahwa opsi kompresi kernel yang berbeda dapat memiliki waktu pemuatan dan dekompresi yang berbeda, dan beberapa opsi mungkin bekerja lebih baik daripada yang lain untuk perangkat keras spesifik Anda.
- Periksa waktu tunggu yang tidak perlu untuk entri mode debouncing/khusus dan minimalkan.
- Lewati waktu boot yang dihabiskan di bootloader ke kernel sebagai cmdline.
- Periksa jam CPU dan pertimbangkan paralelisasi (memerlukan dukungan multi-core) untuk memuat kernel dan menginisialisasi I/O.
Mengoptimalkan Kernel
Gunakan tip berikut untuk mengoptimalkan kernel untuk waktu boot yang lebih baik.
Meminimalkan defconfig perangkat
Meminimalkan konfigurasi kernel dapat mengurangi ukuran kernel untuk dekompresi pemuatan yang lebih cepat, inisialisasi, dan permukaan serangan yang lebih kecil. Untuk mengoptimalkan defconfig perangkat:
- Identifikasi driver yang tidak digunakan . Tinjau direktori
/dev
dan/sys
dan cari node dengan label SELinux umum (yang menunjukkan bahwa node tersebut tidak dikonfigurasi untuk dapat diakses oleh ruang pengguna). Hapus node tersebut jika ditemukan. - Hapus CONFIG yang tidak digunakan . Tinjau file .config yang dihasilkan oleh kernel build untuk secara eksplisit menghapus CONFIG yang tidak digunakan yang diaktifkan secara default. Misalnya, kami menghapus CONFIG yang tidak digunakan berikut dari Google Pixel:
CONFIG_ANDROID_LOGGER=y CONFIG_IMX134=y CONFIG_IMX132=y CONFIG_OV9724=y CONFIG_OV5648=y CONFIG_GC0339=y CONFIG_OV8825=y CONFIG_OV8865=y CONFIG_s5k4e1=y CONFIG_OV12830=y CONFIG_USB_EHCI_HCD=y CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST=y CONFIG_IKCONFIG=y CONFIG_RD_BZIP2=y CONFIG_RD_LZMA=y CONFIG_TI_DRV2667=y CONFIG_CHR_DEV_SCH=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y CONFIG_MMC_SDHCI_MSM_ICE=y CONFIG_MMC_CQ_HCI=y CONFIG_MSDOS_FS=y # CONFIG_SYSFS_SYSCALL is not set CONFIG_EEPROM_AT24=y # CONFIG_INPUT_MOUSEDEV_PSAUX is not set CONFIG_INPUT_HBTP_INPUT=y # CONFIG_VGA_ARB is not set CONFIG_USB_MON=y CONFIG_USB_STORAGE_DATAFAB=y CONFIG_USB_STORAGE_FREECOM=y CONFIG_USB_STORAGE_ISD200=y CONFIG_USB_STORAGE_USBAT=y CONFIG_USB_STORAGE_SDDR09=y CONFIG_USB_STORAGE_SDDR55=y CONFIG_USB_STORAGE_JUMPSHOT=y CONFIG_USB_STORAGE_ALAUDA=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y CONFIG_SW_SYNC_USER=y CONFIG_SEEMP_CORE=y CONFIG_MSM_SMEM_LOGGING=y CONFIG_IOMMU_DEBUG=y CONFIG_IOMMU_DEBUG_TRACKING=y CONFIG_IOMMU_TESTS=y CONFIG_MOBICORE_DRIVER=y # CONFIG_DEBUG_PREEMPT is not set
- Hapus CONFIG yang menyebabkan pengujian yang tidak perlu dijalankan pada setiap boot . Meskipun berguna dalam pengembangan, konfigurasi tersebut (yaitu CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST) harus dihapus di kernel produksi.
Meminimalkan ukuran driver
Beberapa driver di kernel perangkat dapat dihapus jika fungsi tersebut tidak digunakan untuk mengurangi ukuran kernel lebih lanjut. Misalnya, jika WLAN terhubung melalui PCIe, dukungan SDIO tidak digunakan dan harus dihapus selama waktu kompilasi. Untuk detailnya, lihat kernel Google Pixel: net: wireless: cnss: add option untuk menonaktifkan dukungan SDIO.
Menghapus pengoptimalan kompiler untuk ukuran
Hapus konfigurasi kernel untuk CONFIG_CC_OPTIMIZE_FOR_SIZE. Bendera ini awalnya diperkenalkan ketika asumsinya adalah bahwa ukuran kode yang lebih kecil akan menghasilkan hit cache panas (dan dengan demikian lebih cepat). Namun, asumsi ini tidak lagi berlaku karena SoC seluler modern menjadi lebih kuat.
Selain itu, menghapus tanda dapat mengaktifkan peringatan kompiler untuk variabel yang tidak diinisialisasi, yang ditekan di kernel Linux ketika tanda CONFIG_CC_OPTIMIZE_FOR_SIZE hadir (membuat perubahan ini saja telah membantu kami menemukan banyak bug yang berarti di beberapa driver perangkat Android).
Menunda inisialisasi
Banyak proses yang diluncurkan saat boot, tetapi hanya komponen di jalur kritis (bootloader > kernel > init > file system mount > zygote > server sistem) yang secara langsung mempengaruhi waktu boot. Profil initcall selama boot kernel untuk mengidentifikasi periferal/komponen yang lambat dan tidak kritis untuk memulai proses init, kemudian tunda periferal/komponen tersebut hingga nanti dalam proses boot dengan pindah ke modul kernel yang dapat dimuat. Pindah ke probe perangkat/driver asinkron juga dapat membantu memparalelkan komponen lambat di kernel > init jalur kritis.
BoardConfig-common.mk: BOARD_KERNEL_CMDLINE += initcall_debug ignore_loglevel driver: .probe_type = PROBE_PREFER_ASYNCHRONOUS,
Catatan: Ketergantungan driver harus diselesaikan dengan hati-hati dengan menambahkan dukungan EPROBEDEFER
.
Mengoptimalkan efisiensi I/O
Meningkatkan efisiensi I/O sangat penting untuk membuat waktu booting lebih cepat, dan membaca apa pun yang tidak perlu harus ditunda hingga setelah booting (pada Google Pixel, sekitar 1,2GB data dibaca saat boot).
Menyetel sistem file
Kernel Linux membaca lebih dulu ketika file dibaca dari awal atau ketika blok dibaca secara berurutan, sehingga perlu untuk menyetel parameter penjadwal I/O khusus untuk booting (yang memiliki karakterisasi beban kerja yang berbeda dari aplikasi normal).
Perangkat yang mendukung pembaruan tanpa batas (A/B) sangat diuntungkan dari penyetelan sistem file saat boot pertama kali (misalnya 20 detik di Google Pixel). Sebagai contoh, kami menyetel parameter berikut untuk 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 ...
Aneka ragam
- Aktifkan ukuran prefetch hash dm-verity menggunakan konfigurasi kernel DM_VERITY_HASH_PREFETCH_MIN_SIZE (ukuran default adalah 128).
- Untuk stabilitas sistem file yang lebih baik dan pemeriksaan paksa yang dilakukan pada setiap boot, gunakan alat generasi ext4 baru dengan menyetel TARGET_USES_MKE2FS di BoardConfig.mk.
Menganalisis I/O
Untuk memahami aktivitas I/O selama boot, gunakan data kernel ftrace (juga digunakan oleh systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Untuk memecah akses file untuk setiap file, buat perubahan berikut pada kernel (hanya kernel pengembangan; jangan gunakan di kernel produksi):
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);
Gunakan skrip berikut untuk membantu menganalisis kinerja boot.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Mengukur waktu boot dengan rincian langkah-langkah penting dalam proses boot. -
system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Menyediakan informasi akses per setiap file. -
system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Memberikan rincian tingkat sistem.
Mengoptimalkan init.*.rc
Init adalah jembatan dari kernel hingga kerangka kerja dibuat, dan perangkat biasanya menghabiskan beberapa detik dalam tahap init yang berbeda.
Menjalankan tugas secara paralel
Meskipun init Android saat ini kurang lebih merupakan proses berulir tunggal, Anda masih dapat melakukan beberapa tugas secara paralel.
- Jalankan perintah lambat di layanan skrip shell dan gabungkan nanti dengan menunggu properti tertentu. Android 8.0 mendukung kasus penggunaan ini dengan perintah
wait_for_property
baru. - Identifikasi operasi lambat di init. Sistem mencatat perintah init exec/wait_for_prop atau tindakan apa pun yang membutuhkan waktu lama (di Android 8.0, perintah apa pun yang membutuhkan waktu lebih dari 50 mdtk). Misalnya:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
Meninjau log ini dapat menunjukkan peluang untuk perbaikan.
- Mulai layanan dan aktifkan perangkat periferal di jalur kritis lebih awal. Misalnya, beberapa SOC memerlukan memulai layanan terkait keamanan sebelum memulai SurfaceFlinger. Tinjau log sistem ketika ServiceManager mengembalikan "tunggu layanan" — ini biasanya merupakan tanda bahwa layanan dependen harus dimulai terlebih dahulu.
- Hapus semua layanan dan perintah yang tidak digunakan di init.*.rc. Apa pun yang tidak digunakan pada tahap awal init harus ditunda hingga boot selesai.
Catatan: Layanan properti adalah bagian dari proses init, jadi memanggil setproperty
saat boot dapat menyebabkan penundaan yang lama jika init sibuk dengan perintah bawaan.
Menggunakan penyetelan penjadwal
Gunakan penyetelan penjadwal untuk boot awal. Contoh dari 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
Beberapa layanan mungkin memerlukan peningkatan prioritas saat boot. Contoh:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Memulai zigot lebih awal
Perangkat dengan enkripsi berbasis file dapat memulai zygote lebih awal pada pemicu zygote-start (secara default, zygote diluncurkan di class main, yang jauh lebih lambat daripada zygote-start). Saat melakukan ini, pastikan untuk mengizinkan zigot berjalan di semua CPU (karena pengaturan cpuset yang salah dapat memaksa zigot berjalan di CPU tertentu).
Nonaktifkan hemat daya
Selama boot perangkat, pengaturan hemat daya untuk komponen seperti UFS dan/atau gubernur CPU dapat dinonaktifkan.
Perhatian: Hemat daya harus diaktifkan dalam mode pengisi daya untuk efisiensi.
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
Tunda inisialisasi non-kritis
Inisialisasi non-kritis seperti ZRAM dapat ditunda ke boot_complete.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Mengoptimalkan animasi boot
Gunakan tips berikut untuk mengoptimalkan animasi boot.
Mengonfigurasi mulai awal
Android 8.0 memungkinkan memulai animasi boot lebih awal, sebelum memasang partisi data pengguna. Namun, bahkan saat menggunakan rantai alat ext4 baru di Android 8.0, fsck masih dipicu secara berkala karena alasan keamanan, menyebabkan penundaan dalam memulai layanan bootanimation.
Untuk membuat bootanimation dimulai lebih awal, bagi fstab mount menjadi dua fase:
- Pada fase awal, mount hanya partisi (seperti
system/
danvendor/
) yang tidak memerlukan run check, kemudian mulai layanan animasi boot dan dependensinya (seperti servicemanager dan surfaceflinger). - Pada fase kedua, mount partisi (seperti
data/
) yang memang membutuhkan run check.
Animasi boot akan dimulai lebih cepat (dan dalam waktu yang konstan) terlepas dari fsck.
Selesai bersih
Setelah menerima sinyal keluar, bootanimation memainkan bagian terakhir, yang panjangnya dapat memperlambat waktu boot. Sistem yang melakukan booting dengan cepat tidak memerlukan animasi panjang yang dapat secara efektif menyembunyikan perbaikan apa pun yang dibuat. Kami merekomendasikan untuk membuat loop berulang dan final menjadi pendek.
Mengoptimalkan SELinux
Gunakan tip berikut untuk mengoptimalkan SELinux untuk waktu boot yang lebih baik.
- Gunakan ekspresi reguler bersih (regex) . Regex yang dibentuk dengan buruk dapat menyebabkan banyak overhead saat mencocokkan kebijakan SELinux untuk
sys/devices
difile_contexts
. Misalnya, ekspresi reguler/sys/devices/.*abc.*(/.*)?
keliru memaksa pemindaian semua/sys/devices
subdirektori yang berisi "abc", memungkinkan kecocokan untuk/sys/devices/abc
dan/sys/devices/xyz/abc
. Meningkatkan regex ini ke/sys/devices/[^/]*abc[^/]*(/.*)?
akan mengaktifkan kecocokan hanya untuk/sys/devices/abc
. - Pindahkan label ke genfscon . Fitur SELinux yang ada ini meneruskan awalan pencocokan file ke dalam kernel dalam biner SELinux, di mana kernel menerapkannya ke sistem file yang dihasilkan kernel. Ini juga membantu memperbaiki file yang dibuat oleh kernel yang salah label, mencegah kondisi balapan yang dapat terjadi antara proses ruang pengguna yang mencoba mengakses file-file ini sebelum pelabelan ulang terjadi.
Alat dan metode
Gunakan alat berikut untuk membantu Anda mengumpulkan data untuk target pengoptimalan.
Bagan Booting
Bootchart menyediakan perincian beban CPU dan I/O dari semua proses untuk keseluruhan sistem. Itu tidak memerlukan membangun kembali citra sistem dan dapat digunakan sebagai pemeriksaan kewarasan cepat sebelum menyelam ke systrace.
Untuk mengaktifkan bagan boot:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Setelah boot, ambil bagan boot:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
Setelah selesai, hapus /data/bootchart/enabled
untuk mencegah pengumpulan data setiap saat.
Systrace
Systrace memungkinkan pengumpulan jejak kernel dan Android selama boot. Visualisasi systrace dapat membantu dalam menganalisis masalah tertentu selama boot-up. (Namun, untuk memeriksa jumlah rata-rata atau jumlah akumulasi selama seluruh boot, lebih mudah untuk melihat jejak kernel secara langsung).
Untuk mengaktifkan systrace saat boot-up:
- Dalam
frameworks/native/cmds/atrace/atrace.rc
, ubah:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
Ke:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
- Di file
device.mk
, tambahkan baris berikut:PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- Dalam file
BoardConfig.mk
perangkat, tambahkan berikut ini:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- Dalam file
init.rc
khusus perangkat, tambahkan berikut ini: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
Setelah boot, ambil jejak:
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
Ini memungkinkan pelacakan (yang dinonaktifkan secara default).
Untuk analisis I/O terperinci, tambahkan juga blok dan ext4 dan f2fs.