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 debug simbol 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 diatur melalui {i>kernel defconfig<i}.
Beralih ke LZ4 akan memberikan waktu booting yang lebih cepat 500 md hingga 1.000 md.
Hindari logging berlebihan di driver Anda
Di ARM64 dan ARM32, panggilan fungsi yang lebih dari jarak tertentu dari situs panggilan memerlukan tabel lompatan (disebut tabel penautan prosedur, atau PLT) agar dapat mengenkode alamat lompatan penuh. 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 cache ditemukan
pengoptimalan) 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
jenis ini sangat membantu dalam mengurangi waktu muat 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
CALL26
/JUMP26
Entri RELA. 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 logging 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()
. Ketika pemeriksaan perangkat
dilakukan dalam konteks module_init()
, modul tidak dapat menyelesaikan pemuatan sampai
probe selesai. Karena pemuatan modul sebagian besar diserialisasi, perangkat yang
memerlukan waktu relatif lama untuk melakukan pemeriksaan akan memperlambat waktu booting.
Untuk menghindari waktu booting yang lebih lambat, aktifkan pemindaian asinkron untuk modul yang memerlukan waktu untuk memindai perangkatnya. Mengaktifkan pemindaian asinkron untuk semua modul mungkin tidak bermanfaat karena waktu yang diperlukan untuk membuat fork thread dan memulai pemindaian mungkin sama tingginya dengan waktu yang diperlukan untuk memindai 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 yang terjadi adalah mengumpulkan waktu penyelidikan untuk setiap pengemudi dan mengurutkannya.
Untuk mengaktifkan pemeriksaan asinkron untuk suatu modul, pemeriksaan tidak cukup untuk hanya
setel PROBE_PREFER_ASYNCHRONOUS
di kode {i>driver<i}. Untuk modul, Anda juga perlu menambahkan
module_name.async_probe=1
di command line kernel
atau teruskan 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 pemeriksaan driver CPUfreq, semakin cepat Anda dapat menskalakan CPU
ke maksimum (atau beberapa maksimum yang dibatasi secara termal) selama booting. Tujuan
semakin cepat CPU, semakin cepat waktu {i>booting<i}. Panduan ini juga berlaku untuk driver
devfreq
yang mengontrol DRAM, memori, dan frekuensi interkoneksi.
Dengan modul, pengurutan pemuatan dapat bergantung pada level initcall
dan
kompilasi atau tautan
dari {i>driver<i}. Gunakan alias MODULE_SOFTDEP()
untuk membuat
pastikan driver cpufreq
ada di antara beberapa modul pertama yang dimuat.
Selain memuat modul lebih awal, Anda juga perlu memastikan semua dependensi untuk menyelidiki driver CPUfreq juga telah diselidiki. Misalnya, jika Anda memerlukan handle regulator atau clock untuk mengontrol frekuensi CPU, pastikan handle tersebut diuji terlebih dahulu. Atau Anda mungkin memerlukan {i>driver<i} termal untuk dimuat sebelum {i>driver<i} CPUfreq jika mungkin CPU Anda terlalu panas selama {i>booting<i}. 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 untuk
langkah pertama hingga selesai, pindahkan modul ke init tahap kedua dengan menempatkannya
di vendor atau partisi 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 vendor atau partisi vendor_dlkm
. Hal ini memungkinkan mereka
dimuat dalam init 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 atau vendor_dlkm
.
Dengan mencantumkan daftar perangkat leaf (misalnya, UFS atau serial),
dev needs.sh
{i>script <i}menemukan semua {i>driver<i}, perangkat, dan modul
yang dibutuhkan untuk dependensi atau
penyedia (misalnya, jam, regulator, atau gpio
) untuk diselidiki.
Memindahkan modul ke init tahap kedua mengurangi waktu booting di cara:
- Pengurangan ukuran ramdisk.
- Proses ini menghasilkan pembacaan {i>flash<i} yang lebih cepat ketika {i>bootloader<i} memuat ramdisk (langkah booting serial).
- Hal ini menghasilkan kecepatan dekompresi yang lebih cepat ketika {i>kernel<i} melakukan dekompresi {i>ramdisk<i} (langkah {i>booting<i} yang diserialisasi).
- Init tahap kedua berfungsi secara paralel, yang menyembunyikan waktu pemuatan modul dengan pekerjaan 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.
Modul memuat logistik
Versi terbaru Android memiliki fitur konfigurasi board yang mengontrol modul akan 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 yang akan dimuat pada init tahap pertama.BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD
. Daftar modul ini untuk 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 yang akan dimuat {i>init<i} tahap kedua.
Modul {i>boot<i} dan pemulihan dalam {i>ramdisk<i} juga
harus disalin ke vendor atau
Partisi vendor_dlkm
pada /vendor/lib/modules
. Menyalin modul ini ke
partisi vendor memastikan modul tidak terlihat
selama init tahap kedua,
yang berguna untuk men-debug dan mengumpulkan modinfo
untuk laporan bug.
Duplikasi harus menghabiskan ruang minimal di partisi vendor atau vendor_dlkm
selama set modul booting diminimalkan. Pastikan bahwa
File modules.list
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 grup. Memuat modul mode pemulihan dapat dilakukan dalam mode pemulihan, atau di awal tahap kedua init di 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 cara yang lebih mudah dikelola
RECOVERY_KERNEL_MODULES
akan ditentukan secara lokal dalam konfigurasi board
. Skrip sebelumnya menemukan dan mengisi setiap modul subset dari
modul {i>kernel<i} yang tersedia, menyisakan modul
yang tersedia untuk kedua kalinya
init tahap.
Untuk init tahap kedua, sebaiknya jalankan pemuatan modul sebagai layanan agar 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 tahap selanjutnya dari alur booting 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 dari modul yang tidak penting. Pemuatan modul yang digunakan secara eksklusif oleh HAL tertentu dapat ditangguhkan untuk memuat modul hanya ketika HAL dimulai.
Untuk meningkatkan waktu {i>booting<i}, Anda dapat memilih modul secara khusus di
layanan pemuatan modul yang lebih kondusif untuk dimuat setelah peluncuran
layar. Misalnya, Anda dapat memuat modul secara eksplisit untuk
decoder video atau Wi-Fi setelah alur booting init dihapus
(sys.boot_complete
sinyal properti Android, misalnya). 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
tertentu untuk menunjukkan bahwa modul driver
telah menyelesaikan operasi probe. Contohnya adalah menunggu
driver tampilan menyelesaikan pemuatan di latar belakang pemulihan atau fastbootd
,
sebelum menampilkan grafik menu.
Melakukan inisialisasi frekuensi CPU ke nilai yang wajar di bootloader
Tidak semua SoC/produk dapat mem-booting CPU dengan frekuensi tertinggi karena masalah termal atau daya selama pengujian {i>boot loop<i}. Namun, pastikan bootloader menetapkan frekuensi semua CPU online setinggi mungkin untuk SoC atau produk. Hal ini sangat penting karena, dengan kernel yang sepenuhnya modular, 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 frekuensi memori dan 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 dapat memigrasikan thread ke CPU besar jika beban
cukup tinggi di CPU kecil.
Pastikan kinerja CPU besar setidaknya sama dengan kinerja CPU kecil untuk frekuensi di mana {i>bootloader<i} meninggalkannya. Misalnya, jika CPU besar 2x berperforma lebih baik dibandingkan CPU kecil untuk frekuensi yang sama, tetapi {i>bootloader<i} mengatur frekuensi CPU kecil menjadi 1,5 GHz dan CPU 300 MHz, maka kinerja {i>booting<i} akan menurun jika {i>kernel<i} 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 saat firmware perlu dimuat dalam init tahap pertama. Namun secara umum, {i>driver<i} seharusnya tidak memuat {i>firmware<i} apa pun pada tahap pertama init, 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.