Başlatma süresi optimizasyonu

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

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. Modüllerden hata ayıklama simgeleri çıkarıldığında aşağıdakileri azaltarak başlatma süresine yardımcı olur:

  • İkili dosyaları flash'tan okumak için geçen süre.
  • Ramdiskteki baskıyı açmak için gereken süre.
  • Modüllerin yüklenmesi için gereken 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 kullanılmasından kaynaklanan mutlak depolama boyutu küçültme, LZ4'ün sıkıştırılmış açma süresinin avantajıyla karşılaştırıldığında ç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 özel 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üklemesi sırasında düzeltilmesi gerekir. Yerlerinin değiştirilmesi gereken çağrılar, ELF biçiminde açık eklemeli (veya kısaca RELA) yer değiştirme girişleri olarak adlandırılır.

Linux çekirdeği, PLT'yi ayırırken bazı bellek boyutu optimizasyonları (ör. önbellek isabeti optimizasyonu) yapar. Bu yukarı akış taahhüdü ile optimizasyon şeması O(N^2) karmaşıklık düzeyine sahiptir. 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ürelerini önlemek 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şlevlerinde 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üleri 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ü erkenden yüklemenin yanı sıra CPUfreq sürücüsünün kontrolü için tüm bağımlılıkların da denetlendiğ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 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şamanın başlatılması için bir modülün tamamlanması gerekmiyorsa modülü tedarikçi veya vendor_dlkm bölümüne yerleştirerek ikinci aşamanın ilk aşamasına taşıyın.

İlk aşama başlatma işlemi, ikinci aşamanın başlatılması için birkaç cihazın incelenmesini 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şama başlatma işlemi için daha fazla cihaz (USB gibi) ve ekran gerekir. Bu modüllerin bir kopyasını ilk aşama RAM'inde ve tedarikçi firma veya vendor_dlkm bölümünde tutun. Bu sayede, kurtarma veya fastbootd önyükleme akışı için ilk aşamada başlatılabilirler. Ancak kurtarma modu modüllerini normal önyükleme akışı sırasında ilk aşamadaki ilk aşamada yüklemeyin. Kurtarma modu modülleri, başlatma süresini kısaltmak için ikinci aşamaya ertelenebilir. İlk aşamada ihtiyaç duyulmayan diğer tüm modüller, tedarikçi firmaya veya vendor_dlkm bölümüne taşınmalıdır.

Yaprak cihazların (ör. UFS veya seri) listesi verildiğinde dev needs.sh dev needs.sh komut dosyası, 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 yeni Android derlemesinde, her bir aşamaya hangi modüllerin kopyalanacağını ve hangi modüllerin yükleneceğini kontrol eden kart yapılandırmaları bulunur. 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, ikinci aşamada yüklenecek modüllerin listesidir.

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 listesinin 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üklenmesini sağlayın. 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 mevcut çekirdek modüllerinden alt kümelerin her birini bulup doldurur. Kalan modüllerin hepsi ikinci aşamada başlatılı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. Modül yüklemeyi yönetmek için bir kabuk komut dosyası kullanın. Böylece, hata işleme ve azaltma veya modül yükleme işlemini tamamlama gibi diğer lojistikler, gerekirse tekrar raporlanabilir (veya yoksayılabilir).

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, init rc komut dosyası önyükleme akışının sonraki aşamalarını tetikleyerek başlatma ekranına devam edecek ş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, başlatma başlatma akışı temizlendikten sonra video kod çözücü veya kablosuz ağ modüllerini açıkça geç yükleyebilirsiniz (ör. sys.boot_complete Android özelliği sinyali). Çekirdek sürücüleri mevcut olmadığında geç yükleme modüllerinin HAL'lerinin 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 sunmadan önce ekran sürücüsünün kurtarma işleminin arka planında ya da fastbootd'nin arka planında yükleme işlemini tamamlamasını beklemek gösterilebilir.

CPU frekansını bootloader'da makul bir değere başlatın

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, çevrimiçi tüm 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ü yüklenmeden ö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.