Możesz skonfigurować śledzenie systemu, aby przechwytywać Profil procesora i wątków aplikacji w krótkim czasie. Potem możesz wykorzystać raport wyjściowy ze logu systemowego, aby poprawić skuteczność reklam.
Konfigurowanie śledzenia systemu opartego na grze
Narzędzie Systrace jest dostępne na dwa sposoby:
Systrace to niewielkie narzędzie, które:
- Dostarcza dane podstawowe. Systrace przechwytuje dane wyjściowe bezpośrednio z jądra, więc zbierane przez nią dane są niemal identyczne dla połączeń systemowych.
- Zużywa niewiele zasobów. Systrace wprowadza bardzo niskie koszty urządzenia, zwykle poniżej 1%, ponieważ przesyła dane do bufora w pamięci.
Optymalne ustawienia
Ważne jest, aby narzędzie to przedstawiło rozsądny zestaw argumentów:
- Kategorie: najlepszy zestaw kategorii dostępnych w systemie opartym na grach.
śledzenie to: {
sched
,freq
,idle
,am
,wm
,gfx
,view
,sync
,binder_driver
,hal
,dalvik
}. Rozmiar bufora: zgodnie z ogólną zasadą rozmiar bufora wynosi 10 MB na rdzeń procesora. umożliwia śledzenie o długości około 20 sekund. Jeśli na przykład urządzenie ma dwa procesory czterordzeniowe (łącznie 8 rdzeni), odpowiednią wartość do przekazania Program
systrace
ma rozmiar 80 000 KB (80 MB).Jeśli Twoja gra często zmienia kontekst, zwiększ bufor do 15 MB na rdzeń procesora.
Zdarzenia niestandardowe: jeśli zdefiniujesz niestandardowe zdarzenia zdarzeń rejestrowanych w grze, włącz flagę
-a
, która pozwala firmie Systrace uwzględnić te zdarzenia niestandardowe w raport wyjściowy.
Jeśli używasz wiersza poleceń systrace
programu, użyj następującego polecenia
do rejestrowania logu czasu systemu, który stosuje sprawdzone metody dotyczące zbioru kategorii, bufora
rozmiaru i zdarzeń niestandardowych:
python systrace.py -a com.example.myapp -b 80000 -o my_systrace_report.html \ sched freq idle am wm gfx view sync binder_driver hal dalvik
Jeśli używasz aplikacji systemowej Systrace na na urządzeniu, wykonaj te czynności, przechwytuje ślad systemu z zastosowaniem sprawdzonych metod dotyczących zbioru kategorii, bufora rozmiaru i zdarzeń niestandardowych:
Włącz opcję Śledź aplikacje z możliwością debugowania.
Do przy użyciu tego ustawienia, na urządzeniu musi być dostępne 256 lub 512 MB (w zależności od czy procesor ma 4 czy 8 rdzeni), a każdy 64 MB pamięci musi mieć są dostępne jako ciągły fragment.
Wybierz Kategorie i włącz kategorie z tej listy:
am
: Menedżer aktywnościbinder_driver
: sterownik jądra binarnegodalvik
: maszyna wirtualna Dalvikfreq
: częstotliwość procesoragfx
: grafikahal
: moduły sprzętoweidle
: procesor nieaktywnysched
: harmonogram procesorasync
: synchronizacjaview
: wyświetl systemwm
: menedżer okien
Włącz Śledzenie rekordów.
Wczytaj grę.
Wykonuj interakcje w grze odpowiadające rozgrywce, której do pomiaru wydajności urządzenia.
Gdy tylko zauważysz w grze niepożądane zachowanie, włącz śledzić.
Masz już zebrane statystyki skuteczności które są niezbędne do dalszej analizy problemu.
Aby zaoszczędzić miejsce na dysku, ślady systemu na urządzeniu zapisują pliki w skompresowanym logu czasu
format (*.ctrace
). Aby zdekompresować ten plik podczas generowania raportu, użyj funkcji
wiersza poleceń i dodaj opcję --from-file
:
python systrace.py --from-file=/data/local/traces/my_game_trace.ctrace \ -o my_systrace_report.html
Ulepsz określone obszary skuteczności
W tej sekcji omawiamy kilka częstych problemów z wydajnością w grach mobilnych i opisuje, jak zidentyfikować i ulepszyć te aspekty gry.
Prędkość wczytywania
Gracze chcą jak najszybciej wziąć udział w grze, więc które pozwalają maksymalnie skrócić czas wczytywania gry. Poniżej rozwiązania zwykle pomagają skrócić czas wczytywania:
- Zastosuj leniwe ładowanie. Jeśli używasz tych samych zasobów w wielu następujących po sobie zasobów: scen lub poziomów w grze, zasoby są wczytywane tylko raz.
- Zmniejsz rozmiar zasobów. Dzięki temu można połączyć pliki nieskompresowane tych zasobów z pakietem APK gry.
- Używaj metody kompresji, która oszczędza dysk. Przykładem takiej metody jest zlib.
- Używaj IL2CPP zamiast mono. (ma zastosowanie tylko wtedy, gdy używasz Unity). IL2CPP zapewnia na wydajność wykonywania skryptów C#.
- Postaw na wielowątkowość w grze. Więcej informacji znajdziesz w artykule na temat liczby klatek na sekundę spójności.
Spójność liczby klatek
Jednym z najważniejszych elementów w rozgrywce jest osiągnięcie stałą liczbę klatek. Aby łatwiej osiągnąć ten cel, postępuj zgodnie z omówionych w tej sekcji technik optymalizacji.
Wielowątkowość
Przy tworzeniu aplikacji na wiele platform naturalne jest stosowanie wszystkich działań, w ramach gry w jednym wątku. Chociaż ta metoda jest prosta, w wielu silnikach gier, w przypadku Androida nie jest to optymalne urządzenia. W rezultacie gry jednowątkowe często wczytują się powoli i nie mają stałą liczbę klatek.
Układ Systrace przedstawiony na rys. 1 przedstawia typowe zachowanie gry. działające na tylko jednym procesorze naraz:
Aby poprawić wydajność gry, ustaw ją jako wielowątkową. Zazwyczaj najlepszy model to 2 wątki:
- Wątek gry, który zawiera główne moduły gry i wysyła informacje o renderowaniu. poleceń.
- Wątek renderowania, który otrzymuje polecenia renderowania i tłumaczy je na język polecenia graficzne, których GPU urządzenia może używać do wyświetlania sceny.
Interfejs Vulkan API rozszerza ten model, ponieważ może on przekazywać 2 typowe i równoległe bufory. Za pomocą tej funkcji możesz rozłożyć wiele elementów renderowania przez więcej niż 1 procesor, co jeszcze bardziej skraca czas renderowania sceny.
Możesz też wprowadzić zmiany związane z określonym silnikiem, aby poprawić wydajność wielowątkowości:
- Jeśli opracowujesz grę z wykorzystaniem silnika Unity, włącz Renderowanie wielowątkowe i motywowanie procesora graficznego.
- Jeśli używasz niestandardowego silnika, upewnij się, że polecenie renderowania potok poleceń i potok poleceń graficznych są prawidłowo dopasowane; W przeciwnym razie może powodować opóźnienia w wyświetlaniu scen z gry.
Po zastosowaniu tych zmian gra powinna zajmować co najmniej 2 procesory jednocześnie, jak widać na rys. 2:
Wczytuję element interfejsu
Podczas tworzenia gry z wieloma funkcjami łatwo jest pokazywać wiele różnych opcji i działań w tym samym czasie. Aby utrzymać stałą liczbę klatek, trzeba jednak wziąć pod uwagę stosunkowo niewielkie rozmiary ekranów mobilnych a interfejs użytkownika powinien być jak najprostszy.
Raport Systrace przedstawiony na Rysunku 3 to przykład ramki interfejsu, próba renderowania zbyt wielu elementów w stosunku do funkcje zabezpieczeń.
Dobrym celem jest skrócenie czasu aktualizacji interfejsu do 2–3 milisekund. Dostępne opcje aby uzyskać tak szybkie aktualizacje, przeprowadzając optymalizacje podobne do poniższych:
- Aktualizuj tylko te elementy na ekranie, które zostały przeniesione.
- Ogranicz liczbę tekstur i warstw interfejsu. Rozważ połączenie rozmów graficznych, takich jak cieniowanie i tekstury, które wykorzystują ten sam materiał.
- Opóźnij operacje animacji elementu do GPU.
- Wykonuj intensywniejsze usuwanie frustusu i okluzji.
- W miarę możliwości wykonuj operacje rysowania za pomocą interfejsu Vulkan API. wywołanie rysowania. na Vulkan.
Zużycie energii
Nawet po wprowadzeniu optymalizacji omówionych w poprzedniej sekcji możesz zauważysz, że liczba klatek na sekundę w grze pogarsza się w ciągu pierwszych 45-50 minut gry. Dodatkowo urządzenie może się nagrzewać i zużywać więcej energii baterii.
W wielu przypadkach taki niepożądany zestaw parametrów termicznych i zużycia energii jest związany z rozkładu zadań w grę na procesory urządzenia. Aby zwiększyć zużycie energii przez grę, zastosuj sprawdzone metody opisane na stronie poniższych sekcji.
Utrzymuj wątki zajmujące dużo pamięci na 1 CPU
W wielu urządzeniach mobilnych pamięci podręczne L1 znajdują się w konkretnych procesorach, a pamięci podręczne L2 są w zbiorze procesorów, które mają wspólny zegar. Aby zmaksymalizować trafienia w pamięci podręcznej L1, najlepiej jest zachować główny wątek gry i pozostałe wątki wymagające dużej ilości pamięci i działające na jednym procesorze.
Odrocz pracę krótkotrwałą dla procesorów o mniejszej mocy obliczeniowej
Większość silników gier, w tym Unity, ma informacje o opóźnianiu operacji wątków instancji roboczych na wybierze inne procesory niż w głównym wątku gry. Wyszukiwarka nie jest jednak specyficzna architektura urządzenia i nie jest w stanie przewidzieć, jak najwięcej zadań.
Większość urządzeń z układem SOC ma co najmniej 2 współdzielone zegary, jeden dla szybkich procesorów urządzenia i jeden dla wolnych procesorów. W konsekwencji jest to, że jeśli jeden szybki procesor musi działać z maksymalną prędkością, inne szybkie procesory działają z maksymalną prędkością.
Przykładowy raport na Rys. 4 pokazuje grę wykorzystującą procesory. Jednak tak wysoki poziom aktywności generuje mnóstwo energii i ciepła szybko.
Aby zmniejszyć ogólne zużycie energii, najlepiej zasugerować algorytmowi szeregowania, krótsza praca, na przykład wczytywanie dźwięku, uruchomione wątki instancji roboczych, wykonywania choreografa – zostanie odroczone do zestawu wolnych procesorów na urządzeniu. Przenieś jak najwięcej pracy na wolniejsze procesory, zachowując jednocześnie wybranej liczby klatek.
Większość urządzeń wymienia wolniejsze procesory przed tymi szybszymi, ale nie można zakładać, że protokół SOC Twojego urządzenia korzysta z tego zamówienia. Aby to sprawdzić, uruchom polecenia podobne do tych widoczne w tym wykrywaniu topologii procesora kod w GitHubie.
Gdy już się dowiesz, które procesory działają wolno na urządzeniu, możesz zadeklarować koligacje z wątkami krótkotrwałymi, które algorytm szeregowania urządzenia co dalej. Aby to zrobić, dodaj w każdym wątku ten kod:
#include <sched.h> #include <sys/types.h> #include <unistd.h> pid_t my_pid; // PID of the process containing your thread. // Assumes that cpu0, cpu1, cpu2, and cpu3 are the "slow CPUs". cpu_set_t my_cpu_set; CPU_ZERO(&my_cpu_set); CPU_SET(0, &my_cpu_set); CPU_SET(1, &my_cpu_set); CPU_SET(2, &my_cpu_set); CPU_SET(3, &my_cpu_set); sched_setaffinity(my_pid, sizeof(cpu_set_t), &my_cpu_set);
Naprężenie cieplne
Gdy urządzenia się nagrzeją, mogą spowalniać procesor lub GPU, co może prowadzić i w nieoczekiwany sposób. Gry ze złożoną grafiką, lub długotrwałą aktywność w sieci mogą napotkać problemy.
Używaj interfejsu The The API, aby monitorować zmiany temperatury na urządzeniu i podejmować odpowiednie działania, aby: utrzymywania niższego zużycia energii i niższej temperatury urządzenia. Gdy urządzenie zgłasza stres termiczny, odpocznij bieżące ćwiczenia, aby ograniczyć zużycie energii. Na przykład zmniejsz liczbę klatek na sekundę lub wielkość wielokąta.
Najpierw zadeklaruj obiekt PowerManager
zainicjować go w metodzie onCreate()
. Dodaj do obiektu detektor informacji o temperaturze.
Kotlin
class MainActivity : AppCompatActivity() { lateinit var powerManager: PowerManager override fun onCreate(savedInstanceState: Bundle?) { powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager powerManager.addThermalStatusListener(thermalListener) } }
Java
public class MainActivity extends AppCompatActivity { PowerManager powerManager; @Override protected void onCreate(Bundle savedInstanceState) { ... powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); powerManager.addThermalStatusListener(thermalListener); } }
Określ działania, które mają być wykonywane, gdy detektor wykryje stan
. Jeśli Twoja gra używa języka C/C++, dodaj kod do poziomów temperatury ciała w
onThermalStatusChanged()
, aby wywołać kod natywnej gry za pomocą JNI
lub użyj natywnego interfejsu Thermal API.
Kotlin
val thermalListener = object : PowerManager.OnThermalStatusChangedListener() { override fun onThermalStatusChanged(status: Int) { when (status) { PowerManager.THERMAL_STATUS_NONE -> { // No thermal status, so no action necessary } PowerManager.THERMAL_STATUS_LIGHT -> { // Add code to handle light thermal increase } PowerManager.THERMAL_STATUS_MODERATE -> { // Add code to handle moderate thermal increase } PowerManager.THERMAL_STATUS_SEVERE -> { // Add code to handle severe thermal increase } PowerManager.THERMAL_STATUS_CRITICAL -> { // Add code to handle critical thermal increase } PowerManager.THERMAL_STATUS_EMERGENCY -> { // Add code to handle emergency thermal increase } PowerManager.THERMAL_STATUS_SHUTDOWN -> { // Add code to handle immediate shutdown } } } }
Java
PowerManager.OnThermalStatusChangedListener thermalListener = new PowerManager.OnThermalStatusChangedListener () { @Override public void onThermalStatusChanged(int status) { switch (status) { case PowerManager.THERMAL_STATUS_NONE: // No thermal status, so no action necessary break; case PowerManager.THERMAL_STATUS_LIGHT: // Add code to handle light thermal increase break; case PowerManager.THERMAL_STATUS_MODERATE: // Add code to handle moderate thermal increase break; case PowerManager.THERMAL_STATUS_SEVERE: // Add code to handle severe thermal increase break; case PowerManager.THERMAL_STATUS_CRITICAL: // Add code to handle critical thermal increase break; case PowerManager.THERMAL_STATUS_EMERGENCY: // Add code to handle emergency thermal increase break; case PowerManager.THERMAL_STATUS_SHUTDOWN: // Add code to handle immediate shutdown break; } } };
Opóźnienie przy dotknięciu ekranu
gry, które jak najszybciej renderują klatki, tworzą scenariusz powiązany z GPU, w którym bufor ramki staje się przepełniony. Procesor musi poczekać na GPU, który powoduje zauważalne opóźnienie między danymi wpisywanymi przez gracza a danymi wejściowymi. efekt na ekranie.
Aby sprawdzić, czy można poprawić tempo klatek, wykonaj następujące kroki:
- Wygeneruj raport Systrace obejmujący kategorie
gfx
iinput
. Te kategorie obejmują szczególnie przydatne pomiary, które pozwalają określić czas oczekiwania przy dotknięciu ekranu. Zapoznaj się z sekcją
SurfaceView
w raporcie Systrace. przeciążony bufor. powoduje, że liczba oczekujących operacji pobierania z bufora oscyluje między 1 a 2, jak pokazano na ilustracji. na rys. 5.Rysunek 5. Raport Systrace pokazuje przeciążony bufor, okresowo zapełnia się, aby można było zaakceptować polecenia rysowania .
Aby ograniczyć tę niespójność w tempie klatek, wykonaj opisane działania. w następujących sekcjach:
Zintegruj ze swoją grą interfejs API Android Frame Pacing
Interfejs API Android Frame Pacing pomaga wykonywać zamianę klatek i określić interwał, tak aby gra bardziej stabilną liczbę klatek na sekundę.
Zmniejsz rozdzielczość zasobów gry niebędących interfejsem użytkownika
Wyświetlacze na nowoczesnych urządzeniach mobilnych zawierają znacznie więcej pikseli niż odtwarzacz więc można zmniejszyć próbkowanie tak, by 5- czy 10 pikseli zawiera jeden kolor. Ze względu na strukturę większości pamięci podręcznych wyświetlacza najlepiej zmniejsz rozdzielczość tylko w jednym wymiarze.
Nie zmniejsz jednak rozdzielczości elementów interfejsu w grze. To ważne aby zachować grubość linii tych elementów i wystarczająco duże rozmiar docelowego elementu dotykowego dla wszystkich Twoim graczom.
Płynność renderowania
Gdy SurfaceFlinger korzysta z bufora wyświetlacza, by pokazać scenę w grze, aktywność procesora od razu wzrasta. Jeśli występują te skoki aktywności procesora nierównomiernie, może wystąpić zacinanie się w grze. Schemat na rys. 6 wskazuje przyczynę tego zjawiska:
Jeśli klatka zacznie rysować się zbyt późno (nawet o kilka milisekund), kolejne okno wyświetlania. Ramka musi następnie czekać na (33 milisekundy w przypadku gry przy 30 kl./s), co powoduje zauważalnego opóźnienia z perspektywy gracza.
Aby rozwiązać ten problem, użyj funkcji Android Frame Pacing. API, który zawsze wyświetla nową klatkę w Fala VSync.
Stan pamięci
Jeśli grasz przez dłuższy czas, mogą wystąpić błędy braku pamięci.
W takiej sytuacji sprawdź aktywność procesora w raporcie Systrace i zobacz, jak często
system wywołuje demona kswapd
. Jeśli jest wiele połączeń
podczas wykonywania gry warto przyjrzeć się bliżej temu,
zarządza i czyści pamięć.
Więcej informacji znajdziesz w artykule Efektywne zarządzanie pamięcią w grach.
Stan wątku
Podczas poruszania się po typowych elementach raportu Systrace możesz zobaczyć czas, jaki dany wątek spędził w każdym możliwym wątku stanu, wybierając w wątku, co widać na rys. 7:
Jak widać na Rysunku 7, wątki dotyczące gry nie znajdują się "bieganie" lub „możliwe do uruchomienia” tak często, jak powinno. Poniższa lista wskazuje kilka typowych przyczyn, dla których dany wątek może być okresowo wyświetlany przejście w nietypowy stan:
- Jeśli wątek jest uśpiony przez dłuższy czas, może to być przyczyną uciążliwości przed rywalizacją o blokadę lub oczekiwaniem na aktywność GPU.
- Jeśli wątek jest stale blokowany podczas I/O, albo odczytujesz za dużo danych z dysku naraz, lub gra nie jest wydajna.
Dodatkowe materiały
Aby dowiedzieć się więcej o poprawianiu wydajności gry, przeczytaj te artykuły dodatkowe materiały:
Filmy
- Prezentacja Systrace for Games z Android Game Developer Summit 2018