Açılış süresi optimizasyonu

Bu sayfada, başlatma süresini iyileştirmeye yönelik ipuçları verilmektedir.

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 sembollerinin modüllerden kaldırılması, aşağıdakileri azaltarak başlatma süresini kısaltır:

  • İkili dosyaların flash'tan okunması için geçen süre.
  • Ramdisk'in sıkıştırmasının açılması için gereken süre.
  • Modüllerin yüklenmesi için gereken süre.

Hata ayıklama simgesinin modüllerden kaldırılması, önyükleme sırasında birkaç saniye kazandırabilir.

Sembol kaldırma, Android platform derlemesinde varsayılan olarak etkindir ancak bunları açıkça etkinleştirmek için cihazınıza özel yapılandırmanızda 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ırmasını kullanma

Gzip, LZ4'e kıyasla daha küçük bir sıkıştırılmış çıktı oluşturur ancak LZ4, Gzip'ten daha hızlı açılır. Çekirdek ve modüller için Gzip kullanıldığında elde edilen mutlak depolama alanı boyutu azalması, LZ4'ün sıkıştırmayı açma süresi avantajına kıyasla o kadar da önemli değildir.

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

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

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

ARM64 ve ARM32'de, çağrı sitesinden belirli bir mesafeden daha uzak olan işlev çağrıları, tam atlama adresini kodlayabilmek için bir atlama tablosu (prosedür bağlama tablosu veya PLT olarak adlandırılır) gerektirir. Modüller dinamik olarak yüklendiğinden bu atlama tablolarının modül yükleme sırasında düzeltilmesi gerekir. Yeniden konumlandırılması gereken çağrılara, ELF biçiminde açık eklenenli yeniden konumlandırma girişleri (veya kısaca RELA) adı verilir.

Linux çekirdeği, PLT'yi ayırırken bellek boyutu optimizasyonu (ör. önbellek isabeti optimizasyonu) yapar. Bu yukarı akışlı commit ile optimizasyon şeması O(N^2) karmaşıklığına sahiptir. Burada N, R_AARCH64_JUMP26 veya R_AARCH64_CALL26 türündeki RLA'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'ların sayısını artıran yaygın bir kodlama kalıbı, sürücüdeki aşırı günlük kaydıdı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. commit text in the upstream commit (yukarı akış commit'indeki commit metni) bölümünde, optimizasyon yapılmasına rağmen altı modülün yüklenmesinin yaklaşık 250 ms sürdüğünü görürsünüz. Bunun nedeni, bu altı modülün en fazla günlük kaydı içeren ilk altı modül olmasıdır.

Günlük kaydını azaltmak, mevcut günlük kaydının ne kadar fazla olduğuna bağlı olarak başlatma sürelerinde yaklaşık 100-300 ms tasarruf sağlayabilir.

Eşzamansız yoklamayı seçici olarak etkinleştirme

Bir modül yüklendiğinde, desteklediği cihaz zaten DT'den (devicetree) doldurulmuş ve sürücü çekirdeğine eklenmişse cihaz yoklama işlemi 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ün yüklenmesi tamamlanamaz. Modül yükleme işlemi çoğunlukla seri olarak yapıldığından, yoklama işlemi nispeten uzun süren bir cihaz, başlatma süresini yavaşlatır.

Daha yavaş başlatma sürelerini önlemek için cihazlarını yoklaması biraz zaman alan modüller için eşzamansız yoklamayı etkinleştirin. Tüm modüller için eşzamansız yoklamanın etkinleştirilmesi, bir iş parçacığını çatallayıp yoklamayı başlatmak için gereken süre cihazı yoklamak için gereken süre kadar uzun olabileceğinden faydalı olmayabilir.

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

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

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

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

CPUfreq sürücünüz ne kadar erken yoklama yaparsa önyükleme sırasında CPU frekansını en yüksek değere (veya termal olarak sınırlı bir maksimum değere) o kadar erken ölçeklendirebilirsiniz. CPU ne kadar hızlıysa başlatma da o kadar hızlı olur. Bu yönerge, devfreqDRAM, bellek ve ara bağlantı frekansını kontrol eden 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. MODULE_SOFTDEP() sürücüsünün yüklenen ilk birkaç modül arasında olmasını sağlamak için cpufreq diğer adını kullanın.

Modülü erken yüklemenin yanı sıra, CPUfreq sürücüsünü yoklamak için gereken tüm bağımlılıkların da yoklandığından emin olmanız gerekir. Örneğin, CPU'nuzun frekansını kontrol etmek için bir saat veya regülatör kolu gerekiyorsa bunların önce araştırıldığından emin olun. Ayrıca, işlemcilerinizin başlatma sırasında aşırı ısınması mümkünse CPUfreq sürücüsünden önce termal sürücülerin yüklenmesi gerekebilir. Bu nedenle, CPUfreq ve ilgili devfreq sürücülerinin mümkün olduğunca erken araştırma yapmasını sağlamak için elinizden geleni yapın.

CPUfreq sürücünüzü erken yoklamanın sağlayacağı tasarruf, bunları ne kadar erken yoklayabileceğinize 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 başlatma, tedarikçi veya tedarikçi_dlkm bölümüne taşıma

İlk aşamadaki başlatma süreci sıralı olduğundan başlatma sürecini paralelleştirmek için çok fazla fırsat yoktur. Bir modülün ilk aşama başlatma işleminin tamamlanması için gerekmiyorsa modülü tedarikçi veya vendor_dlkm bölümüne yerleştirerek ikinci aşama başlatma işlemine taşıyın.

İlk aşama başlatma, ikinci aşama başlatmaya ulaşmak için birden fazla cihazın incelenmesini gerektirmez. Normal bir başlatma akışı için yalnızca konsol ve flash depolama özellikleri gerekir.

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, daha fazla cihazın (ör. USB) ve ekranın yoklanmasını gerektirir. Bu modüllerin bir kopyasını ilk aşama ramdisk'te ve vendor veya vendor_dlkm bölümünde saklayın. Bu sayede, kurtarma veya fastbootd başlatma akışı için ilk aşamada başlatılabilirler. Ancak normal başlatma akışı sırasında ilk aşama başlatma işleminde kurtarma modu modüllerini yüklemeyin. Kurtarma modu modülleri, başlatma süresini kısaltmak için ikinci aşama başlatmaya ertelenebilir. İlk aşamada başlatma için gerekli olmayan diğer tüm modüller, tedarikçi veya vendor_dlkm bölümüne taşınmalıdır.

Yaprak cihazların listesi (ör. UFS veya seri) verildiğinde, dev needs.sh komut dosyası, bağımlılıklar veya tedarikçiler (ör. saatler, regülatörler veya gpio) için gereken tüm sürücüleri, cihazları ve modülleri bulur.

Modüllerin ikinci aşama başlatmaya taşınması, aşağıdaki şekillerde başlatma sürelerini kısaltır:

  • Ramdisk boyutu küçültüldü.
    • Bu, önyükleyici ramdisk'i yüklediğinde (serileştirilmiş önyükleme adımı) daha hızlı flash okumaları sağlar.
    • Bu, çekirdek ramdisk'i (serileştirilmiş önyükleme adımı) açarken daha hızlı açma hızları sağlar.
  • İkinci aşama başlatma işlemi paralel olarak çalışır. Bu sayede, ikinci aşama başlatma işleminde yapılan çalışmayla modülün yükleme süresi gizlenir.

Modülleri ikinci aşamaya taşıdığınızda, ikinci aşama başlatmaya kaç modül taşıyabildiğinize bağlı olarak 500-1000 ms arasında başlatma süresi tasarrufu sağlayabilirsiniz.

Modül yükleme lojistiği

En yeni Android derlemesinde, hangi modüllerin her aşamaya 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ümeye odaklanılmaktadır:

  • BOARD_VENDOR_RAMDISK_KERNEL_MODULES. Bu, ramdisk'e kopyalanacak modüllerin listesidir.
  • BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD. Bu, ilk aşama başlatma sırasında yüklenecek modüllerin listesidir.
  • BOARD_VENDOR_RAMDISK_RECOVERY_KERNEL_MODULES_LOAD. Bu, ramdisk'ten kurtarma veya fastbootd seçildiğinde yüklenecek modüllerin listesidir.
  • BOARD_VENDOR_KERNEL_MODULES. Bu modüllerin listesi, /vendor/lib/modules/ dizinindeki vendor_dlkm bölümüne kopyalanır.
  • BOARD_VENDOR_KERNEL_MODULES_LOAD. Bu, ikinci aşama başlatma sırasında yüklenecek modüllerin listesidir.

Ramdisk'teki başlatma ve kurtarma modülleri de /vendor/lib/modules bölümündeki vendor veya vendor_dlkm bölümüne kopyalanmalıdır. Bu modüllerin satıcı bölümüne kopyalanması, modüllerin ikinci aşama başlatma sırasında görünmez olmamasını sağlar. Bu, hata ayıklama ve hata raporları için modinfo toplama açısından faydalıdır.

Yineleme, önyükleme modülü grubu en aza indirildiği sürece satıcıda veya vendor_dlkmbölümünde minimum alan kaplamalıdır. Tedarikçinin modules.list dosyasında, /vendor/lib/modules içinde filtrelenmiş bir modül listesi olduğundan emin olun. Filtrelenmiş liste, başlatma sürelerinin modüllerin tekrar yüklenmesinden (pahalı bir işlem) etkilenmemesini sağlar.

Kurtarma modu modüllerinin grup olarak yüklendiğinden emin olun. Kurtarma modu modüllerinin yüklenmesi, kurtarma modunda veya her başlatma akışında ikinci aşama başlatma işleminin başında yapılabilir.

Aşağıdaki örnekte gösterildiği gibi bu işlemleri gerçekleştirmek 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 BOOT_KERNEL_MODULES ve RECOVERY_KERNEL_MODULES öğelerinin yönetimi daha kolay olan bir alt kümesi gösterilmektedir. Yukarıdaki komut dosyası, seçilen kullanılabilir çekirdek modüllerinden her bir alt küme modülünü bulup doldurur ve kalan modülleri ikinci aşama başlatma için bırakır.

İkinci aşama başlatma için modül yüklemeyi hizmet olarak çalıştırmanızı öneririz. Böylece, başlatma akışı engellenmez. 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şleminin tamamlanması gibi diğer lojistikler gerekirse bildirilebilir (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 ayarlayın. Bu, init rc komut dosyası başlatma akışının sonraki aşamalarını tetikleyerek başlatma ekranına geçilmesini sağlar. Aşağıdaki koda sahipseniz /vendor/etc/init.insmod.sh aşağıdaki örnek komut dosyasını inceleyin:

#!/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 şu şekilde 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 geçtikten sonra ek optimizasyonlar yapılabilir. İkinci aşama başlatma akışını, gerekli olmayan modüllerin ertelenmiş modül yüklemesini içerecek şekilde bölmek için modprobe engelleme listesi özelliğini kullanabilirsiniz. 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ünür önyükleme sürelerini iyileştirmek için özellikle başlatma ekranından sonra yüklemeye daha uygun olan modül yükleme hizmetindeki modülleri seçebilirsiniz. Örneğin, başlatma önyükleme akışı temizlendikten sonra (sys.boot_complete örneğin Android mülk sinyali) video kod çözücü veya kablosuz modüllerini açıkça geç yükleyebilirsiniz. Geç yüklenen modüllerin HAL'lerinin, çekirdek sürücüleri mevcut olmadığında yeterince uzun süre engellediğinden emin olun.

Alternatif olarak, sürücü modüllerinin yoklama işlemlerini tamamladığını göstermek için belirli sysfs girişlerinin görünmesini beklemek üzere başlatma akışı rc komut dosyalarında init'in wait<file>[<timeout>] komutunu kullanabilirsiniz. Buna örnek olarak, menü grafiklerini göstermeden önce kurtarma işleminin arka planında ekran sürücüsünün yüklenmesinin tamamlanmasını bekleme veya fastbootd verilebilir.

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

Önyükleme döngüsü testleri sırasında termal veya güç sorunları nedeniyle tüm SoC'ler/ürünler CPU'yu en yüksek frekansta başlatamayabilir. Ancak önyükleyicinin, SoC veya ürün için güvenli bir şekilde mümkün olduğunca yüksek bir frekans belirlediğinden emin olun. Tamamen modüler bir çekirdekte init ramdisk sıkıştırması, CPUfreq sürücüsü yüklenebilmeden önce gerçekleştiği için bu çok önemlidir. Bu nedenle, önyükleyici tarafından frekansının alt ucunda bırakılan işlemcinin ramdisk sıkıştırmasını açma süresi, statik olarak derlenmiş bir çekirdeğe göre (ramdisk boyutu farkı ayarlandıktan sonra) daha uzun sürebilir. Bunun nedeni, işlemci yoğun işler (sıkıştırmayı açma) yapılırken işlemci frekansının çok düşük olmasıdır. 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ının farkında değildir ve CPU planlama kapasitesini mevcut frekanslarına göre ölçeklendirmez. Yük, küçük CPU'da yeterince yüksekse çekirdek, iş parçacıklarını büyük CPU'ya taşıyabilir.

Büyük CPU'ların, önyükleyici tarafından bırakıldıkları frekansta 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 iyi performans gösteriyorsa ancak önyükleyici küçük CPU'nun frekansını 1, 5 GHz, büyük CPU'nun frekansını ise 300 MHz olarak ayarlıyorsa çekirdek bir iş parçacığını büyük CPU'ya taşıdığında başlatma performansı düşer. Bu örnekte, büyük CPU'yu 750 MHz'de başlatmak güvenliyse açıkça kullanmayı planlamasanız bile bunu yapmanız gerekir.

Sürücüler, ilk aşama başlatma sırasında donanım yazılımı yüklememelidir.

Donanım yazılımının ilk aşama başlatma sırasında yüklenmesi gereken bazı kaçınılmaz durumlar olabilir. Ancak genel olarak sürücüler, özellikle cihaz yoklama bağlamında ilk aşama başlatma sırasında herhangi bir donanım yazılımı yüklememelidir. İlk aşama başlatma sırasında donanım yazılımının yüklenmesi, donanım yazılımı ilk aşama ramdisk'inde mevcut değilse tüm başlatma sürecinin durmasına neden olur. Donanım yazılımı ilk aşama ramdisk'te bulunsa bile gereksiz bir gecikmeye neden olur.