Açılış süresi optimizasyonu

Bu sayfada, önyükleme süresini iyileştirmeye yönelik ipuçları sunulmaktadır.

Modüllerden hata ayıklama sembollerini kaldırma

Hata ayıklama sembollerinin üretim cihazındaki çekirdekten kaldırılmasına benzer şekilde, hata ayıklama sembollerini modüllerden de kaldırdığınızdan emin olun. Hata ayıklama simgelerinin modüllerden çıkarılması, aşağıdakileri azaltarak önyükleme süresini kısaltır:

  • Flash'tan ikili dosyaları okumak için geçen süre.
  • Ramdisk'in sıkıştırmasını çözmek için geçen süre.
  • Modüllerin yüklenmesi için geçen süre.

Modüllerden hata ayıklama sembolünün kaldırılması, açılış sırasında birkaç saniye tasarruf sağlayabilir.

Simge ayıklama, Android platform derlemesinde varsayılan olarak etkindir ancak açıkça etkinleştirmek için cihaza özgü yapılandırmanızdaki device/vendor/device altında BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES değerini ayarlayın.

Çekirdek ve ramdisk için LZ4 sıkıştırma kullanın

Gzip, LZ4'e kıyasla daha küçük bir sıkıştırılmış çıkış oluşturur ancak LZ4, Gzip'e kıyasla daha hızlı sıkıştırma açar. Çekirdek ve modüller için Gzip'in sağladığı mutlak depolama alanı boyutu azaltımı, LZ4'ün sunduğu sıkıştırma süresi avantajına kıyasla çok önemli değildir.

BOARD_RAMDISK_USE_LZ4 üzerinden Android platform derlemesine LZ4 ramdisk sıkıştırma desteği eklendi. Bu seçeneği cihaza özgü yapılandırmanızda ayarlayabilirsiniz. Çekirdek sıkıştırması, çekirdek defconfig aracılığıyla ayarlanabilir.

LZ4'e geçiş, 500 ila 1.000 ms daha hızlı başlatma süresi sağlar.

Sürücülerinizde aşırı günlük kaydı kullanmaktan kaçının

ARM64 ve ARM32'de, çağrı sitesinden belirli bir mesafeden daha uzaktaki işlev çağrılarının tam atlama adresini kodlayabilmesi için bir atlama tablosuna (prosedür bağlama tablosu veya PLT olarak adlandırılır) ihtiyacı vardır. Modüller dinamik olarak yüklendiğinden bu atlama tablolarının modül yükleme sırasında düzeltilmesi gerekir. Taşıma gerektiren çağrılara, ELF biçiminde açık eklemeli (veya kısaca RELA) taşıma girişleri denir.

Linux çekirdeği, PLT'yi ayırırken bazı bellek boyutu optimizasyonları (ör. önbellek isabeti optimizasyonu) yapar. Bu yukarı akış commit'iyle, optimizasyon şemasının karmaşıklığı O(N^2) olur. Burada N, R_AARCH64_JUMP26 veya R_AARCH64_CALL26 türündeki RELA'ların sayısıdır. Bu nedenle, bu türden daha az RELA'ya sahip olmak modül yükleme süresini azaltmaya yardımcı olur.

R_AARCH64_CALL26 veya R_AARCH64_JUMP26 RELA sayısını artıran yaygın bir kodlama kalıbı, sürücüde aşırı günlük kaydı oluşturmaktır. printk() veya başka bir günlük kaydı şemasına yapılan her çağrı genellikle bir CALL26/JUMP26 RELA girişi ekler. Yukarı akıştaki commit metninde, optimizasyona rağmen altı modülün yüklenmesi için yaklaşık 250 ms gerektiğini fark edin. Bunun nedeni, bu altı modülün en fazla günlük kaydı içeren ilk altı modül olmasıdır.

Günlüğe kaydetme işlemini azaltmak, mevcut günlük kaydetme işleminin ne kadar aşırı olduğuna bağlı olarak açılış sürelerinde yaklaşık 100-300 ms tasarruf sağlayabilir.

Eşzamansız problamayı seçerek etkinleştirme

Bir modül yüklendiğinde, desteklediği cihaz DT'den (cihaz ağacı) doldurulmuş ve sürücü çekirdeğine eklenmişse cihaz araştırması module_init() çağrısı bağlamında yapılır. module_init() bağlamında bir cihaz araştırması yapıldığında, araştırma tamamlanana kadar modül yüklenemez. Modül yükleme işlemi çoğunlukla serileştirildiğinden, tarama işleminin nispeten uzun sürdüğü cihazlar önyükleme süresini yavaşlatır.

Daha yavaş önyükleme sürelerinden kaçınmak için, cihazlarını taraması biraz zaman alan modüller için eşzamansız tarama özelliğini etkinleştirin. Bir iş parçasını ayırmak ve sondayı başlatmak için gereken süre, cihazı incelemek için gereken süre kadar uzun olabileceğinden, tüm modüller için eşzamansız problamayı etkinleştirmek yararlı olmayabilir.

I2C gibi yavaş bir veri yolu üzerinden bağlanan cihazlar, prob işlevinde donanım yazılımı yükleyen cihazlar ve çok fazla donanım başlatma işlemi yapan cihazlar zamanlama sorununa neden olabilir. Bunun ne zaman gerçekleştiğini belirlemenin en iyi yolu, her sürücü için prob süresini toplayıp sıralamaktır.

Bir modül için eşzamansız problamayı etkinleştirmek amacıyla sürücü kodunda yalnızca PROBE_PREFER_ASYNCHRONOUS işaretini ayarlamak yeterli değildir. Modüller için de çekirdek komut satırına module_name.async_probe=1 eklemeniz veya modülü modprobe ya da insmod kullanarak yüklerken async_probe=1'yi modül parametresi olarak iletmeniz gerekir.

Asenkron problamayı etkinleştirmek, donanımınıza/sürücülerinize bağlı olarak açılış sürelerinde yaklaşık 100-500 ms tasarruf sağlayabilir.

CPUfreq sürücünüzü mümkün olduğunca erken inceleyin

CPUfreq sürücünüz ne kadar erken algılarsa önyükleme sırasında CPU frekansını maksimuma (veya termal olarak sınırlanmış bir maksimuma) o kadar erken ölçeklendirebilirsiniz. CPU ne kadar hızlıysa önyükleme de o kadar hızlı olur. Bu kural, DRAM, bellek ve arabirim frekansını kontrol eden devfreq sürücüler için de geçerlidir.

Modüllerde yükleme sırası, initcall düzeyine ve sürücülerin derleme veya bağlantı sırasına bağlı olabilir. cpufreq sürücüsünün yüklenen ilk birkaç modül arasında olduğundan emin olmak için MODULE_SOFTDEP() takma adı kullanın.

Modülü erken yüklemenin yanı sıra, CPUfreq sürücüsünü incelemek için gereken tüm bağımlılıkların da incelendiğinden emin olmanız gerekir. Örneğin, CPU'nuzun frekansını kontrol etmek için bir saat veya düzenleyici koluna ihtiyacınız varsa önce bunların sorgulandığından emin olun. Ayrıca, CPU'larınızın önyükleme sırasında çok ısınması mümkünse termal sürücülerin CPUfreq sürücüsünden önce yüklenmesi gerekebilir. Bu nedenle, CPUfreq ve ilgili devfreq sürücülerinin mümkün olduğunca erken tetiklenmesini sağlamak için elinizden geleni yapın.

CPUfreq sürücünüzü erkenden sorgulayarak elde edeceğiniz tasarruf, bu sürücülerin ne kadar erken sorgulandığına ve önyükleyicinin CPU'ları hangi sıklıkta etkin bıraktığına bağlı olarak çok küçük veya çok büyük olabilir.

Modülleri ikinci aşama init, vendor veya vendor_dlkm bölümüne taşıma

İlk aşamadaki başlatma işlemi serileştirildiğinden, önyükleme işlemini paralelleştirmek için pek fazla fırsat yoktur. İlk aşamalı başlatmanın tamamlanması için bir modüle ihtiyaç yoksa modülü tedarikçi firmaya veya vendor_dlkm bölümüne yerleştirerek ikinci aşamalı başlatmaya taşıyın.

İlk aşamada başlatma, ikinci aşamada başlatmaya geçmek için birkaç cihazı incelemeyi gerektirmez. Normal bir önyükleme akışı için yalnızca konsol ve flash depolama alanı özellikleri gereklidir.

Aşağıdaki temel sürücüleri yükleyin:

  • watchdog
  • reset
  • cpufreq

Kurtarma ve kullanıcı alanı fastbootd modu için ilk aşamada, daha fazla cihazın (USB gibi) incelenmesi ve görüntülenmesi gerekir. Bu modüllerin bir kopyasını birinci aşama ramdisk'inde ve tedarikçi veya vendor_dlkm bölümünde bulundurun. Bu sayede, kurtarma veya fastbootd önyükleme akışı için ilk aşamada başlatılabilirler. Ancak normal önyükleme akışı sırasında ilk aşamada başlatma işleminde kurtarma modu modüllerini yüklemeyin. Kurtarma modu modülleri, önyükleme süresini azaltmak için ikinci aşamalı başlatma işlemine ertelenebilir. İlk aşamada başlatma işleminde ihtiyaç duyulmayan diğer tüm modüller tedarikçiye veya vendor_dlkm bölümüne taşınmalıdır.

dev needs.sh komut dosyası, bir son cihaz listesi (ör. UFS veya seri) verildiğinde, bağımlılıkların veya tedarikçilerin (ör. saatler, düzenleyiciler veya gpio) incelemesi için gereken tüm sürücüleri, cihazları ve modülleri bulur.

Modülleri ikinci aşamalı başlatmaya taşımak, önyükleme sürelerini aşağıdaki şekillerde azaltır:

  • Ramdisk boyutunu küçültme.
    • Bu sayede önyükleme programı ramdisk'i yüklerken (serileştirilmiş önyükleme adımı) daha hızlı flash okumaları elde edilir.
    • Bu sayede çekirdek, ramdisk'i (serileştirilmiş önyükleme adımı) sıkıştırdığında daha hızlı sıkıştırma hızları elde edilir.
  • İkinci aşamada başlatma işlemi paralel olarak çalışır. Bu sayede, ikinci aşamada başlatma işleminde yapılan çalışmayla modülün yükleme süresi gizlenir.

Modülleri ikinci aşamaya taşımak, ikinci aşamada başlatmaya kaç modül taşıyabildiğinize bağlı olarak açılış sürelerinde 500 ila 1.000 ms tasarruf sağlayabilir.

Modül yükleme lojistiği

En son Android derlemesi, hangi modüllerin her aşamaya kopyalanacağını ve hangi modüllerin yükleneceğini kontrol eden kart yapılandırmalarına sahiptir. Bu bölümde aşağıdaki alt küme ele alınmaktadır:

  • BOARD_VENDOR_RAMDISK_KERNEL_MODULES. Bu, ramdisk'e kopyalanacak modüllerin listesidir.
  • BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD. İlk aşamada yüklenecek modüllerin listesi.
  • BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD. Bu modül listesi, ramdisk'ten kurtarma veya fastbootd seçildiğinde yüklenir.
  • BOARD_VENDOR_KERNEL_MODULES. Bu modül listesi, /vendor/lib/modules/ dizininde tedarikçiye veya vendor_dlkm bölümüne kopyalanacaktır.
  • BOARD_VENDOR_KERNEL_MODULES_LOAD. Bu liste, ikinci aşamada başlatılacak modülleri içerir.

Ramdisk'teki önyükleme ve kurtarma modülleri de /vendor/lib/modules adresindeki tedarikçiye veya vendor_dlkm bölümüne kopyalanmalıdır. Bu modülleri tedarikçi bölümüne kopyalamak, modüllerin ikinci aşamada başlatılırken görünmez olmasını sağlar. Bu, hata ayıklama ve hata raporları için modinfo toplama işlemlerinde faydalıdır.

Önyükleme modülü grubu en aza indirildiği sürece kopyalama işlemi, tedarikçi veya vendor_dlkm bölümünde çok az yer kaplar. Tedarikçi firmanın modules.list dosyasında /vendor/lib/modules içinde filtrelenmiş bir modül listesi bulunduğundan emin olun. Filtrelenmiş liste, başlatma sürelerinin modüllerin tekrar yüklenmesinden (pahalı bir işlemdir) etkilenmemesini sağlar.

Kurtarma modu modüllerinin grup halinde yüklendiğinden emin olun. Kurtarma modu modüllerini yükleme işlemi, kurtarma modunda veya her önyükleme akışında ikinci aşama init'in başında yapılabilir.

Aşağıdaki örnekte gösterildiği gibi bu işlemleri yapmak için cihaz Board.Config.mk dosyalarını kullanabilirsiniz:

# 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)))

Bu örnekte, kart yapılandırma dosyalarında yerel olarak belirtilecek daha kolay yönetilebilir bir BOOT_KERNEL_MODULES ve RECOVERY_KERNEL_MODULES alt kümesi gösterilmektedir. Önceki komut dosyası, seçili kullanılabilir çekirdek modüllerinden alt küme modüllerinin her birini bulup doldurur ve kalan modülleri ikinci aşamada başlatma işlemine bırakır.

İkinci aşamada başlatma için, modül yüklemenin önyükleme akışını engellememesi amacıyla bir hizmet olarak çalıştırılmasını öneririz. Hata işleme ve azaltma veya modül yükleme tamamlanması gibi diğer lojistik işlemlerin gerektiğinde geri raporlanabilmesi (veya yoksayılması) için modül yüklemeyi yönetmek üzere bir kabuk komut dosyası kullanın.

Kullanıcı derlemelerinde bulunmayan bir hata ayıklama modülü yükleme hatasını yoksayabilirsiniz. Bu hatayı yoksaymak için vendor.device.modules.ready özelliğini, başlatma ekranına devam etmek için init rc komut dosyası önyükleme akışının sonraki aşamalarını tetikleyecek şekilde ayarlayın. /vendor/etc/init.insmod.sh dosyasında aşağıdaki koda sahipseniz aşağıdaki örnek komut dosyasına bakın:

#!/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

Donanım rc dosyasında one shot hizmeti şunlarla belirtilebilir:

service insmod-sh /vendor/etc/init.insmod.sh /vendor/etc/init.insmod.<hw>.cfg
    class main
    user root
    group root system
    Disabled
    oneshot

Modüller birinci aşamadan ikinci aşamaya taşındıktan sonra ek optimizasyonlar yapılabilir. Modprobe engellenenler listesi özelliğini kullanarak ikinci aşama önyükleme akışını, gerekli olmayan modüllerin ertelenen modül yüklemesini içerecek şekilde bölebilirsiniz. Yalnızca belirli bir HAL tarafından kullanılan modüllerin yüklenmesi, modüllerin yalnızca HAL başlatıldığında yüklenmesi için ertelenebilir.

Görünen önyükleme sürelerini iyileştirmek için modül yükleme hizmetinde, başlatma ekranından sonra yüklenmeye daha uygun modülleri seçebilirsiniz. Örneğin, video kod çözücü veya kablosuz ağ modüllerini, başlatma önyükleme akışı temizlendikten sonra (ör. sys.boot_complete Android mülk sinyali) açıkça geç yükleyebilirsiniz. Geç yüklenen modüller için HAL'lerin, çekirdek sürücüleri mevcut olmadığında yeterince uzun süre engellediğinden emin olun.

Alternatif olarak, sürücü modüllerinin tarama işlemlerini tamamladığını gösteren belirli sysfs girişlerini beklemek için önyükleme akışı rc komut dosyasında init'in wait<file>[<timeout>] komutunu kullanabilirsiniz. Buna örnek olarak, menü grafiklerini göstermeden önce ekran sürücüsünün kurtarma işleminin arka planında yükleme işlemini tamamlamasını beklemek verilebilir.fastbootd

Bootloader'da CPU frekansını makul bir değere ayarlama

Bazı SoC'ler/ürünler, önyükleme döngüsü testleri sırasında termal veya güç sorunları nedeniyle CPU'yu en yüksek frekansta başlatamayabilir. Ancak önyükleyicinin, tüm çevrimiçi CPU'ların sıklığını bir SoC veya ürün için güvenli bir şekilde mümkün olduğunca yüksek ayarladığından emin olun. Bu, tamamen modüler bir çekirdekte init ramdisk sıkıştırma işleminin CPUfreq sürücüsünün yüklenmesinden önce gerçekleşmesi nedeniyle çok önemlidir. Bu nedenle, önyükleme yükleyicisi CPU'yu sıklık aralığının alt ucunda bırakırsa ramdisk sıkıştırma süresi, CPU yoğun işlem (sıkıştırma) yaparken CPU sıklık çok düşük olacağından statik olarak derlenmiş bir çekirdekten daha uzun sürebilir (ramdisk boyutu farkına göre ayarlandıktan sonra). Aynı durum bellek ve ara bağlantı sıklığı için de geçerlidir.

Bootloader'da büyük CPU'ların CPU frekansını başlatma

CPUfreq sürücüsü yüklenmeden önce çekirdek, CPU frekanslarından haberdar değildir ve CPU planlama kapasitesini mevcut frekanslarına göre ölçeklendirmez. Küçük CPU'da yük yeterince yüksekse çekirdek, iş parçacıklarını büyük CPU'ya taşıyabilir.

Büyük CPU'ların, önyükleyicinin onları bıraktığı frekansta en az küçük CPU'lar kadar performanslı olduğundan emin olun. Örneğin, büyük CPU aynı frekansta küçük CPU'dan 2 kat daha performanslıysa ancak önyükleyici küçük CPU'nun frekansını 1, 5 GHz, büyük CPU'nun frekansını 300 MHz olarak ayarlarsa çekirdek bir iş parçacığı büyük CPU'ya taşırsa önyükleme performansı düşer. Bu örnekte, büyük CPU'yu 750 MHz'te başlatmak güvenliyse açıkça kullanmayı planlamasanız bile bunu yapmanız gerekir.

Sürücüler, ilk aşamada donanım yazılımını yüklememelidir

Donanım yazılımının ilk aşamada başlatılması gereken bazı kaçınılmaz durumlar olabilir. Ancak genel olarak sürücüler, özellikle cihaz probu bağlamında ilk aşamada herhangi bir donanım yazılımı yüklememelidir. Donanım yazılımı, ilk aşama init'te yüklenirse ve donanım yazılımı ilk aşama ramdisk'te mevcut değilse tüm önyükleme işleminin duraklamasına neden olur. Donanım yazılımı ilk aşama ramdisk'te olsa bile gereksiz bir gecikmeye neden olur.