Mengoptimalkan Waktu Booting

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
  • Menghemat 1,6 detik dengan menghapus log UART
  • Menghemat 0,4 detik dengan mengubah ke LZ4 dari GZIP
Kernel perangkat
  • Menghemat 0,3 detik dengan menghapus konfigurasi kernel yang tidak digunakan dan mengurangi ukuran driver
  • Menghemat 0,3 detik dengan optimasi prefetch dm-verity
  • Disimpan 0,15 detik untuk menghapus tunggu/tes yang tidak perlu di driver
  • Disimpan 0,12 detik untuk menghapus CONFIG_CC_OPTIMIZE_FOR_SIZE
Penyetelan I/O
  • Disimpan 2 detik pada boot normal
  • Disimpan 25 detik pada boot pertama
init.*.rc
  • Disimpan 1,5 detik dengan memparalelkan perintah init
  • Menghemat 0,25 detik dengan memulai zigot lebih awal
  • Disimpan 0,22 detik oleh cpuset tune
Animasi boot
  • Dimulai 2 detik lebih awal saat boot tanpa dipicu fsck, jauh lebih besar saat boot dengan boot yang dipicu fsck
  • Menghemat 5 detik di Pixel XL dengan shutdown langsung 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/ dan vendor/ ) 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 di file_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
  • Ini memungkinkan pelacakan (yang dinonaktifkan secara default).

  • 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
  • Untuk analisis I/O terperinci, tambahkan juga blok dan ext4 dan f2fs.

  • 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