Bu dokümanda, belirli Android cihazların önyükleme sürelerini iyileştirmeyle ilgili iş ortağı rehberliği sağlanmaktadır. Kullanıcıların cihazı kullanabilmek için önyüklemenin tamamlanmasını beklemesi gerektiğinden, önyükleme süresi sistem performansının önemli bir bileşenidir. Soğuk başlatmanın daha sık gerçekleştiği arabalar gibi cihazlarda hızlı bir başlatma süresi kritik öneme sahiptir (Hiç kimse sadece bir navigasyon hedefini girmek için onlarca saniye beklemeyi sevmez).
Android 8.0, çeşitli bileşenlerde çeşitli iyileştirmeleri destekleyerek önyükleme sürelerini kısaltır. Aşağıdaki tabloda bu performans iyileştirmeleri (Google Pixel ve Pixel XL cihazlarda ölçülen değerler) özetlenmiştir.
Bileşen | İyileştirme |
---|---|
Önyükleyici |
|
Cihaz çekirdeği |
|
G/Ç ayarı |
|
init.*.rc |
|
Açılış animasyonu |
|
SELinux politikası | genfscon tarafından 0,2 saniye tasarruf edildi |
Bootloader'ı optimize etme
Önyükleyiciyi daha iyi önyükleme süreleri için optimize etmek üzere:
- Günlük kaydı için:
- Çok fazla günlük kaydı olduğunda uzun sürebileceği için UART'a günlük kaydını devre dışı bırakın. (Google Pixel cihazlarda, bootloader'ı 1,5 saniye yavaşlattığı tespit edildi).
- Yalnızca hata durumlarını günlüğe kaydedin ve diğer bilgileri, ayrı bir mekanizmayla almak için bellekte saklayın.
- Çekirdek sıkıştırma için, modern donanımlarda GZIP yerine LZ4 kullanmayı düşünün (örnek yama). Farklı çekirdek sıkıştırma seçeneklerinin farklı yükleme ve sıkıştırma sürelerine sahip olabileceğini ve bazı seçeneklerin belirli donanımınız için diğerlerinden daha iyi çalışabileceğini unutmayın.
- Hata ayıklama/özel mod girişi için gereksiz bekleme sürelerini kontrol edin ve bunları en aza indirin.
- Önyükleme makinesinde harcanan önyükleme süresini cmdline olarak çekirdeğe iletin.
- Çekirdek yükleme ve G/Ç'yi başlatma için CPU saatini kontrol edin ve paralelleştirmeyi (çok çekirdekli destek gerekir) düşünün.
G/Ç verimliliğini optimize etme
Açılış süresini kısaltmak için G/Ç verimliliğini artırmak çok önemlidir.Gerekmeyen her şeyin okunması, önyükleme işleminden sonraya ertelenebilir (Google Pixel'de önyükleme sırasında yaklaşık 1,2 GB veri okunur).
Dosya sistemini ayarlama
Linux çekirdeği önceden okuma özelliği, bir dosya baştan okunduğunda veya bloklar sırayla okunduğunda devreye girer. Bu da I/O planlayıcı parametrelerinin özellikle önyükleme için (normal uygulamalardan farklı bir iş yükü karakterizasyonuna sahiptir) ayarlanmasını zorunlu kılar.
Sorunsuz (A/B) güncellemeleri destekleyen cihazlar, ilk kez başlatıldığında dosya sistemi ayarlarından (ör. Google Pixel'de 20 saniye) büyük ölçüde yararlanır. Örneğin, Google Pixel için aşağıdaki parametreleri ayarladık:
on late-fs # boot time fs tune # boot time fs tune write /sys/block/sda/queue/iostats 0 write /sys/block/sda/queue/scheduler cfq write /sys/block/sda/queue/iosched/slice_idle 0 write /sys/block/sda/queue/read_ahead_kb 2048 write /sys/block/sda/queue/nr_requests 256 write /sys/block/dm-0/queue/read_ahead_kb 2048 write /sys/block/dm-1/queue/read_ahead_kb 2048 on property:sys.boot_completed=1 # end boot time fs tune write /sys/block/sda/queue/read_ahead_kb 512 ...
Çeşitli
- DM_VERITY_HASH_PREFETCH_MIN_SIZE çekirdek yapılandırmasını kullanarak dm-verity karma ön getirme boyutunu etkinleştirin (varsayılan boyut 128'dir).
- Daha iyi dosya sistemi kararlılığı ve her önyüklemede gerçekleşen zorunlu kontrolün kaldırılması için BoardConfig.mk dosyasında TARGET_USES_MKE2FS ayarını yaparak yeni ext4 oluşturma aracını kullanın.
G/Ç'yi analiz etme
Açılış sırasındaki G/Ç etkinliklerini anlamak için çekirdek ftrace verilerini (systrace tarafından da kullanılır) kullanın:
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Her dosyanın dosya erişimini ayrıntılı olarak incelemek için çekirdekte aşağıdaki değişiklikleri yapın (yalnızca geliştirme çekirdeği; üretim çekirdeklerinde kullanmayın):
diff --git a/fs/open.c b/fs/open.c index 1651f35..a808093 100644 --- a/fs/open.c +++ b/fs/open.c @@ -981,6 +981,25 @@ } EXPORT_SYMBOL(file_open_root); +static void _trace_do_sys_open(struct file *filp, int flags, int mode, long fd) +{ + char *buf; + char *fname; + + buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!buf) + return; + fname = d_path(&filp-<f_path, buf, PAGE_SIZE); + + if (IS_ERR(fname)) + goto out; + + trace_printk("%s: open(\"%s\", %d, %d) fd = %ld, inode = %ld\n", + current-<comm, fname, flags, mode, fd, filp-<f_inode-<i_ino); +out: + kfree(buf); +} + long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) { struct open_flags op; @@ -1003,6 +1022,7 @@ } else { fsnotify_open(f); fd_install(fd, f); + _trace_do_sys_open(f, flags, mode, fd);
Açılış performansını analiz etmenize yardımcı olması için aşağıdaki komut dosyalarını kullanın.
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Başlatma işlemindeki önemli adımların dökümünü içeren bir başlangıç süresi ölçümü yapar.system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Her dosya için erişim bilgilerini sağlar.system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Sistem düzeyinde döküm sağlar.
init.*.rc dosyasını optimize etme
Init, çekirdekten çerçevenin oluşturulmasına kadar olan köprüdür ve cihazlar genellikle farklı init aşamalarında birkaç saniye geçirir.
Görevleri paralel olarak çalıştırma
Mevcut Android init aşağı yukarı tek iş parçacıklı bir işlem olsa da bazı görevleri paralel olarak gerçekleştirebilirsiniz.
- Kabuk komut dosyası hizmetinde yavaş komutları yürütün ve belirli bir mülkü bekleyerek daha sonra birleştirin. Android 8.0, bu kullanım alanını yeni bir
wait_for_property
komutuyla destekler. - init'te yavaş işlemleri belirleme Sistem, init komutunu (exec/wait_for_prop) veya uzun süren herhangi bir işlemi (Android 8.0'da 50 ms'den uzun süren tüm komutlar) günlüğe kaydeder. Örnek:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
Bu günlüğü inceleyerek iyileştirme fırsatları bulabilirsiniz.
- Kritik yoldaki hizmetleri başlatın ve çevre birim cihazlarını erkenden etkinleştirin. Örneğin, bazı SOC'ler SurfaceFlinger'ı başlatmadan önce güvenlikle ilgili hizmetlerin başlatılmasını gerektirir. ServiceManager "wait for service" (hizmeti bekle) değerini döndürdüğünde sistem günlüğünü inceleyin. Bu, genellikle bağımlı bir hizmetin önce başlatılması gerektiğinin bir işaretidir.
- init.*.rc dosyasında kullanılmayan tüm hizmetleri ve komutları kaldırın. İlk aşamada başlatılırken kullanılmayan her şey, önyükleme tamamlanana kadar ertelenebilir.
Not: Mülk hizmeti, init sürecinin bir parçasıdır. Bu nedenle, init yerleşik komutlarda meşgulse önyükleme sırasında setproperty
çağrısı uzun bir gecikmeye neden olabilir.
Planlayıcı ayarını kullanma
Erken başlatma için planlayıcı ayarlarını kullanın. Google Pixel'den örnek:
on init # boottime stune write /dev/stune/schedtune.prefer_idle 1 write /dev/stune/schedtune.boost 100 on property:sys.boot_completed=1 # reset stune write /dev/stune/schedtune.prefer_idle 0 write /dev/stune/schedtune.boost 0 # or just disable EAS during boot on init write /sys/kernel/debug/sched_features NO_ENERGY_AWARE on property:sys.boot_completed=1 write /sys/kernel/debug/sched_features ENERGY_AWARE
Bazı hizmetlerin, önyükleme sırasında öncelik artırması gerekebilir. Örnek:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Zigotu erken başlatın
Dosya tabanlı şifreleme kullanan cihazlar, zygote-start tetikleyicisinde zygote'u daha erken başlatabilir (varsayılan olarak zygote, zygote-start'tan çok daha sonra olan class main'de başlatılır). Bunu yaparken zygote'un tüm CPU'larda çalışmasına izin verdiğinizden emin olun (yanlış cpuset ayarı zygote'u belirli CPU'larda çalışmaya zorlayabilir).
Güç tasarrufunu devre dışı bırakma
Cihazın başlatılması sırasında UFS ve/veya CPU denetleyicisi gibi bileşenler için güç tasarrufu ayarı devre dışı bırakılabilir.
Dikkat: Verimlilik için şarj cihazı modunda güç tasarrufu etkinleştirilmelidir.
on init # Disable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0 write /sys/module/lpm_levels/parameters/sleep_disabled Y on property:sys.boot_completed=1 # Enable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1 write /sys/module/lpm_levels/parameters/sleep_disabled N on charger # Enable UFS powersaving write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1 write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1 write /sys/class/typec/port0/port_type sink write /sys/module/lpm_levels/parameters/sleep_disabled N
Kritik olmayan başlatmayı erteleme
ZRAM gibi kritik olmayan başlatma işlemleri boot_complete
'e ertelenebilir.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Açılış animasyonunu optimize etme
Açılış animasyonunu optimize etmek için aşağıdaki ipuçlarını kullanın.
Erken başlangıcı yapılandırma
Android 8.0, önyükleme animasyonunun userdata bölümünün monte edilmesinden önce başlatılmasını sağlar. Ancak Android 8.0'da yeni ext4 araç zinciri kullanıldığında bile fsck, güvenlik nedeniyle düzenli olarak tetiklenmeye devam eder ve bootanimation hizmetinin başlatılmasında gecikme yaşanmasına neden olur.
bootanimation'in erken başlamasını sağlamak için fstab bağlama işlemini iki aşamaya bölün:
- İlk aşamada, yalnızca çalıştırma kontrolü gerektirmeyen bölümleri (
system/
vevendor/
gibi) monte edin, ardından önyükleme animasyonu hizmetlerini ve bunların bağımlılarını (ör. servicemanager ve surfaceflinger) başlatın. - İkinci aşamada, kontrol çalıştırmayı gerektiren bölümleri (
data/
gibi) monte edin.
fsck'ye bakılmaksızın önyükleme animasyonu çok daha hızlı (ve sabit bir sürede) başlatılır.
Temiz bir şekilde bitirin
Çıkış sinyalini aldıktan sonra bootanimation son kısmı oynatır. Bu kısmın uzunluğu, önyükleme süresini uzatabilir. Hızlı bir şekilde açılan bir sistemde, yapılan iyileştirmeleri etkili bir şekilde gizleyebilecek uzun animasyonlara gerek yoktur. Hem tekrarlanan döngüyü hem de finali kısa tutmanız önerilir.
SELinux'u optimize etme
SELinux'u daha iyi önyükleme süreleri için optimize etmek üzere aşağıdaki ipuçlarını kullanın.
- Net normal ifadeler (regex) kullanın. Kötü biçimlendirilmiş normal ifade,
file_contexts
içindekisys/devices
için SELinux politikasını eşleştirirken çok fazla ek yüke neden olabilir. Örneğin, normal ifade/sys/devices/.*abc.*(/.*)?
, "abc" içeren tüm/sys/devices
alt dizinlerinin yanlışlıkla taranmasını zorunlu kılarak hem/sys/devices/abc
hem de/sys/devices/xyz/abc
için eşleşmeleri etkinleştirir. Bu normal ifadeyi/sys/devices/[^/]*abc[^/]*(/.*)?
olarak iyileştirmek, yalnızca/sys/devices/abc
ile eşleşmeyi sağlar. - Etiketleri genfscon'a taşıyın. Mevcut SELinux özelliği, dosya eşleştirme ön eklerini SELinux ikili dosyasındaki çekirdeğe iletir. Çekirdek, bu ön ekleri çekirdek tarafından oluşturulan dosya sistemlerine uygular. Bu işlem, yeniden etiketleme işleminden önce bu dosyalara erişmeye çalışan kullanıcı alanı süreçleri arasında oluşabilecek yarış koşullarını önleyerek, çekirdek tarafından oluşturulan yanlış etiketlenmiş dosyaların düzeltilmesine de yardımcı olur.
Araçlar ve yöntemler
Optimizasyon hedefleri için veri toplamanıza yardımcı olması amacıyla aşağıdaki araçları kullanın.
Bootchart
Bootchart, sistem genelindeki tüm işlemlerin CPU ve G/Ç yükü dökümünü sağlar. Sistem görüntüsünün yeniden oluşturulmasını gerektirmez ve systrace'e girmeden önce hızlı bir doğrulama kontrolü olarak kullanılabilir.
bootchart'ı etkinleştirmek için:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Açılıştan sonra önyükleme grafiğini alın:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
İşlem tamamlandığında, verilerin her seferinde toplanmasını önlemek için /data/bootchart/enabled
öğesini silin.
bootchart.png
dosyasının bulunmadığını belirten bir hata alırsanız aşağıdakileri yapın:
- Aşağıdaki komutları çalıştırın:
sudo apt install python-is-python3
cd ~/Documents
git clone https://github.com/xrmx/bootchart.git
cd bootchart/pybootchartgui
mv main.py.in main.py
-
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
değerini,pybootchartgui
değerinin yerel kopyasını (~/Documents/bootchart/pybootchartgui.py
konumunda) işaret edecek şekilde güncelleyin
Systrace
Systrace, önyükleme sırasında hem çekirdek hem de Android izlemelerinin toplanmasına olanak tanır. systrace'in görselleştirilmesi, önyükleme sırasında belirli bir sorunun analiz edilmesine yardımcı olabilir. (Ancak, tüm önyükleme sırasındaki ortalama sayıyı veya birikmiş sayıyı kontrol etmek için doğrudan çekirdek izlemeye bakmak daha kolaydır).
systrace'i önyükleme sırasında etkinleştirmek için:
-
frameworks/native/cmds/atrace/atrace.rc
dosyasında şunları değiştirin:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
Şunları yapmak için:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
device.mk
dosyasına aşağıdaki satırı ekleyin:PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- Cihaz
BoardConfig.mk
dosyasına aşağıdakileri ekleyin:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- Cihaza özgü
init.rc
dosyasına aşağıdakileri ekleyin:on property:sys.boot_completed=1 // This stops tracing on boot complete write /d/tracing/tracing_on 0 write /d/tracing/events/ext4/enable 0 write /d/tracing/events/f2fs/enable 0 write /d/tracing/events/block/enable 0
-
Açılıştan sonra, izlemeyi alın:
adb root && adb shell atrace --async_stop -z -c -o /data/local/tmp/boot_trace
adb pull /data/local/tmp/boot_trace
$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=boot_trace
Bu işlem, izlemeyi (varsayılan olarak devre dışıdır) etkinleştirir.
Ayrıntılı G/Ç analizi için ayrıca block, ext4 ve f2fs dosya sistemlerini de ekleyin.