Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Mengoptimalkan Waktu Boot

Dokumen ini memberikan panduan mitra untuk meningkatkan waktu boot untuk perangkat Android tertentu. Waktu boot adalah komponen penting dari kinerja sistem karena pengguna harus menunggu boot 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 (sebagaimana diukur pada perangkat Google Pixel dan Pixel XL).

Komponen Perbaikan
Bootloader
  • 1.6s disimpan dengan menghapus log UART
  • Menyimpan 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
  • 0,3 dtk disimpan dengan pengoptimalan prefetch dm-verity
  • Menyimpan 0.15 detik untuk menghapus menunggu / tes yang tidak perlu di driver
  • Menyimpan 0.12 detik untuk menghapus CONFIG_CC_OPTIMIZE_FOR_SIZE
Penyetelan I / O
  • Menyimpan 2 detik pada boot normal
  • Menyimpan 25 detik saat boot pertama
init. *. rc
  • 1,5s disimpan dengan paralel perintah init
  • Menghemat 0,25 detik dengan memulai zigot lebih awal
  • Disimpan 0.22s oleh cpuset tune
Animasi boot
  • Memulai 2 detik lebih awal saat boot tanpa pemicu fsck, jauh lebih besar saat boot dengan boot yang dipicu fsck
  • Menyimpan 5 detik di Pixel XL dengan segera mematikan animasi boot
Kebijakan SELinux Disimpan 0.2s oleh genfscon

Mengoptimalkan Bootloader

Untuk mengoptimalkan bootloader untuk waktu boot yang lebih baik:

  • Untuk logging:
    • Nonaktifkan penulisan log ke UART karena dapat memakan waktu lama dengan banyak logging. (Di perangkat Google Pixel, kami menemukan itu memperlambat bootloader 1.5s).
    • Catat hanya situasi kesalahan dan pertimbangkan untuk menyimpan informasi lain ke memori dengan mekanisme terpisah untuk mengambil.
  • Untuk dekompresi kernel, pertimbangkan untuk menggunakan LZ4 untuk perangkat keras kontemporer daripada GZIP (contoh tambalan ). 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 debouncing / entri mode khusus dan minimalkan.
  • Berikan 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 node tersebut tidak dikonfigurasi agar dapat diakses oleh ruang pengguna). Hapus node tersebut jika ditemukan.
  • Batalkan setelan CONFIG yang tidak digunakan . Tinjau file .config yang dibuat oleh kernel build untuk secara eksplisit membatalkan setelan 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 seperti itu (yaitu CONFIG_IOMMU_IO_PGTABLE_FAST_SELFTEST) harus dihapus di kernel produksi.

Meminimalkan ukuran driver

Beberapa driver di kernel perangkat dapat dihapus jika fungsinya tidak digunakan untuk mengurangi ukuran kernel lebih lanjut. Misalnya, jika WLAN dihubungkan melalui PCIe, dukungan SDIO tidak digunakan dan harus dihapus selama waktu kompilasi. Untuk detailnya, lihat kernel Google Pixel: net: wireless: cnss: add opsi untuk menonaktifkan dukungan SDIO.

Menghapus pengoptimalan compiler 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 hot cache hit (dan dengan demikian menjadi lebih cepat). Namun, asumsi ini tidak lagi valid karena SoC seluler modern telah menjadi lebih kuat.

Selain itu, menghapus flag dapat mengaktifkan peringatan compiler untuk variabel yang tidak diinisialisasi, yang disembunyikan di kernel Linux ketika flag CONFIG_CC_OPTIMIZE_FOR_SIZE ada (melakukan perubahan ini saja telah membantu kami menemukan banyak bug yang berarti di beberapa driver perangkat Android).

Menunda inisialisasi

Banyak proses diluncurkan selama boot, tetapi hanya komponen di jalur kritis (bootloader> kernel> init> mount sistem file> zygote> server sistem) yang secara langsung memengaruhi waktu boot. Profil initcall selama booting kernel untuk mengidentifikasi periferal / komponen yang lambat dan tidak penting untuk memulai proses init, kemudian tunda periferal / komponen tersebut hingga nanti dalam proses boot dengan berpindah ke modul kernel yang dapat dimuat. Pindah ke perangkat asinkron / probe driver juga dapat membantu paralel komponen lambat di jalur kritis kernel> init.

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 mempercepat waktu boot, dan membaca apa pun yang tidak perlu harus ditunda hingga setelah boot (di Google Pixel, sekitar 1,2 GB data dibaca saat boot).

Menyetel sistem file

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

Perangkat yang mendukung pembaruan tanpa batas (A / B) mendapatkan keuntungan besar dari penyetelan sistem file pada boot pertama kali (mis. 20-an pada Google Pixel). Contohnya, 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
    ...

Miscellaneous

  • 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 dijatuhkan yang terjadi 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, lakukan perubahan berikut pada kernel (khusus pengembangan kernel; 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 booting.

  • 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 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 Android init saat ini kurang lebih merupakan proses berulir tunggal, Anda masih dapat melakukan beberapa tugas secara paralel.

  • Jalankan perintah lambat dalam 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 md). 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 lebih awal. Misalnya, beberapa SOC memerlukan memulai layanan terkait keamanan sebelum memulai SurfaceFlinger. Tinjau log sistem ketika ServiceManager menampilkan "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 selama boot dapat menyebabkan penundaan yang lama jika init sibuk dalam 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 selama 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 kelas utama, yang lebih lama dari zygote-start). Saat melakukan ini, pastikan untuk mengizinkan zygote berjalan di semua CPU (karena pengaturan cpuset yang salah dapat memaksa zygote untuk berjalan di CPU tertentu).

Nonaktifkan penghematan daya

Selama perangkat melakukan booting, pengaturan hemat daya untuk komponen seperti UFS dan / atau pengatur 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 ditangguhkan 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.

Konfigurasi awal

Android 8.0 memungkinkan memulai animasi booting lebih awal, sebelum memasang partisi data pengguna. Namun, bahkan saat menggunakan rangkaian 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 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 proses.

Animasi boot akan dimulai lebih cepat (dan dalam waktu yang konstan) terlepas dari fsck.

Finishing bersih

Setelah menerima sinyal keluar, bootanimation memainkan bagian terakhir, yang lamanya dapat memperlambat waktu boot. Sistem yang melakukan booting dengan cepat tidak memerlukan animasi panjang yang secara efektif dapat menyembunyikan peningkatan yang dibuat. Kami merekomendasikan membuat loop berulang dan finale pendek.

Mengoptimalkan SELinux

Gunakan tip berikut untuk mengoptimalkan SELinux untuk waktu boot yang lebih baik.

  • Gunakan ekspresi reguler yang bersih (regex) . Regex dengan format yang 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 sudah ada ini meneruskan prefiks pencocokan file ke kernel dalam biner SELinux, di mana kernel menerapkannya ke sistem file yang dibuat oleh kernel. Ini juga membantu memperbaiki file yang dibuat kernel dengan label yang salah, mencegah kondisi balapan yang dapat terjadi antara proses userspace yang mencoba mengakses file ini sebelum pelabelan ulang terjadi.

Alat dan metode

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

Bootchart

Bootchart menyediakan pemecahan beban CPU dan I / O dari semua proses untuk keseluruhan sistem. Ini tidak memerlukan membangun kembali citra sistem dan dapat digunakan sebagai pemeriksaan kesehatan 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.

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 terakumulasi selama boot keseluruhan, lebih mudah untuk melihat jejak kernel secara langsung).

Untuk mengaktifkan systrace selama 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

    Untuk:

      #    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
  • Di 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.

  • Di file init.rc khusus init.rc , tambahkan yang 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