Ten dokument zawiera wskazówki dla partnerów dotyczące skrócenia czasu uruchamiania określonych urządzeń z systemem Android. Czas rozruchu jest ważnym elementem wydajności systemu, ponieważ użytkownicy muszą poczekać na zakończenie rozruchu, zanim będą mogli korzystać z urządzenia. W przypadku urządzeń takich jak samochody, w których zimne uruchamianie systemu zdarza się częściej, szybki czas rozruchu ma kluczowe znaczenie (nikt nie lubi czekać kilkudziesięciu sekund tylko na wprowadzenie celu nawigacji).
Android 8.0 pozwala na skrócenie czasu uruchamiania, obsługując kilka ulepszeń w szeregu komponentów. W poniższej tabeli podsumowano tę poprawę wydajności (mierzoną na urządzeniach Google Pixel i Pixel XL).
Część | Poprawa |
---|---|
Program rozruchowy |
|
Jądro urządzenia |
|
Strojenie wejść/wyjść |
|
init.*.rc |
|
Animacja uruchamiania |
|
Polityka SELinuksa | Genfscon zaoszczędził 0,2 s |
Zoptymalizuj bootloader
Aby zoptymalizować program ładujący w celu skrócenia czasu uruchamiania:
- Do logowania:
- Wyłącz zapisywanie dziennika do UART, ponieważ przy dużej liczbie rejestrowań może to zająć dużo czasu. (Na urządzeniach Google Pixel odkryliśmy, że spowalnia program ładujący o 1,5 s).
- Rejestruj tylko sytuacje błędów i rozważ przechowywanie innych informacji w pamięci za pomocą osobnego mechanizmu do odzyskiwania.
- W przypadku dekompresji jądra rozważ użycie LZ4 dla współczesnego sprzętu zamiast GZIP (przykładowa łatka ). Należy pamiętać, że różne opcje kompresji jądra mogą mieć różne czasy ładowania i dekompresji, a niektóre opcje mogą działać lepiej niż inne w przypadku konkretnego sprzętu.
- Sprawdź niepotrzebne czasy oczekiwania na odrzucenie/wejście w tryb specjalny i zminimalizuj je.
- Przekaż czas rozruchu spędzony w programie ładującym do jądra jako linię cmdline.
- Sprawdź zegar procesora i rozważ równoległość (wymaga obsługi wielu rdzeni) w celu ładowania jądra i inicjowania wejść/wyjść.
Zoptymalizuj wydajność we/wy
Poprawa wydajności operacji we/wy ma kluczowe znaczenie dla skrócenia czasu rozruchu, dlatego odczytanie wszystkiego, co nie jest konieczne, należy odłożyć do czasu rozruchu (w przypadku Google Pixel podczas rozruchu odczytywane jest około 1,2 GB danych).
Dostrój system plików
Jądro Linuksa uruchamia funkcję odczytu z wyprzedzeniem, gdy plik jest odczytywany od początku lub gdy bloki są odczytywane sekwencyjnie, co powoduje konieczność dostrojenia parametrów harmonogramu we/wy specjalnie pod kątem uruchamiania (który ma inną charakterystykę obciążenia niż zwykłe aplikacje).
Urządzenia obsługujące płynne aktualizacje (A/B) czerpią ogromne korzyści z dostrajania systemu plików przy pierwszym uruchomieniu (np. 20s w Google Pixel). Dla przykładu dostroiliśmy następujące parametry dla Google Pixel:
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 ...
Różnorodny
- Włącz rozmiar wstępnego pobierania skrótu dm-verity, używając konfiguracji jądra DM_VERITY_HASH_PREFETCH_MIN_SIZE (domyślny rozmiar to 128).
- Aby uzyskać lepszą stabilność systemu plików i pomijanie wymuszonego sprawdzania, które występuje przy każdym uruchomieniu, użyj nowego narzędzia do generowania ext4, ustawiając TARGET_USES_MKE2FS w BoardConfig.mk.
Analizuj wejścia/wyjścia
Aby zrozumieć działania we/wy podczas rozruchu, użyj danych ftrace jądra (używanych również przez systrace):
trace_event=block,ext4 in BOARD_KERNEL_CMDLINE
Aby rozdzielić dostęp do każdego pliku, dokonaj następujących zmian w jądrze (tylko jądro rozwojowe; nie używaj w jądrach produkcyjnych):
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);
Użyj poniższych skryptów, aby pomóc w analizie wydajności rozruchu.
-
system/extras/boottime_tools/bootanalyze/bootanalyze.py
Mierzy czas rozruchu z zestawieniem ważnych kroków w procesie rozruchu. -
system/extras/boottime_tools/io_analysis/check_file_read.py boot_trace
Zawiera informacje o dostępie do każdego pliku. -
system/extras/boottime_tools/io_analysis/check_io_trace_all.py boot_trace
Zawiera zestawienie na poziomie systemu.
Zoptymalizuj init.*.rc
Init jest mostem prowadzącym od jądra do momentu ustanowienia frameworka, a urządzenia zwykle spędzają kilka sekund na różnych etapach inicjowania.
Uruchamiaj zadania równolegle
Chociaż bieżąca inicjacja Androida jest mniej więcej procesem jednowątkowym, nadal możesz wykonywać niektóre zadania równolegle.
- Wykonuj powolne polecenia w usłudze skryptowej powłoki i dołącz do nich później, czekając na określoną właściwość. Android 8.0 obsługuje ten przypadek użycia za pomocą nowego polecenia
wait_for_property
. - Zidentyfikuj powolne operacje w pliku init. System rejestruje polecenie init exec/wait_for_prop lub jakąkolwiek akcję trwającą długo (w Androidzie 8.0 każde polecenie trwające dłużej niż 50 ms). Na przykład:
init: Command 'wait_for_coldboot_done' action=wait_for_coldboot_done returned 0 took 585.012ms
Przeglądanie tego dziennika może wskazać możliwości wprowadzenia ulepszeń.
- Wcześnie uruchamiaj usługi i włączaj urządzenia peryferyjne na ścieżce krytycznej. Na przykład niektóre SOC wymagają uruchomienia usług związanych z bezpieczeństwem przed uruchomieniem SurfaceFlinger. Przejrzyj dziennik systemowy, gdy ServiceManager zwróci komunikat „czekaj na usługę” — zwykle jest to znak, że najpierw należy uruchomić usługę zależną.
- Usuń wszystkie nieużywane usługi i polecenia z pliku init.*.rc. Wszystko, co nie zostało użyte na wczesnym etapie inicjacji, powinno zostać odroczone do zakończenia rozruchu.
Uwaga: Usługa właściwości jest częścią procesu inicjowania, więc wywołanie setproperty
podczas uruchamiania może spowodować duże opóźnienie, jeśli init jest zajęty wbudowanymi poleceniami.
Użyj dostrajania harmonogramu
Użyj dostrajania harmonogramu w celu wczesnego uruchomienia. Przykład z Pixela Google:
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
Niektóre usługi mogą wymagać zwiększenia priorytetu podczas uruchamiania. Przykład:
init.zygote64.rc: service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server class main priority -20 user root ...
Rozpocznij zygotę wcześnie
Urządzenia z szyfrowaniem opartym na plikach mogą uruchamiać zygotę wcześniej w momencie wyzwalacza zygoty (domyślnie zygota jest uruchamiana w klasie głównej, czyli znacznie później niż start zygoty). Robiąc to, upewnij się, że zezwoliłeś na działanie zygoty na wszystkich procesorach (ponieważ nieprawidłowe ustawienie zestawu procesorów może wymusić działanie zygoty na określonych procesorach).
Wyłącz oszczędzanie energii
Podczas uruchamiania urządzenia można wyłączyć ustawienia oszczędzania energii dla komponentów takich jak UFS i/lub regulator procesora.
Uwaga: w celu zapewnienia wydajności należy włączyć oszczędzanie energii w trybie ładowarki.
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
Odłóż niekrytyczną inicjalizację
Inicjalizacja niekrytyczna, taka jak ZRAM, może zostać odroczona do boot_complete
.
on property:sys.boot_completed=1 # Enable ZRAM on boot_complete swapon_all /vendor/etc/fstab.${ro.hardware}
Zoptymalizuj animację rozruchu
Skorzystaj z poniższych wskazówek, aby zoptymalizować animację rozruchu.
Skonfiguruj wczesny start
Android 8.0 umożliwia wczesne rozpoczęcie animacji rozruchu, przed zamontowaniem partycji danych użytkownika. Jednak nawet w przypadku korzystania z nowego łańcucha narzędzi ext4 w systemie Android 8.0 fsck jest nadal uruchamiany okresowo ze względów bezpieczeństwa, powodując opóźnienie w uruchomieniu usługi animacji rozruchowej.
Aby animacja rozruchu rozpoczęła się wcześniej, podziel montaż fstab na dwie fazy:
- We wczesnej fazie zamontuj tylko partycje (takie jak
system/
ivendor/
), które nie wymagają sprawdzania uruchomienia, a następnie uruchom usługi animacji rozruchu i ich zależności (takie jak menedżer usług i Surfaceflinger). - W drugiej fazie zamontuj partycje (takie jak
data/
), które wymagają sprawdzenia działania.
Animacja rozruchu zostanie uruchomiona znacznie szybciej (i w stałym czasie) niezależnie od fsck.
Zakończ czysto
Po otrzymaniu sygnału wyjścia ostatnią część odgrywa animacja rozruchowa, której długość może spowolnić czas uruchamiania. System, który uruchamia się szybko, nie potrzebuje długich animacji, które skutecznie ukrywałyby wprowadzone ulepszenia. Zalecamy, aby zarówno powtarzająca się pętla, jak i finał były krótkie.
Zoptymalizuj SELinuksa
Skorzystaj z poniższych wskazówek, aby zoptymalizować SELinux w celu skrócenia czasu uruchamiania.
- Używaj czystych wyrażeń regularnych (regex) . Źle sformułowane wyrażenie regularne może prowadzić do dużego obciążenia podczas dopasowywania polityki SELinux dla
sys/devices
wfile_contexts
. Na przykład wyrażenie regularne/sys/devices/.*abc.*(/.*)?
błędnie wymusza skanowanie wszystkich podkatalogów/sys/devices
zawierających „abc”, umożliwiając dopasowanie zarówno/sys/devices/abc
, jak i/sys/devices/xyz/abc
. Poprawiasz to wyrażenie regularne do/sys/devices/[^/]*abc[^/]*(/.*)?
umożliwi dopasowanie tylko dla/sys/devices/abc
. - Przenieś etykiety do genfscon . Ta istniejąca funkcja SELinux przekazuje przedrostki dopasowujące pliki do jądra w pliku binarnym SELinux, gdzie jądro stosuje je do systemów plików generowanych przez jądro. Pomaga to również naprawić błędnie oznaczone pliki utworzone przez jądro, zapobiegając warunkom wyścigu, które mogą wystąpić między procesami przestrzeni użytkownika próbującymi uzyskać dostęp do tych plików przed zmianą etykietowania.
Narzędzia i metody
Skorzystaj z poniższych narzędzi, które pomogą Ci zebrać dane na potrzeby celów optymalizacji.
Schemat startowy
Bootchart zapewnia rozkład obciążenia procesora i wejść/wyjść wszystkich procesów w całym systemie. Nie wymaga przebudowy obrazu systemu i może być użyty do szybkiego sprawdzenia poprawności przed zanurzeniem się w systrace.
Aby włączyć bootchart:
adb shell 'touch /data/bootchart/enabled'
adb reboot
Po uruchomieniu pobierz schemat rozruchowy:
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
Po zakończeniu usuń /data/bootchart/enabled
aby zapobiec gromadzeniu danych za każdym razem.
bootchart.png
nie istnieje, wykonaj następujące czynności:- Uruchom następujące polecenia:
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
- Zaktualizuj
$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh
aby wskazywał lokalną kopiępybootchartgui
(znajdującą się pod adresem~/Documents/bootchart/pybootchartgui.py
)
Systrace
Systrace umożliwia zbieranie śladów jądra i systemu Android podczas uruchamiania systemu. Wizualizacja systrace może pomóc w analizie konkretnego problemu podczas uruchamiania. (Jednak aby sprawdzić średnią lub skumulowaną liczbę podczas całego rozruchu, łatwiej jest bezpośrednio zajrzeć do śledzenia jądra).
Aby włączyć systrace podczas uruchamiania:
- W
frameworks/native/cmds/atrace/atrace.rc
zmień:write /sys/kernel/debug/tracing/tracing_on 0 write /sys/kernel/tracing/tracing_on 0
Do:
# write /sys/kernel/debug/tracing/tracing_on 0 # write /sys/kernel/tracing/tracing_on 0
- W pliku
device.mk
dodaj następujący wiersz:PRODUCT_PROPERTY_OVERRIDES += debug.atrace.tags.enableflags=802922 PRODUCT_PROPERTY_OVERRIDES += persist.traced.enable=0
- W pliku
BoardConfig.mk
urządzenia dodaj następujące polecenie:BOARD_KERNEL_CMDLINE := ... trace_buf_size=64M trace_event=sched_wakeup,sched_switch,sched_blocked_reason,sched_cpu_hotplug
- W pliku
init.rc
specyficznym dla urządzenia dodaj następujące polecenie: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
Po uruchomieniu pobierz ślad:
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
Umożliwia to śledzenie (które jest domyślnie wyłączone).
Aby uzyskać szczegółową analizę wejść/wyjść, dodaj także blok oraz ext4 i f2fs.