Halaman ini memberikan tips untuk meningkatkan waktu booting.
Menghapus simbol debug dari modul
Mirip dengan cara simbol debug dihapus dari kernel di perangkat produksi, pastikan Anda juga menghapus simbol debug dari modul. Menghapus simbol debug dari modul membantu waktu booting dengan mengurangi hal berikut:
- Waktu yang diperlukan untuk membaca biner dari flash.
- Waktu yang diperlukan untuk mendekompresi ramdisk.
- Waktu yang diperlukan untuk memuat modul.
Menghapus simbol debug dari modul dapat menghemat beberapa detik selama booting.
Penghapusan simbol diaktifkan secara default dalam build platform Android, tetapi
untuk mengaktifkannya secara eksplisit, tetapkan
BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES dalam konfigurasi khusus perangkat Anda
di bagian device/vendor/device.
Menggunakan kompresi LZ4 untuk kernel dan ramdisk
Gzip menghasilkan output terkompresi yang lebih kecil dibandingkan dengan LZ4, tetapi LZ4 melakukan dekompresi lebih cepat daripada Gzip. Untuk kernel dan modul, pengurangan ukuran penyimpanan absolut dari penggunaan Gzip tidak terlalu signifikan dibandingkan dengan manfaat waktu dekompresi LZ4.
Dukungan untuk kompresi ramdisk LZ4 telah ditambahkan ke build platform Android melalui BOARD_RAMDISK_USE_LZ4. Anda dapat menyetel opsi ini di konfigurasi khusus perangkat. Kompresi kernel dapat disetel melalui defconfig kernel.
Beralih ke LZ4 akan memberikan waktu booting 500 md hingga 1000 md lebih cepat.
Hindari logging yang berlebihan di driver Anda
Di ARM64 dan ARM32, panggilan fungsi yang berjarak lebih dari jarak tertentu dari situs panggilan memerlukan tabel lompatan (disebut tabel penghubung prosedur, atau PLT) agar dapat mengenkode alamat lompatan penuh. Karena modul dimuat secara dinamis, tabel lompatan ini perlu diperbaiki selama pemuatan modul. Panggilan yang perlu direlokasi disebut entri relokasi dengan entri addenda eksplisit (atau RELA, singkatnya) dalam format ELF.
Kernel Linux melakukan beberapa pengoptimalan ukuran memori (seperti pengoptimalan hit cache) saat mengalokasikan PLT. Dengan commit upstream ini,
skema pengoptimalan memiliki kompleksitas O(N^2), dengan N adalah jumlah
Rela dari jenis R_AARCH64_JUMP26 atau R_AARCH64_CALL26. Jadi, memiliki lebih sedikit RLA jenis ini akan membantu mengurangi waktu pemuatan modul.
Salah satu pola coding umum yang meningkatkan jumlah
R_AARCH64_CALL26 atau RULA adalah logging yang berlebihan dalam
driver.R_AARCH64_JUMP26 Setiap panggilan ke printk() atau skema logging lainnya biasanya menambahkan entri RELA CALL26/JUMP26. Dalam teks commit di commit upstream,
,perhatikan bahwa meskipun dengan pengoptimalan, enam modul memerlukan waktu sekitar 250 md untuk dimuat—hal ini karena enam modul tersebut adalah enam modul teratas dengan jumlah logging terbanyak.
Mengurangi logging dapat menghemat sekitar 100 - 300 md pada waktu booting, bergantung pada seberapa berlebihan logging yang ada.
Mengaktifkan penyelidikan asinkron secara selektif
Saat modul dimuat, jika perangkat yang didukungnya telah diisi dari DT (devicetree) dan ditambahkan ke driver core, maka pemeriksaan perangkat dilakukan dalam konteks panggilan module_init(). Saat penyelidikan perangkat selesai dalam konteks module_init(), modul tidak dapat menyelesaikan pemuatan hingga penyelidikan selesai. Karena pemuatan modul sebagian besar diserialkan, perangkat yang
membutuhkan waktu yang relatif lama untuk melakukan penyelidikan akan memperlambat waktu booting.
Untuk menghindari waktu booting yang lebih lambat, aktifkan pemeriksaan asinkron untuk modul yang membutuhkan waktu lama untuk memeriksa perangkatnya. Mengaktifkan penyelidikan asinkron untuk semua modul mungkin tidak bermanfaat karena waktu yang diperlukan untuk membuat cabang thread dan memulai penyelidikan mungkin sama dengan waktu yang diperlukan untuk menyelidiki perangkat.
Perangkat yang terhubung melalui bus lambat seperti I2C, perangkat yang memuat firmware dalam fungsi probe-nya, dan perangkat yang melakukan banyak inisialisasi hardware dapat menyebabkan masalah pengaturan waktu. Cara terbaik untuk mengidentifikasi kapan hal ini terjadi adalah mengumpulkan waktu pemeriksaan untuk setiap driver dan mengurutkannya.
Untuk mengaktifkan pemeriksaan asinkron untuk modul, tidak cukup hanya dengan
menyetel tanda PROBE_PREFER_ASYNCHRONOUS
dalam kode driver. Untuk modul, Anda juga perlu menambahkan
module_name.async_probe=1 di command line kernel
atau meneruskan async_probe=1 sebagai parameter modul saat memuat modul menggunakan
modprobe atau insmod.
Mengaktifkan penyelidikan asinkron dapat menghemat sekitar 100 - 500 md pada waktu booting bergantung pada hardware/driver Anda.
Periksa driver CPUfreq Anda sedini mungkin
Semakin awal driver CPUfreq Anda melakukan probing, semakin cepat Anda dapat menskalakan frekuensi CPU ke maksimum (atau maksimum yang dibatasi secara termal) selama booting. Makin cepat CPU, makin cepat booting. Pedoman ini juga berlaku untuk driver yang mengontrol frekuensi DRAM, memori, dan interkoneksi.devfreq
Dengan modul, urutan pemuatan dapat bergantung pada tingkat initcall dan urutan kompilasi atau penautan driver. Gunakan alias MODULE_SOFTDEP() untuk memastikan driver cpufreq adalah salah satu dari beberapa modul pertama yang dimuat.
Selain memuat modul lebih awal, Anda juga harus memastikan semua dependensi untuk menyelidiki driver CPUfreq juga telah diselidiki. Misalnya, jika Anda memerlukan clock atau pegangan regulator untuk mengontrol frekuensi CPU, pastikan keduanya diperiksa terlebih dahulu. Atau, Anda mungkin perlu memuat driver termal sebelum driver CPUfreq jika CPU Anda berpotensi menjadi terlalu panas selama proses booting. Jadi, lakukan apa yang dapat Anda lakukan untuk memastikan driver CPUfreq dan devfreq yang relevan diperiksa sedini mungkin.
Penghematan dari penyelidikan driver CPUfreq Anda lebih awal bisa sangat kecil hingga sangat besar, bergantung pada seberapa awal Anda bisa mendapatkan penyelidikan ini dan pada frekuensi berapa bootloader meninggalkan CPU.
Memindahkan modul ke inisialisasi tahap kedua, partisi vendor, atau vendor_dlkm
Karena proses inisialisasi tahap pertama diserialkan, tidak banyak
peluang untuk memparalelkan proses booting. Jika modul tidak diperlukan agar inisialisasi tahap pertama selesai, pindahkan modul ke inisialisasi tahap kedua dengan menempatkannya di partisi vendor atau vendor_dlkm.
Inisialisasi tahap pertama tidak memerlukan pemeriksaan beberapa perangkat untuk mencapai inisialisasi tahap kedua. Hanya kemampuan penyimpanan flash dan konsol yang diperlukan untuk alur booting normal.
Muat driver penting berikut:
watchdogresetcpufreq
Untuk mode pemulihan dan ruang pengguna fastbootd, inisialisasi tahap pertama memerlukan lebih banyak perangkat untuk diuji (seperti USB), dan tampilan. Simpan salinan modul ini di
ramdisk tahap pertama dan di partisi vendor atau vendor_dlkm. Hal ini memungkinkan file tersebut dimuat di inisialisasi tahap pertama untuk pemulihan atau alur booting fastbootd. Namun,
jangan muat modul mode pemulihan dalam inisialisasi tahap pertama selama alur booting normal. Modul mode pemulihan dapat ditunda ke inisialisasi tahap kedua untuk mengurangi
waktu booting. Semua modul lain yang tidak diperlukan dalam inisialisasi tahap pertama harus dipindahkan ke partisi vendor atau vendor_dlkm.
Dengan daftar perangkat leaf (misalnya, UFS atau serial),
dev needs.sh
skrip menemukan semua driver, perangkat, dan modul yang diperlukan untuk dependensi atau
pemasok (misalnya, clock, regulator, atau gpio) yang akan diselidiki.
Memindahkan modul ke inisialisasi tahap kedua akan mengurangi waktu booting dengan cara berikut:
- Pengurangan ukuran ramdisk.
- Hal ini menghasilkan pembacaan flash yang lebih cepat saat bootloader memuat ramdisk (langkah booting yang diserialkan).
- Hal ini menghasilkan kecepatan dekompresi yang lebih cepat saat kernel mendekompresi ramdisk (langkah booting yang diserialkan).
- Inisialisasi tahap kedua berjalan secara paralel, yang menyembunyikan waktu pemuatan modul dengan pekerjaan yang dilakukan dalam inisialisasi tahap kedua.
Memindahkan modul ke tahap kedua dapat menghemat 500 - 1000 md pada waktu booting, bergantung pada jumlah modul yang dapat Anda pindahkan ke inisialisasi tahap kedua.
Logistik pemuatan modul
Build Android terbaru menampilkan konfigurasi papan yang mengontrol modul mana yang disalin ke setiap tahap, dan modul mana yang dimuat. Bagian ini berfokus pada subset berikut:
BOARD_VENDOR_RAMDISK_KERNEL_MODULES. Daftar modul ini akan disalin ke dalam ramdisk.BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD. Daftar modul ini akan dimuat pada inisialisasi tahap pertama.BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD. Daftar modul ini akan dimuat saat pemulihan ataufastbootddipilih dari ramdisk.BOARD_VENDOR_KERNEL_MODULES. Daftar modul ini akan disalin ke partisi vendor atauvendor_dlkmdi direktori/vendor/lib/modules/.BOARD_VENDOR_KERNEL_MODULES_LOAD. Daftar modul ini akan dimuat dalam inisialisasi tahap kedua.
Modul boot dan pemulihan di ramdisk juga harus disalin ke partisi vendor atau
vendor_dlkm di /vendor/lib/modules. Menyalin modul ini ke partisi vendor memastikan modul tidak terlihat selama inisialisasi tahap kedua, yang berguna untuk proses debug dan pengumpulan modinfo untuk laporan bug.
Duplikasi harus menggunakan ruang minimal di vendor atau partisi selama set modul booting diminimalkan.vendor_dlkm Pastikan file
modules.list vendor memiliki daftar modul yang difilter di /vendor/lib/modules.
Daftar yang difilter memastikan waktu booting tidak terpengaruh oleh pemuatan modul lagi (yang merupakan proses yang mahal).
Pastikan modul mode pemulihan dimuat sebagai grup. Memuat modul mode pemulihan dapat dilakukan dalam mode pemulihan, atau di awal inisialisasi tahap kedua dalam setiap alur booting.
Anda dapat menggunakan file Board.Config.mk perangkat untuk melakukan tindakan ini seperti yang terlihat dalam contoh berikut:
# All kernel modules
KERNEL_MODULES := $(wildcard $(KERNEL_MODULE_DIR)/*.ko)
KERNEL_MODULES_LOAD := $(strip $(shell cat $(KERNEL_MODULE_DIR)/modules.load)
# First stage ramdisk modules
BOOT_KERNEL_MODULES_FILTER := $(foreach m,$(BOOT_KERNEL_MODULES),%/$(m))
# Recovery ramdisk modules
RECOVERY_KERNEL_MODULES_FILTER := $(foreach m,$(RECOVERY_KERNEL_MODULES),%/$(m))
BOARD_VENDOR_RAMDISK_KERNEL_MODULES += \
$(filter $(BOOT_KERNEL_MODULES_FILTER) \
$(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES))
# ALL modules land in /vendor/lib/modules so they could be rmmod/insmod'd,
# and modules.list actually limits us to the ones we intend to load.
BOARD_VENDOR_KERNEL_MODULES := $(KERNEL_MODULES)
# To limit /vendor/lib/modules to just the ones loaded, use:
# BOARD_VENDOR_KERNEL_MODULES := $(filter-out \
# $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES))
# Group set of /vendor/lib/modules loading order to recovery modules first,
# then remainder, subtracting both recovery and boot modules which are loaded
# already.
BOARD_VENDOR_KERNEL_MODULES_LOAD := \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER), \
$(filter $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)))
BOARD_VENDOR_KERNEL_MODULES_LOAD += \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER) \
$(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
# NB: Load order governed by modules.load and not by $(BOOT_KERNEL_MODULES)
BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD := \
$(filter $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
# Group set of /vendor/lib/modules loading order to boot modules first,
# then the remainder of recovery modules.
BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD := \
$(filter $(BOOT_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD))
BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD += \
$(filter-out $(BOOT_KERNEL_MODULES_FILTER), \
$(filter $(RECOVERY_KERNEL_MODULES_FILTER),$(KERNEL_MODULES_LOAD)))
Contoh ini menampilkan subset BOOT_KERNEL_MODULES dan RECOVERY_KERNEL_MODULES yang lebih mudah dikelola untuk ditentukan secara lokal dalam file konfigurasi papan. Skrip sebelumnya menemukan dan mengisi setiap modul subset dari
modul kernel yang tersedia yang dipilih, dan menyisakan modul yang tersisa untuk inisialisasi
tahap kedua.
Untuk inisialisasi tahap kedua, sebaiknya jalankan pemuatan modul sebagai layanan agar tidak memblokir alur booting. Gunakan skrip shell untuk mengelola pemuatan modul sehingga logistik lain, seperti penanganan dan mitigasi error, atau penyelesaian pemuatan modul, dapat dilaporkan kembali (atau diabaikan) jika perlu.
Anda dapat mengabaikan kegagalan pemuatan modul debug yang tidak ada pada build pengguna.
Untuk mengabaikan kegagalan ini, tetapkan properti vendor.device.modules.ready untuk
memicu tahap selanjutnya dari bootflow pembuatan skrip init rc agar dapat melanjutkan ke layar peluncuran. Lihat contoh skrip berikut, jika Anda memiliki kode berikut
di /vendor/etc/init.insmod.sh:
#!/vendor/bin/sh
. . .
if [ $# -eq 1 ]; then
cfg_file=$1
else
# Set property even if there is no insmod config
# to unblock early-boot trigger
setprop vendor.common.modules.ready
setprop vendor.device.modules.ready
exit 1
fi
if [ -f $cfg_file ]; then
while IFS="|" read -r action arg
do
case $action in
"insmod") insmod $arg ;;
"setprop") setprop $arg 1 ;;
"enable") echo 1 > $arg ;;
"modprobe") modprobe -a -d /vendor/lib/modules $arg ;;
. . .
esac
done < $cfg_file
fi
Dalam file rc hardware, layanan one shot dapat ditentukan dengan:
service insmod-sh /vendor/etc/init.insmod.sh /vendor/etc/init.insmod.<hw>.cfg
class main
user root
group root system
Disabled
oneshot
Pengoptimalan tambahan dapat dilakukan setelah modul berpindah dari tahap pertama ke tahap kedua. Anda dapat menggunakan fitur daftar blokir modprobe untuk memisahkan alur booting tahap kedua guna menyertakan pemuatan modul yang ditangguhkan untuk modul yang tidak penting. Pemuatan modul yang digunakan secara eksklusif oleh HAL tertentu dapat ditunda untuk memuat modul hanya saat HAL dimulai.
Untuk meningkatkan waktu booting yang terlihat, Anda dapat secara khusus memilih modul di layanan pemuatan modul yang lebih kondusif untuk dimuat setelah layar peluncuran. Misalnya, Anda dapat memuat modul secara eksplisit untuk
dekoder video atau Wi-Fi setelah alur booting init dibersihkan
(sys.boot_complete
sinyal properti Android, misalnya). Pastikan HAL untuk modul yang dimuat terlambat memblokir cukup lama saat driver kernel tidak ada.
Atau, Anda dapat menggunakan perintah wait<file>[<timeout>] init dalam skrip rc alur booting untuk menunggu entri sysfs tertentu menunjukkan bahwa modul driver telah menyelesaikan operasi pemeriksaan. Contohnya adalah menunggu
driver tampilan selesai dimuat di latar belakang pemulihan atau fastbootd,
sebelum menampilkan grafis menu.
Lakukan inisialisasi frekuensi CPU ke nilai yang wajar di bootloader
Tidak semua SoC/produk dapat mem-boot CPU pada frekuensi tertinggi karena masalah termal atau daya selama pengujian boot loop. Namun, pastikan bootloader menyetel frekuensi semua CPU yang aktif ke setinggi mungkin dengan aman untuk SoC atau produk. Hal ini sangat penting karena, dengan kernel modular sepenuhnya, dekompresi init ramdisk terjadi sebelum driver CPUfreq dapat dimuat. Jadi, jika CPU dibiarkan pada frekuensi yang lebih rendah oleh bootloader, waktu dekompresi ramdisk dapat memakan waktu lebih lama daripada kernel yang dikompilasi secara statis (setelah disesuaikan dengan perbedaan ukuran ramdisk) karena frekuensi CPU akan sangat rendah saat melakukan pekerjaan intensif CPU (dekompresi). Hal yang sama berlaku untuk frekuensi memori dan interkoneksi.
Menginisialisasi frekuensi CPU besar di bootloader
Sebelum driver CPUfreq dimuat, kernel tidak mengetahui frekuensi CPU dan tidak menskalakan kapasitas penjadwalan CPU untuk frekuensi saat ini. Kernel dapat memigrasikan thread ke CPU besar jika beban cukup tinggi di CPU kecil.
Pastikan CPU besar memiliki performa setidaknya sama dengan CPU kecil untuk frekuensi saat bootloader membiarkannya. Misalnya, jika CPU besar memiliki performa 2x lebih baik daripada CPU kecil untuk frekuensi yang sama, tetapi bootloader menyetel frekuensi CPU kecil ke 1,5 GHz dan frekuensi CPU besar ke 300 MHz, maka performa booting akan menurun jika kernel memindahkan thread ke CPU besar. Dalam contoh ini, jika aman untuk mem-boot CPU besar pada 750 MHz, Anda harus melakukannya meskipun Anda tidak berencana menggunakannya secara eksplisit.
Driver tidak boleh memuat firmware dalam inisialisasi tahap pertama
Mungkin ada beberapa kasus yang tidak dapat dihindari saat firmware perlu dimuat di inisialisasi tahap pertama. Namun secara umum, driver tidak boleh memuat firmware apa pun dalam inisialisasi tahap pertama, terutama dalam konteks pemeriksaan perangkat. Memuat firmware di init tahap pertama menyebabkan seluruh proses booting terhenti jika firmware tidak tersedia di ramdisk tahap pertama. Meskipun firmware ada di ramdisk tahap pertama, hal ini tetap menyebabkan penundaan yang tidak perlu.