Halaman ini memberikan tips untuk meningkatkan waktu booting.
Menghapus simbol debug dari modul
Serupa 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 waktu 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
di bagian perangkat/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 menetapkan opsi ini
di konfigurasi khusus perangkat. Kompresi kernel dapat ditetapkan melalui defconfig kernel.
Beralih ke LZ4 akan memberikan waktu booting 500 md hingga 1000 md lebih cepat.
Menghindari logging yang berlebihan di driver
Di ARM64 dan ARM32, panggilan fungsi yang berjarak lebih dari jarak tertentu dari situs panggilan memerlukan jump table (disebut tabel penautan prosedur, atau PLT) agar dapat mengenkode alamat lompatan lengkap. Karena modul dimuat secara dinamis, tabel lompat ini perlu diperbaiki selama pemuatan modul. Panggilan yang memerlukan relokasi disebut entri relokasi dengan entri tambahan eksplisit (atau RELA, untuk 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 RELA
dari jenis ini akan membantu mengurangi waktu pemuatan modul.
Salah satu pola coding umum yang meningkatkan jumlah
RELA R_AARCH64_CALL26
atau R_AARCH64_JUMP26
adalah logging yang berlebihan di
driver. Setiap panggilan ke printk()
atau skema logging lainnya biasanya menambahkan
entri RELA CALL26
/JUMP26
. Dalam teks commit dalam 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 pencatatan log dapat menghemat waktu sekitar 100 - 300 md pada waktu booting, bergantung pada seberapa berlebihan logging yang ada.
Mengaktifkan probing asinkron, secara selektif
Saat modul dimuat, jika perangkat yang didukungnya telah
diisi dari DT (devicetree) dan ditambahkan ke core driver, maka probe
perangkat dilakukan dalam konteks panggilan module_init()
. Jika pemeriksaan perangkat
dilakukan dalam konteks module_init()
, modul tidak dapat menyelesaikan pemuatan hingga
pemeriksaan selesai. Karena pemuatan modul sebagian besar diserialisasi, perangkat yang
memerlukan waktu yang relatif lama untuk diperiksa akan memperlambat waktu booting.
Untuk menghindari waktu booting yang lebih lambat, aktifkan pemindaian asinkron untuk modul yang memerlukan waktu untuk memindai perangkatnya. Mengaktifkan pemeriksaan asinkron untuk semua modul mungkin tidak bermanfaat karena waktu yang diperlukan untuk melakukan fork thread dan memulai pemeriksaan mungkin setinggi waktu yang diperlukan untuk menyelidiki perangkat.
Perangkat yang terhubung melalui bus lambat seperti I2C, perangkat yang melakukan pemuatan firmware dalam fungsi probe, dan perangkat yang melakukan banyak inisialisasi hardware dapat menyebabkan masalah pengaturan waktu. Cara terbaik untuk mengidentifikasi kapan hal ini terjadi adalah dengan mengumpulkan waktu pemeriksaan untuk setiap driver dan mengurutkannya.
Untuk mengaktifkan pemindaian asinkron untuk modul, tidak cukup hanya
menetapkan 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 probing asinkron dapat menghemat sekitar 100 - 500 md pada waktu booting, bergantung pada hardware/driver Anda.
Periksa driver CPUfreq sedini mungkin
Semakin awal driver CPUfreq melakukan pemeriksaan, semakin cepat Anda dapat menskalakan frekuensi CPU
ke maksimum (atau beberapa maksimum yang dibatasi secara termal) selama booting. Makin
cepat CPU, makin cepat booting. Panduan ini juga berlaku untuk driver
devfreq
yang mengontrol DRAM, memori, dan frekuensi interkoneksi.
Dengan modul, urutan pemuatan dapat bergantung pada level 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 memeriksa driver CPUfreq juga telah diperiksa. Misalnya, jika Anda memerlukan handle regulator atau clock untuk mengontrol frekuensi CPU, pastikan handle tersebut diuji terlebih dahulu. Atau, Anda mungkin memerlukan driver termal dimuat sebelum driver CPUfreq jika CPU Anda menjadi terlalu panas selama booting. Jadi, lakukan apa yang Anda bisa untuk memastikan CPUfreq dan driver devfreq yang relevan menyelidiki sedini mungkin.
Penghematan dari menyelidiki driver CPUfreq lebih awal dapat sangat kecil hingga sangat besar, bergantung pada seberapa awal Anda dapat menyelidikinya dan pada frekuensi apa bootloader meninggalkan CPU.
Memindahkan modul ke partisi init tahap kedua, vendor, atau vendor_dlkm
Karena proses init tahap pertama diserialisasi, tidak ada banyak
kesempatan untuk melakukan paralelisasi 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 sampai ke inisialisasi tahap kedua. Hanya kemampuan konsol dan penyimpanan flash yang diperlukan untuk alur booting normal.
Muat driver penting berikut:
watchdog
reset
cpufreq
Untuk mode fastbootd
pemulihan dan ruang pengguna, inisialisasi tahap pertama memerlukan lebih banyak
perangkat untuk diselidiki (seperti USB), dan ditampilkan. Simpan salinan modul ini di
ramdisk tahap pertama dan di partisi vendor atau vendor_dlkm
. Hal ini memungkinkannya
dimuat dalam inisialisasi tahap pertama untuk pemulihan atau alur booting fastbootd
. Namun,
jangan memuat modul mode pemulihan dalam inisialisasi tahap pertama selama alur
booting normal. Modul mode pemulihan dapat ditangguhkan ke init tahap kedua untuk mengurangi
waktu booting. Semua modul lain yang tidak diperlukan pada init tahap pertama harus
dipindahkan ke partisi vendor_dlkm
atau vendor.
Dengan daftar perangkat leaf (misalnya, UFS atau serial),
skrip
dev needs.sh
menemukan semua driver, perangkat, dan modul yang diperlukan untuk dependensi atau
penyedia (misalnya, clock, regulator, atau gpio
) untuk diselidiki.
Memindahkan modul ke init 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 serial).
- Hal ini menghasilkan kecepatan dekompresi yang lebih cepat saat kernel mendekompresi ramdisk (langkah booting serial).
- Init tahap kedua berfungsi secara paralel, yang menyembunyikan waktu pemuatan modul dengan tugas yang dilakukan pada init 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 board 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 ramdisk.BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD
. Daftar modul ini akan dimuat dalam inisialisasi tahap pertama.BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD
. Daftar modul ini yang akan dimuat saat pemulihan ataufastbootd
dipilih dari ramdisk.BOARD_VENDOR_KERNEL_MODULES
. Daftar modul ini akan disalin ke partisi vendor atauvendor_dlkm
di direktori/vendor/lib/modules/
.BOARD_VENDOR_KERNEL_MODULES_LOAD
. Daftar modul ini yang akan dimuat dalam init tahap kedua.
Modul booting dan pemulihan di ramdisk juga harus disalin ke partisi vendor atau
vendor_dlkm
di /vendor/lib/modules
. Menyalin modul ini ke
partisi vendor akan memastikan modul tidak terlihat selama proses init tahap kedua,
yang berguna untuk men-debug dan mengumpulkan modinfo
untuk laporan bug.
Duplikasi ini akan memerlukan sedikit ruang pada vendor atau partisi vendor_dlkm
selama kumpulan modul booting diminimalkan. Pastikan file
modules.list
vendor memiliki daftar modul yang difilter di /vendor/lib/modules
.
Daftar yang difilter memastikan waktu booting tidak terpengaruh oleh modul yang dimuat
lagi (yang merupakan proses yang mahal).
Pastikan modul mode pemulihan dimuat sebagai satu 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
board. Skrip sebelumnya menemukan dan mengisi setiap modul subset dari
modul kernel yang tersedia dan dipilih, sehingga modul yang tersisa untuk tahap
init kedua.
Untuk init tahap kedua, sebaiknya jalankan pemuatan modul sebagai layanan sehingga tidak memblokir alur booting. Gunakan skrip shell untuk mengelola pemuatan modul sehingga logistik lainnya, seperti penanganan dan mitigasi error, atau penyelesaian pemuatan modul, dapat dilaporkan kembali (atau diabaikan) jika diperlukan.
Anda dapat mengabaikan kegagalan pemuatan modul debug yang tidak ada di build pengguna.
Untuk mengabaikan kegagalan ini, tetapkan properti vendor.device.modules.ready
untuk
memicu bootflow skrip init rc
tahap selanjutnya untuk 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 kedua. Anda dapat menggunakan fitur daftar blokir modprobe untuk memisahkan alur booting tahap kedua guna menyertakan pemuatan modul yang ditangguhkan dari modul yang tidak penting. Pemuatan modul yang digunakan secara eksklusif oleh HAL tertentu dapat ditangguhkan untuk memuat modul hanya saat HAL dimulai.
Untuk meningkatkan waktu booting yang terlihat, Anda dapat memilih modul secara khusus di
layanan pemuatan modul yang lebih kondusif untuk pemuatan setelah layar
peluncuran. Misalnya, Anda dapat memuat modul secara eksplisit untuk
decoder video atau Wi-Fi setelah alur booting init dihapus
(misalnya, sinyal properti Android sys.boot_complete
). Pastikan HAL untuk modul pemuatan
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
yang dipilih guna menunjukkan bahwa modul driver
telah menyelesaikan operasi pemeriksaan. Contohnya adalah menunggu
driver tampilan menyelesaikan pemuatan di latar belakang pemulihan atau fastbootd
,
sebelum menampilkan grafik menu.
Menginisialisasi frekuensi CPU ke nilai yang wajar di bootloader
Tidak semua SoC/produk mungkin dapat mem-booting CPU pada frekuensi tertinggi karena masalah termal atau daya selama pengujian loop booting. Namun, pastikan bootloader menetapkan frekuensi semua CPU online ke setinggi mungkin untuk SoC atau produk. Hal ini sangat penting karena, dengan kernel modular sepenuhnya, dekompresi ramdisk init terjadi sebelum driver CPUfreq dapat dimuat. Jadi, jika CPU dibiarkan di bagian bawah frekuensinya oleh bootloader, waktu dekompresi ramdisk dapat memerlukan waktu lebih lama daripada kernel yang dikompilasi secara statis (setelah menyesuaikan perbedaan ukuran ramdisk) karena frekuensi CPU akan sangat rendah saat melakukan pekerjaan intensif CPU (dekompresi). Hal yang sama berlaku untuk memori dan frekuensi interkoneksi.
Menginisialisasi frekuensi CPU CPU berukuran besar di bootloader
Sebelum driver CPUfreq
dimuat, kernel tidak mengetahui
frekuensi CPU dan tidak menskalakan kapasitas penjadwalan CPU untuk frekuensi
saat ini. Kernel mungkin memigrasikan thread ke CPU besar jika bebannya
cukup tinggi pada CPU kecil.
Pastikan CPU besar setidaknya memiliki performa yang sama dengan CPU kecil untuk frekuensi yang digunakan bootloader. Misalnya, jika CPU besar memiliki performa 2x lebih baik daripada CPU kecil untuk frekuensi yang sama, tetapi bootloader menetapkan frekuensi CPU kecil ke 1,5 GHz dan frekuensi CPU besar ke 300 MHz, performa booting akan menurun jika kernel memindahkan thread ke CPU besar. Dalam contoh ini, jika aman untuk mem-booting CPU besar pada 750 MHz, Anda harus melakukannya meskipun tidak berencana menggunakannya secara eksplisit.
Driver tidak boleh memuat firmware dalam inisialisasi tahap pertama
Mungkin ada beberapa kasus yang tidak dapat dihindari ketika firmware perlu dimuat dalam init tahap pertama. Namun secara umum, driver tidak boleh memuat firmware apa pun pada tahap pertama ini, terutama dalam konteks pemeriksaan perangkat. Memuat firmware di init tahap pertama menyebabkan seluruh proses booting terhenti jika firmware tidak tersedia di ramdisk tahap pertama. Dan meskipun firmware ada di tahap pertama ramdisk, firmware tersebut masih menyebabkan penundaan yang tidak perlu.