Ocena skuteczności

Aby ocenić wydajność urządzenia, użyj narzędzia Simpleperf. Simpleperf to natywne narzędzie do profilowania aplikacji i procesów natywnych na Androidzie. Użyj profilowania procesora, aby w czasie rzeczywistym sprawdzić wykorzystanie procesora przez aplikację i aktywność wątków.

Istnieją 2 widoczne dla użytkowników wskaźniki skuteczności:

  • Spodziewana, odczuwalna wydajność. Czy interfejs użytkownika (UI) wyświetla klatki z błędami czy też stale renderuje obraz z prędkością 60 FPS? Czy dźwięk odtwarza się bez artefaktów lub trzasków? Jak długi jest czas od chwili, gdy użytkownik dotknie ekranu, do chwili wyświetlenia efektu na ekranie?
  • Czas potrzebny na wykonanie dłuższych operacji (np. otwieranie aplikacji).

Pierwszy jest bardziej zauważalny niż drugi. Użytkownicy zwykle zauważają zacięcia, ale nie będą w stanie odróżnić 500 ms od 600 ms czasu uruchamiania aplikacji, chyba że będą patrzeć na 2 urządzenia obok siebie. Opóźnienie dotyku jest natychmiast zauważalne i znacznie wpływa na odbiór urządzenia.

W przypadku szybkiego urządzenia najważniejszą rzeczą w systemie jest przepływ interfejsu użytkownika, z wyjątkiem tego, co jest niezbędne do jego działania. Oznacza to, że przetwarzanie interfejsu powinno wyprzedzać inne działania, które nie są konieczne do płynnego interfejsu. Aby zapewnić płynność interfejsu, synchronizacja w tle, wysyłanie powiadomień i podobna praca muszą być opóźnione, jeśli może być wykonywana praca związana z interfejsem. Można poświęcić wydajność dłuższych operacji (czas działania HDR+, uruchamianie aplikacji itp.), aby zapewnić płynność interfejsu.

Pojemność a jitter

W przypadku skuteczności urządzenia pojemność i jitter to 2 ważne dane.

Pojemność

Pojemność to łączna ilość zasobu, jaką urządzenie ma w danym przedziale czasu. Mogą to być zasoby procesora, zasoby karty graficznej, zasoby we/wy, zasoby sieciowe, przepustowość pamięci lub dowolne podobne dane. Podczas analizowania skuteczności całego systemu może być przydatne odseparowanie poszczególnych komponentów i przyjęcie, że skuteczność określa jeden parametr (szczególnie podczas dostosowywania nowego urządzenia, ponieważ obciążenia wykonywane na tym urządzeniu są prawdopodobnie stałe).

Pojemność systemu zależy od zasobów obliczeniowych online. Zmiana częstotliwości procesora lub karty graficznej jest głównym sposobem zmiany pojemności, ale istnieją też inne sposoby, takie jak zmiana liczby rdzeni procesora w trybie online. W zależności od tego, jak duża jest pojemność systemu, zmienia się zużycie energii. Zmiany pojemności zawsze powodują podobną zmianę zużycia energii.

Potrzebna w danym momencie pojemność jest w dużej mierze określana przez uruchomioną aplikację. W związku z tym platforma może niewiele zrobić, aby dostosować pojemność do danego zbioru zadań, a środki do tego celu są ograniczone do ulepszeń czasu wykonywania (platforma Android, ART, Bionic, kompilator GPU/sterowniki, jądro).

Zakłócenia

Wymagana pojemność dla zadania jest łatwa do określenia, ale jitter to bardziej niejasne pojęcie. Aby dowiedzieć się więcej o jitterze jako przeszkodzie dla szybkich systemów, przeczytaj artykuł The Case of the Missing Supercomputer Performance: Achieving Optimal Performance on the 8,192 processors of ASCI Q. (to badanie, dlaczego superkomputer ASCIQ nie osiągnął oczekiwanej wydajności, i doskonałe wprowadzenie do optymalizacji dużych systemów).

Na tej stronie używamy określenia „jitter” w odniesieniu do tego, co w artykule ASCI Q nazywa szumem. Jitter to przypadkowe zachowanie systemu, które uniemożliwia uruchomienie zauważalnego działania. Często jest to zadanie, które musi zostać wykonane, ale nie musi być realizowane w określonym czasie. Ponieważ jest on losowy, bardzo trudno jest obalić istnienie jittera w przypadku danego obciążenia. Trudno też udowodnić, że znany czynnik powodujący jitter był przyczyną konkretnego problemu z wydajnością. Narzędzia najczęściej używane do diagnozowania przyczyn jittera (np. śledzenie lub rejestrowanie) mogą wprowadzać własny jitter.

Do jittera w implementacjach Androida w rzeczywistych warunkach przyczyniają się m.in.:

  • Opóźnienie planisty
  • Moduły obsługi przerwań
  • Kod sterownika działa zbyt długo z wyłączonym wywłaszczeniem lub przerwaniem
  • Długotrwałe softirq-i
  • Rywalizacja o blokadę (aplikacja, framework, sterownik jądra, blokada bindera, blokada mmap)
  • Spór o deskryptor pliku, w którym wątek o niskim priorytecie blokuje plik, uniemożliwiając uruchomienie wątku o wysokim priorytecie.
  • Uruchamianie kodu istotnego dla interfejsu użytkownika w kolekach zadań, w których może on zostać opóźniony
  • Przechodzenie procesora w stan bezczynności
  • Logowanie
  • Opóźnienia operacji wejścia/wyjścia
  • niepotrzebne tworzenie procesów (np. transmisje CONNECTIVITY_CHANGE);
  • Wypełnianie pamięci podręcznej strony z powodu niewystarczającej ilości wolnej pamięci

Czas wymagany na dany okres jittera może się zmniejszać wraz ze wzrostem mocy. Jeśli na przykład sterownik pozostawi przerwania wyłączone podczas oczekiwania na odczyt z interfejsu I2C, zajmie to określony czas niezależnie od tego, czy procesor działa z częstotliwością 384 MHz czy 2 GHz. Wzrost przepustowości nie jest realnym rozwiązaniem umożliwiającym poprawę wydajności w przypadku jittera. W rezultacie szybsze procesory zwykle nie poprawiają wydajności w sytuacjach, w których występuje jitter.

Na koniec warto wspomnieć, że w przeciwieństwie do pojemności jitter zależy niemal całkowicie od dostawcy systemu.

Wykorzystanie pamięci

Zazwyczaj za słabe działanie oprogramowania obwinia się zużycie pamięci. Chociaż zużycie nie jest problemem związanym z wydajnością, może powodować drgania spowodowane obciążeniem lowmemorykiller, ponownym uruchamianiem usług i wyczerpywaniem pamięci podręcznej strony. Zmniejszenie zużycia pamięci może zapobiec bezpośrednim przyczynom niskiej wydajności, ale mogą też istnieć inne ulepszenia, które również zapobiegają tym przyczynom (np. przypięcie ramki, aby zapobiec jej wyparciu, gdy zostanie ona wkrótce ponownie załadowana).

Analiza początkowej wydajności urządzenia

Rozpoczynanie od systemu, który działa, ale ma słabe wyniki, i próba naprawienia jego działania przez analizę poszczególnych przypadków widocznej dla użytkowników niskiej wydajności nie jest rozsądną strategią. Zła wydajność nie jest zwykle łatwa do odtworzenia (np. jitter) ani nie jest problemem aplikacji, ponieważ zbyt wiele zmiennych w całym systemie uniemożliwia skuteczność tej strategii. W efekcie bardzo łatwo jest błędnie zidentyfikować przyczyny i wprowadzić drobne ulepszenia, pomijając systemowe możliwości naprawienia skuteczności w całym systemie.

Zamiast tego, gdy wprowadzasz nowe urządzenie:

  1. Uruchom system, aby wyświetlić interfejs z działającymi sterownikami i podstawowymi ustawieniami sterownika częstotliwości (jeśli zmienisz ustawienia sterownika częstotliwości, powtórz wszystkie czynności opisane poniżej).
  2. Upewnij się, że jądro obsługuje punkt sched_blocked_reason, a także inne punkty w pipeline wyświetlania, które wskazują, kiedy ramka jest dostarczana do wyświetlacza.
  3. Wykonuj długie śledzenia całego potoku interfejsu użytkownika (od odbierania danych wejściowych przez IRQ do końcowego skanowania) podczas wykonywania lekkiego i ciągłego obciążenia (np. UiBench lub test kulki w TouchLatency).
  4. Rozwiąż problemy z utratą klatek wykryte w lekkiej i konsekwentnej pracy.
  5. Powtarzaj kroki 3–4, aż uzyskasz zero utraconych klatek przez co najmniej 20 sekund.
  6. Przejdź do innych widocznych dla użytkownika źródeł zakłóceń.

Inne proste czynności, które możesz wykonać na wczesnym etapie uruchamiania urządzenia:

  • Upewnij się, że w jądrze jest zastosowana poprawka sched_blocked_reasontracepoint. Ten punkt śledzenia jest włączony za pomocą kategorii śledzonej sched w systrace i zawiera funkcję odpowiedzialną za uśpienie, gdy wątek przechodzi w tryb nieprzerywanego uśpienia. Jest to bardzo ważne dla analizy skuteczności, ponieważ nieprzerwany sen jest bardzo częstym wskaźnikiem jittera.
  • Upewnij się, że masz wystarczającą ilość śledzonych danych w przypadku GPU i przepływów danych wyświetlacza. W przypadku najnowszych procesorów Qualcomm SOC punkty śledzenia są włączone za pomocą:
  • adb shell "echo 1 > /d/tracing/events/kgsl/enable"
    adb shell "echo 1 > /d/tracing/events/mdss/enable"
    

    Te zdarzenia pozostają włączone podczas wykonywania polecenia systrace, dzięki czemu możesz zobaczyć dodatkowe informacje o wyświetleniu ścieżki (MDSS) w sekcji mdss_fb0. W standardowym widoku systrace nie zobaczysz żadnych dodatkowych informacji o procesorze graficznym w układzie Qualcomm SOC, ale wyniki są widoczne w samym pliku śledzonej aktywności (szczegółowe informacje znajdziesz w artykule Zrozumienie pliku systrace).

    W przypadku tego rodzaju śledzenia wyświetlania potrzebujesz jednego zdarzenia, które bezpośrednio wskazuje, że klatka została przesłana do wyświetlacza. Na tej podstawie możesz określić, czy udało Ci się osiągnąć czas wyświetlania klatki.Jeśli zdarzenie Xn nastąpi mniej niż 16,7 ms po zdarzeniu Xn-1 (przy założeniu wyświetlacza 60 Hz), oznacza to, że nie wystąpiło zacięcie. Jeśli zespół SOC nie dostarcza takich sygnałów, poproś o nie dostawcę. Debugowanie jittera jest bardzo trudne bez jednoznacznego sygnału o ukończeniu klatki.

Korzystanie z syntetycznych punktów odniesienia

Testy syntetyczne są przydatne do sprawdzania, czy urządzenie ma podstawowe funkcje. Nie jest jednak przydatne traktowanie wyników testów porównawczych jako przybliżonego wskaźnika wydajności urządzenia.

Na podstawie doświadczeń z systemami operacyjnymi SOC wiemy, że różnice w wydajności syntetycznych benchmarków między systemami nie są skorelowane z podobną różnicą w dostrzegalnej wydajności interfejsu użytkownika (liczba opuszczonych klatek, czas klatek w 99. percentylu itp.). Syntetyczne dane porównawcze to dane porównawcze dotyczące tylko pojemności; jitter wpływa na zmierzoną skuteczność tych danych tylko przez kradzież czasu z operacji zbiorczej danych. W związku z tym wyniki testów porównawczych na podstawie danych syntetycznych są w większości nieistotne jako dane o wydajności postrzeganej przez użytkowników.

Weź pod uwagę 2 urządzenia SOC z benchmarkiem X, które renderują 1000 klatek interfejsu użytkownika i zgłaszają łączny czas renderowania (im niższy wynik, tym lepiej).

  • SOC 1 renderuje każdą klatkę benchmarku X w 10 ms i otrzymuje wynik 10 000.
  • SOC 2 renderuje 99% klatek w 1 ms,ale 1% klatek w 100 ms i otrzymuje wynik 19 900, co jest znacznie lepszym wynikiem.

Jeśli punkt odniesienia wskazuje na rzeczywistą wydajność interfejsu użytkownika, SOC 2 będzie bezużyteczny. Przy częstotliwości odświeżania 60 Hz SOC 2 będzie wyświetlać klatkę z zakłóceniem co 1, 5 s. Tymczasem SOC 1 (wolniejszy SOC według benchmarku X) byłby płynny.

Korzystanie z raportów o błędach

Raporty o błędach są czasami przydatne do analizy wydajności, ale ze względu na ich rozmiar rzadko są przydatne do debugowania sporadycznych problemów z płynnością. Mogą one podać wskazówki dotyczące tego, co system robił w danym momencie, zwłaszcza jeśli problem wystąpił podczas przełączania aplikacji (co jest rejestrowane w raporcie o błędach). Raporty o błędach mogą też wskazywać, że coś jest nie tak z systemem, co może ograniczać jego skuteczność (np. ograniczanie ze względu na temperaturę lub fragmentacja pamięci).

Używanie TouchLatency

Kilka przykładów nieprawidłowego działania pochodzi z TouchLatency, który jest preferowanym okresowym obciążeniem używanym w przypadku Pixela i Pixela XL. Jest dostępny na stronie frameworks/base/tests/TouchLatency i ma 2 tryby: opóźnienia dotyku i kulki odbijającej się od ścian (aby przełączyć tryby, kliknij przycisk w prawym górnym rogu).

Test odbijającej się piłki jest tak prosty, jak się wydaje: piłka odbija się po ekranie bez końca, niezależnie od działań użytkownika. Jest to też najtrudniejszy test do przeprowadzenia w doskonały sposób, ale im bliżej do jego ukończenia bez utraty klatek, tym lepsze będzie Twoje urządzenie. Test bouncing ball jest trudny, ponieważ jest to trywialna, ale doskonale spójna obciążenie, która działa z bardzo niskim zegarem (zakładamy, że urządzenie ma regulator częstotliwości; jeśli urządzenie działa z ustawionymi zegarami, podczas pierwszego uruchomienia testu bouncing ball zmniejsz częstotliwość procesora i procesora graficznego do wartości zbliżonej do minimalnej). Gdy system przechodzi w stan bezczynności i zegary zbliżają się do wartości bezczynności, wymagany czas procesora i karty graficznej na każdą klatkę wzrasta. Możesz obserwować piłkę i zauważyć, że obraz jest zrywny. W pliku systrace zobaczysz też brakujące klatki.

Ponieważ obciążenie jest bardzo spójne, możesz zidentyfikować większość źródeł zacięcia znacznie łatwiej niż w przypadku większości widocznych dla użytkownika obciążeń, śledząc, co dokładnie działa w systemie w przypadku każdego pominiętego klatka, a nie w przypadku potoku interfejsu użytkownika. Niższe zegary wzmacniają efekt jittera, ponieważ zwiększają prawdopodobieństwo, że jitter spowoduje utratę klatki. W związku z tym im mniejsza jest wartość TouchLatency w porównaniu z 60 FPS, tym mniejsze jest prawdopodobieństwo wystąpienia nieprawidłowego działania systemu, które powoduje sporadyczne, trudne do odtworzenia zakłócenia w większych aplikacjach.

Ponieważ jitter często (ale nie zawsze) jest niezależny od szybkości zegara, diagnozowanie jittera należy przeprowadzić za pomocą testu, który działa z bardzo niską szybkością zegara z tych powodów:

  • Nie cały jitter jest niezależny od szybkości zegara; wiele źródeł po prostu zużywa czas procesora.
  • Sterownik powinien doprowadzić średni czas generowania klatek do wartości zbliżonej do limitu, tak aby czas poświęcony na wykonywanie zadań niezwiązanych z interfejsem użytkownika nie spowodował pominięcia klatki.