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

  • İkili dosyaların flash'tan okunması için gereken 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.

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

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 cihaz/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 kullanmanın mutlak depolama alanı boyutu açısından sağladığı azalma, 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ının tam atlama adresini kodlayabilmek 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. Yeniden konumlandırılması gereken çağrılara, ELF biçiminde açık ekler içeren yeniden konumlandırma girişleri (veya kısaca RELA) girişleri adı verilir.

Linux çekirdeği, PLT'yi ayırırken bellek boyutu optimizasyonu (ör. önbellek isabeti optimizasyonu) yapar. Bu upstream 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 DT'den (devicetree) daha önce doldurulmuş ve sürücü çekirdeğine eklenmişse cihaz yoklaması module_init() çağrısı bağlamında yapılır. module_init() bağlamında bir cihaz incelemesi yapıldığında, inceleme 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, iş parçacığı oluşturma ve yoklamayı başlatma süresi cihazı yoklama süresi 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 inceleyin

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ı olursa başlatma da o kadar hızlı olur. Bu yönerge, devfreq DRAM, 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 sıklığını kontrol etmek için bir saat veya regülatör koluna ihtiyacınız varsa bunların önce araştırıldığından emin olun. Ayrıca, CPU'larınızın 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ırıldığından emin olmak 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 vendor_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 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 yüklenebilirler. Ancak normal başlatma akışı sırasında ilk aşama başlatma işleminde kurtarma modu modüllerini yüklemeyin. Geri yükleme modu [Recovery mode] modülleri, başlatma süresini kısaltmak için ikinci aşama başlatmaya ertelenebilir. İlk aşama başlatma işleminde gerekli olmayan diğer tüm modüller, satıcı 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ülleri ikinci aşama başlatmaya taşıma, 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şıyarak, ikinci aşama başlatmaya kaç modül taşıyabildiğinize bağlı olarak 500-1000 ms önyükleme süresi kazanabilirsiniz.

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. Kurtarma veya fastbootd ramdisk'ten seçildiğinde yüklenecek modüllerin listesi.
  • BOARD_VENDOR_KERNEL_MODULES. Bu, /vendor/lib/modules/ dizinindeki vendor_dlkm bölümüne kopyalanacak modüllerin listesidir.
  • 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 konumundaki 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şlatmanın 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 lojistik işlemler gerektiğinde 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 init rc değerine ayarlayarak komut dosyası başlatma akışının sonraki aşamalarını tetikleyin ve başlatma ekranına geçin. /vendor/etc/init.insmod.sh Aşağıdaki koda sahipseniz /vendor/etc/init.insmod.sh aşağıdaki örnek komut dosyasını referans alı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 ş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 özelliği sinyali) video kod çözücü veya kablosuz için modülleri 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österen belirli sysfs girişlerinin görünmesini beklemek için 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, bir SoC veya ürün için güvenli bir şekilde mümkün olan en yüksek frekansa tüm online CPU'ların frekansını ayarladığından emin olun. Bu çok önemlidir. Çünkü tamamen modüler bir çekirdekte, init ramdisk sıkıştırması, CPUfreq sürücüsü yüklenebilmeden önce gerçekleşir. Bu nedenle, önyükleyici tarafından işlemcinin frekansı düşük seviyede bırakılırsa işlemci yoğun işler (sıkıştırmayı açma) yapılırken işlemci frekansı çok düşük olacağından, ramdisk sıkıştırmayı açma süresi statik olarak derlenmiş bir çekirdeğe göre (ramdisk boyutu farkı ayarlandıktan sonra) daha uzun sürebilir. 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ükleyicinin bunları bıraktığı 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 önyükleme performansı düşer. Bu örnekte, büyük CPU'yu 750 MHz'de başlatmak güvenliyse bunu açıkça kullanmayı planlamasanız bile 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.