Mengoptimalkan Waktu Boot

Dokumen ini memberikan panduan mitra untuk meningkatkan waktu booting untuk perangkat Android tertentu. Waktu booting merupakan komponen penting kinerja sistem karena pengguna harus menunggu booting selesai sebelum dapat menggunakan perangkat. Untuk perangkat seperti mobil dimana cold boot-up lebih sering terjadi, memiliki waktu boot yang cepat sangatlah penting (tidak ada orang yang suka menunggu puluhan detik hanya untuk memasukkan tujuan navigasi).

Android 8.0 memungkinkan pengurangan waktu booting dengan mendukung beberapa peningkatan di berbagai komponen. Tabel berikut merangkum peningkatan kinerja ini (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
  • Menghemat 0,15 detik untuk menghapus waktu tunggu/tes yang tidak perlu pada driver
  • Menghemat 0,12 detik untuk menghapus CONFIG_CC_OPTIMIZE_FOR_SIZE
penyetelan I/O
  • Disimpan 2 detik pada boot normal
  • Menghemat 25 detik pada boot pertama
init.*.rc
  • Menghemat 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 penghentian langsung animasi boot
kebijakan SELinux Disimpan 0,2 detik oleh genfscon

Mengoptimalkan Bootloader

Untuk mengoptimalkan bootloader agar waktu booting lebih baik:

  • Untuk pencatatan:
    • Nonaktifkan penulisan log ke UART karena dapat memakan waktu lama dengan banyak logging. (Pada perangkat Google Pixel, kami menemukannya memperlambat bootloader 1,5 detik).
    • Catat hanya situasi kesalahan dan pertimbangkan untuk menyimpan informasi lain ke memori dengan mekanisme terpisah untuk mengambilnya.
  • Untuk dekompresi kernel, pertimbangkan untuk menggunakan LZ4 untuk perangkat keras kontemporer daripada 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 opsi lainnya untuk perangkat keras spesifik Anda.
  • Periksa waktu tunggu yang tidak perlu untuk debouncing/entri mode 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 efisiensi I/O

Meningkatkan efisiensi I/O sangat penting untuk mempercepat waktu booting, dan pembacaan apa pun yang tidak diperlukan sebaiknya ditunda hingga booting selesai (di Google Pixel, sekitar 1,2 GB data dibaca saat booting).

Menyetel sistem file

Pembacaan awal kernel Linux dimulai ketika file dibaca dari awal atau ketika blok dibaca secara berurutan, sehingga perlu menyetel parameter penjadwal I/O secara khusus untuk booting (yang memiliki karakterisasi beban kerja berbeda dari aplikasi normal).

Perangkat yang mendukung pembaruan tanpa batas (A/B) mendapat manfaat besar 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 hilang yang terjadi pada setiap boot, gunakan alat generasi ext4 baru dengan mengatur TARGET_USES_MKE2FS di BoardConfig.mk.

Menganalisis I/O

Untuk memahami aktivitas I/O saat boot, gunakan data kernel ftrace (juga digunakan oleh systrace):

trace_event=block,ext4 in BOARD_KERNEL_CMDLINE

Untuk memecah akses file untuk setiap file, lakukan 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 booting dengan perincian langkah-langkah penting dalam proses booting.
  • system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace Memberikan informasi akses untuk setiap file.
  • system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace Memberikan perincian tingkat sistem.

Mengoptimalkan init.*.rc

Init adalah jembatan dari kernel hingga kerangka kerja dibuat, dan perangkat biasanya menghabiskan beberapa detik dalam tahapan init yang berbeda.

Menjalankan tugas secara paralel

Meskipun init Android saat ini kurang lebih merupakan proses thread tunggal, Anda masih dapat melakukan beberapa tugas secara paralel.

  • Jalankan perintah lambat di layanan skrip shell dan gabung 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 memerlukan waktu lama (di Android 8.0, perintah apa pun memerlukan waktu lebih dari 50 ms). Misalnya:
    init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms

    Meninjau log ini mungkin menunjukkan peluang untuk perbaikan.

  • Mulai layanan dan aktifkan perangkat periferal di jalur kritis sejak dini. 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 booting 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 di pemicu zygote-start (secara default, zygote diluncurkan di kelas main, yang lebih lambat dari 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 penghematan daya

Selama booting perangkat, pengaturan hemat daya untuk komponen seperti UFS dan/atau pengatur CPU dapat dinonaktifkan.

Perhatian: Penghematan 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 tip berikut untuk mengoptimalkan animasi boot.

Mengonfigurasi permulaan awal

Android 8.0 memungkinkan memulai animasi booting lebih awal, sebelum memasang partisi data pengguna. Namun, meskipun menggunakan rantai alat ext4 baru di Android 8.0, fsck masih terpicu secara berkala karena alasan keamanan, sehingga menyebabkan penundaan dalam memulai layanan bootanimasi.

Untuk memulai bootanimasi lebih awal, bagi pemasangan fstab menjadi dua fase:

  • Pada tahap awal, pasang hanya partisi (seperti system/ dan vendor/ ) yang tidak memerlukan pemeriksaan proses, lalu mulai layanan animasi booting dan dependensinya (seperti servicemanager dan Surfaceflinger).
  • Pada fase kedua, pasang partisi (seperti data/ ) yang memerlukan pemeriksaan jalankan.

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 durasinya dapat memperlambat waktu booting. Sistem yang melakukan booting dengan cepat tidak memerlukan animasi panjang yang dapat secara efektif menyembunyikan perbaikan apa pun yang dilakukan. Kami merekomendasikan agar perulangan berulang dan akhir menjadi pendek.

Mengoptimalkan SELinux

Gunakan tip berikut untuk mengoptimalkan SELinux untuk meningkatkan waktu boot.

  • Gunakan ekspresi reguler yang bersih (regex) . Regex yang bentuknya buruk dapat menyebabkan banyak overhead saat mencocokkan kebijakan SELinux untuk sys/devices di file_contexts . Misalnya, regex /sys/devices/.*abc.*(/.*)? secara keliru memaksa pemindaian semua subdirektori /sys/devices yang berisi "abc", mengaktifkan 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. Hal ini juga membantu memperbaiki file yang dibuat oleh kernel dengan label yang salah, mencegah kondisi balapan yang dapat terjadi antara proses ruang pengguna yang mencoba mengakses file ini sebelum pelabelan ulang terjadi.

Alat dan metode

Gunakan alat berikut untuk membantu Anda mengumpulkan data untuk target pengoptimalan.

Bagan boot

Bootchart menyediakan perincian beban CPU dan I/O dari semua proses untuk keseluruhan sistem. Itu tidak memerlukan pembangunan kembali citra sistem dan dapat digunakan sebagai pemeriksaan kewarasan cepat sebelum masuk ke systrace.

Untuk mengaktifkan bootchart:

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.

Jika bootchart tidak berfungsi dan Anda mendapatkan pesan kesalahan yang mengatakan bahwa bootchart.png tidak ada, lakukan hal berikut:
  1. Jalankan perintah berikut:
          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
        
  2. Perbarui $ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh agar menunjuk ke salinan lokal pybootchartgui (terletak di ~/Documents/bootchart/pybootchartgui.py )

Systrace

Systrace memungkinkan pengumpulan jejak kernel dan Android saat boot. Visualisasi systrace dapat membantu dalam menganalisis masalah tertentu selama boot-up. (Namun, untuk memeriksa jumlah rata-rata atau jumlah akumulasi selama keseluruhan 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 mengaktifkan penelusuran (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
  • Di file BoardConfig.mk perangkat, tambahkan yang berikut:
    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 yang berikut:
    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