Data wydania:
Android 12 (poziom API 31) – interfejs Performance Hint API
Android 13 (poziom API 33) – menedżer wskazówek dotyczących wydajności w interfejsie NDK API
(Wersja testowa) Android 15 (DP1) – reportActualWorkDuration()
Dzięki wskazówkom dotyczącym wydajności procesora gra może wpływać na dynamiczne działanie procesora zachowanie, które lepiej pasuje do potrzeb. Na większości urządzeń Android dynamicznie dostosowuje taktowanie procesora oraz typ rdzeni zadania na podstawie poprzednich żądań. Jeśli zadanie używa większej liczby zasobów procesora, taktowanie jest zwiększone, a zadanie zostanie ostatecznie przeniesione do większego rdzenia. Jeśli zbiór zadań używa mniej zasobów, Android zmniejsza przydział zasobów. Dzięki ADPF aplikacja lub gra może wysłać dodatkowy sygnał dotyczący jej wyników i terminów. Ten sprawia, że system intensywniej przyspiesza (poprawia wydajność) i obniża szybko uruchamiają się po zakończeniu zadania (co pozwala zmniejszyć zużycie energii).
Taktowanie zegara
Gdy urządzenia z Androidem dynamicznie dostosowują taktowanie taktowania procesora, częstotliwość może
żeby zmienić wydajność kodu. Projektowanie kodu odpowiadającego zegarowi dynamicznemu
prędkości jest ważne dla maksymalizacji wydajności, utrzymania bezpiecznej temperatury
i wydajne korzystanie z energii. Nie możesz bezpośrednio przypisać częstotliwości procesora
w kodzie aplikacji. W efekcie aplikacje często próbują uruchamiać
Częstotliwość taktowania procesora polega na uruchomieniu pętli zajętej w wątku w tle,
i wydaje się bardziej wymagające. Nie jest to zła praktyka, ponieważ zużywa energię i zwiększa
obciążenie cieplne urządzenia, gdy aplikacja nie używa dodatkowej
i zasobami Google Cloud. Interfejs CPU PerformanceHint
API został zaprojektowany do rozwiązania tego problemu. Według
informowanie systemu o rzeczywistym czasie trwania i docelowym czasie trwania pracy,
Android będzie mógł uzyskać informacje o potrzebach aplikacji w zakresie CPU i przydzielić
i skuteczne wykorzystanie zasobów. Pozwala to uzyskać optymalną wydajność przy wydajnym zasilaniu.
poziomu konsumpcji.
Typy podstawowe
Rodzaje rdzeni procesora, na których działa gra, to kolejna ważna wydajność współczynnik konwersji. Urządzenia z Androidem często zmieniają rdzeń procesora przypisany do wątku na podstawie najnowszego zachowania zbioru zadań. Przypisanie rdzeni procesora jest jeszcze większe układy SOC z kilkoma typami rdzeni. Na niektórych z tych urządzeń rdzenie mogą być używane tylko przez krótki czas, bez wykorzystania termicznych urządzeń stanu.
Gra nie powinna próbować ustawiać głównej koligacji procesora z tych powodów:
- Najlepszy typ rdzeni dla zadania różni się w zależności od modelu urządzenia.
- Zrównoważony rozwój większych rdzeni zależy od układu SOC i różnych rozwiązania termiczne dostępne w poszczególnych modelach urządzeń.
- Wpływ na środowisko na temperaturę termiczne może dodatkowo komplikować rdzeń wyboru. Na przykład pogoda lub etui na telefon może zmienić stan temperatury. urządzenia.
- Wybrane podstawowe funkcje nie obsługują nowych urządzeń o większej wydajności, właściwości termiczne. W związku z tym urządzenia często ignorują procesor gry. o podobnych zainteresowaniach.
Przykład domyślnego działania algorytmu szeregowania w systemie Linux
![Działanie algorytmu szeregowania w systemie Linux](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_linux_sched_behavior.png?authuser=8&hl=pl)
Interfejs PerformanceHint API pobiera więcej czasu niż czas oczekiwania w DVFS
![Abstrakcje ADPF są większe niż opóźnienia w DVFS](https://developer.android.google.cn/static/games/optimize/adpf/images/adpf_dvfs_latency.png?authuser=8&hl=pl)
- Jeśli zadania muszą działać na określonym procesorze, interfejs PerformanceHint API wie, jak podjąć decyzję w Twoim imieniu.
- Nie musisz więc korzystać z podobnych zainteresowań.
- Urządzenia mają różne topologie. Cechy mocy i temperatury zbyt zróżnicowane, by pokazać je deweloperowi.
- Nie możesz zakładać żadnych założeń dotyczących systemu, w którym działasz.
Rozwiązanie
ADPF udostępnia PerformanceHintManager
aby gry mogły wysyłać do Androida wskazówki dotyczące wydajności, aby uzyskać
typ rdzenia. Dzięki temu system operacyjny może zdecydować, jak najlepiej wykorzystać wskazówki na podstawie układu SOC,
roztworu termicznego urządzenia. Jeśli Twoja aplikacja korzysta zarówno z tego interfejsu API, jak i z Term
stanu monitorowania, może przekazać
systemowi operacyjnemu bardziej świadome wskazówki, zamiast używać
zajęte pętle i inne techniki kodowania, które mogą powodować ograniczanie przepustowości.
Oto jak gra wykorzystuje wskazówki dotyczące wydajności:
- Utwórz sesje wskazówek dla głównych wątków, które zachowują się podobnie. Na przykład:
- Wątek renderowania i jego zależności otrzymują 1 sesję
- W Cocos główny wątek silnika i wątek renderowania otrzymują jeden sesja
- Zintegruj w Unity wtyczkę dostawcy Androida Adaptive Performance
- W Unreal zintegruj wtyczkę Unreal Adaptive Performance i zastosuj Opcje skalowalności umożliwiające obsługę wielu poziomów jakości.
- Wątki zamówienia reklamowego otrzymują kolejną sesję
- Wątki audio otrzymują 3 sesję
- Wątek renderowania i jego zależności otrzymują 1 sesję
- Gra powinna to zrobić wcześnie, co najmniej 2 ms, a najlepiej więcej niż 4 ms. przed rozpoczęciem sesji należy zwiększyć zasoby systemowe.
- W przypadku każdej sesji podpowiedzi przewiduj czas jej trwania. Typowy czas trwania jest odpowiednikiem interwału klatek, ale aplikacja może użyć funkcji jeśli zbiór zadań nie różni się znacznie między klatkami, a krótszy odstęp czasu.
Jak zastosować teorię w praktyce:
Inicjowanie PerformanceHintManager i createHintSession
Pobierz menedżera za pomocą usługi systemowej i utwórz sesję podpowiedzi dotyczącą wątku lub grupę wątków działającą na tym samym zadaniu.
C++
int32_t tids[1];
tids[0] = gettid();
int64_t target_fps_nanos = getFpsNanos();
APerformanceHintManager* hint_manager = APerformanceHint_getManager();
APerformanceHintSession* hint_session =
APerformanceHint_createSession(hint_manager, tids, 1, target_fps_nanos);
Java
int[] tids = {
android.os.Process.myTid()
};
long targetFpsNanos = getFpsNanos();
PerformanceHintManager performanceHintManager =
(PerformanceHintManager) this.getSystemService(Context.PERFORMANCE_HINT_SERVICE);
PerformanceHintManager.Session hintSession =
performanceHintManager.createHintSession(tids, targetFpsNanos);
W razie potrzeby ustaw wątki
Data wydania:
Android 11 (poziom API 34)
Korzystanie z setThreads
funkcji PerformanceHintManager.Session
, gdy masz inne wątki
które trzeba dodać później. Jeśli na przykład utworzysz wątek fizyki,
gdy zechcesz dodać go do sesji, możesz użyć tego interfejsu API setThreads
.
C++
auto tids = thread_ids.data();
std::size_t size = thread_ids_.size();
APerformanceHint_setThreads(hint_session, tids, size);
Java
int[] tids = new int[3];
// add all your thread IDs. Remember to use android.os.Process.myTid() as that
// is the linux native thread-id.
// Thread.currentThread().getId() will not work because it is jvm's thread-id.
hintSession.setThreads(tids);
Jeśli kierujesz reklamy na niższe poziomy interfejsu API, musisz zniszczyć sesję i za każdym razem, gdy chcesz zmienić identyfikatory wątków, twórz nową sesję.
Raportuj rzeczywisty czas trwania pracy
Możesz śledzić w nanosekundach rzeczywisty czas potrzebny do ukończenia pracy i generować raporty jest przesyłane do systemu po zakończeniu pracy w każdym cyklu. Na przykład, jeśli dla wątków renderowania. Wywołuj go w każdej klatce.
Aby uzyskać dokładny czas, użyj:
C++
clock_gettime(CLOCK_MONOTONIC, &clock); // if you prefer "C" way from <time.h>
// or
std::chrono::high_resolution_clock::now(); // if you prefer "C++" way from <chrono>
Java
System.nanoTime();
Na przykład:
C++
// All timings should be from `std::chrono::steady_clock` or `clock_gettime(CLOCK_MONOTONIC, ...)`
auto start_time = std::chrono::high_resolution_clock::now();
// do work
auto end_time = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count();
int64_t actual_duration = static_cast<int64_t>(duration);
APerformanceHint_reportActualWorkDuration(hint_session, actual_duration);
Java
long startTime = System.nanoTime();
// do work
long endTime = System.nanoTime();
long duration = endTime - startTime;
hintSession.reportActualWorkDuration(duration);
W razie potrzeby zaktualizuj docelowy czas pracy
Gdy zmienia się docelowy czas trwania pracy, na przykład jeśli gracz wybierze
dla różnych docelowych klatek na sekundę, wywołaj funkcję updateTargetWorkDuration
jest metoda informowania systemu, dzięki czemu
system operacyjny może dostosować zasoby
na nową wartość docelową. Nie musisz wywoływać tej funkcji za każdym razem – wystarczy
gdy zmieni się docelowy czas trwania.
C++
APerformanceHint_updateTargetWorkDuration(hint_session, target_duration);
Java
hintSession.updateTargetWorkDuration(targetDuration);