Veröffentlicht:
Android 12 (API-Level 31) – Performance Hint API
Android 13 (API-Level 33) – Performance Hint Manager in der NDK API
(Vorabversion) Android 15 (DP1) – reportActualWorkDuration()
Mit Hinweisen zur CPU-Leistung kann ein Spiel die dynamische CPU-Leistung beeinflussen besser an die Anforderungen angepasst werden. Auf den meisten Geräten passt Android CPU-Taktgeschwindigkeit und Kerntyp für eine Arbeitslast basierend auf den vorherigen Anforderungen. Wenn eine Arbeitslast mehr CPU-Ressourcen nutzt, erhöht sich die Taktgeschwindigkeit auf einen größeren Kern verschoben. Wenn die Arbeitslast weniger senkt Android die Ressourcenzuweisung. Mit ADPF wird die Anwendung oder Spiel ein zusätzliches Signal zu seiner Leistung und zu Fristen senden kann. Dieses kann das System stärker ansteigen (was die Leistung verbessert) und wird schnell erfasst, wenn die Arbeitslast abgeschlossen ist (Einsparungen beim Stromverbrauch).
Taktgeschwindigkeit
Wenn Android-Geräte die CPU-Taktgeschwindigkeit dynamisch anpassen, kann die Frequenz
die Leistung Ihres Codes ändern. Code für die dynamische Uhr entwerfen
Geschwindigkeit ist wichtig für die Leistungsmaximierung und die Aufrechterhaltung eines sicheren
und Energie effizient nutzen. Sie können CPU-Frequenzen nicht direkt zuweisen
in Ihrem App-Code. Daher ist es üblich, Apps mit einer höheren
CPU-Taktgeschwindigkeiten besteht in der Ausführung einer Belastungsschleife in einem Hintergrundthread, damit die Arbeitslast
etwas anspruchsvoller erscheint. Das ist nicht sinnvoll, da dadurch Strom verschwendet
die thermische Belastung des Geräts, wenn die App die zusätzliche
Ressourcen. Die CPU PerformanceHint
API wurde für dieses Problem entwickelt. Von
dem System die tatsächliche
Arbeitsdauer und die angestrebte Dauer
Android kann sich einen Überblick
über den CPU-Bedarf der App verschaffen und
effizient Ressourcen zu schaffen. Dies führt zu einer optimalen Leistung bei effizienter Energieversorgung
des Verbrauchs.
Kerntypen
Die CPU-Kerntypen, auf denen Ihr Spiel läuft, sind eine weitere wichtige Leistung Faktor. Android-Geräte ändern häufig den einem Thread zugewiesenen CPU-Kern auf Basis des aktuellen Arbeitslastverhaltens. Die Zuweisung von CPU-Kernen ist noch auf SoCs mit mehreren Kerntypen. Auf einigen dieser Geräte ist der größere Kerne nur kurz verwendet werden, ohne dass dies zu einem thermischen Bundesstaat.
Aus den folgenden Gründen sollte in Ihrem Spiel nicht versucht werden, die CPU-Kernaffinität festzulegen:
- Der beste Kerntyp für eine Arbeitslast variiert je nach Gerätemodell.
- Die Nachhaltigkeit der Ausführung größerer Kerne variiert je nach SoC und verschiedenen Wärmelösungen für jedes Gerätemodell.
- Die Umweltauswirkungen auf den Wärmezustand können Kerne eine große Auswahl. Beispielsweise kann sich das Wetter oder die Schutzhülle des Smartphones den Temperaturzustand verändern eines Geräts.
- Die Hauptauswahl ermöglicht keine neuen Geräte mit zusätzlicher Leistung und Schutz vor Überhitzung. Der Prozessor eines Spiels wird deshalb häufig von den Geräten ignoriert. Affinität.
Beispiel für das Standardverhalten des Linux-Planers
<ph type="x-smartling-placeholder">![Verhalten des Linux-Planers](https://developer.android.com/static/games/optimize/adpf/images/adpf_linux_sched_behavior.png?authuser=0&hl=de)
Die PerformanceHint API abstrahiert mehr als DVFS-Latenzen
<ph type="x-smartling-placeholder">![ADPF-Zusammenfassungen mehr als DVFS-Latenzen](https://developer.android.com/static/games/optimize/adpf/images/adpf_dvfs_latency.png?authuser=0&hl=de)
- </ph>
- Wenn die Aufgaben auf einer bestimmten CPU ausgeführt werden müssen, weiß die PerformanceHint API, wie diese Entscheidung in Ihrem Namen zu treffen.
- Daher müssen Sie keine Affinität verwenden.
- Die Geräte haben verschiedene Topologien: Leistungs- und thermische Eigenschaften sind zu vielfältig, um dem App-Entwickler zu begegnen.
- Sie können keine Annahmen über das zugrunde liegende System treffen, auf dem Sie arbeiten.
Lösung
Das ADPF stellt die PerformanceHintManager
bereit.
damit Spiele Leistungshinweise an Android senden,
um die CPU-Taktgeschwindigkeit und
Kerntyp verwendet werden. Das Betriebssystem kann dann entscheiden, wie die Hinweise
auf Grundlage des SoC und
Wärmelösung des Geräts. Wenn deine App diese API zusammen mit Wärmepumpen verwendet
Statusüberwachung angezeigt wird, kann es dem Betriebssystem fundiertere Hinweise liefern, anstatt
und andere Codierungstechniken,
die eine Drosselung verursachen können.
So werden Leistungshinweise für Spiele verwendet:
- Hinweissitzungen für wichtige Threads erstellen, die sich ähnlich verhalten. Hier einige Beispiele:
<ph type="x-smartling-placeholder">
- </ph>
- Rendering-Thread und seine Abhängigkeiten erhalten eine Sitzung
<ph type="x-smartling-placeholder">
- </ph>
- In Cocos erhalten der Haupt-Engine-Thread und der Rendering-Thread einen Sitzung
- Binden Sie in Unity das Adaptive Performance Android Provider-Plug-in ein.
- Binden Sie in Unreal das Unreal Adaptive Performance-Plug-in ein und verwenden Sie Skalierbarkeitsoptionen zur Unterstützung mehrerer Qualitätsstufen
- E/A-Threads erhalten eine weitere Sitzung
- Audiothreads erhalten eine dritte Sitzung
- Rendering-Thread und seine Abhängigkeiten erhalten eine Sitzung
<ph type="x-smartling-placeholder">
- Das Spiel sollte dies frühzeitig tun, mindestens 2 ms und vorzugsweise mehr als 4 ms. bevor eine Sitzung mehr Systemressourcen benötigt.
- Prognostizieren Sie bei jeder Hinweissitzung die für jede Sitzung erforderliche Dauer. Die typische Dauer entspricht einem Frameintervall, die App kann jedoch einen kürzere Intervalle, wenn die Arbeitslast in den einzelnen Frames nicht wesentlich variiert.
So setzen Sie die Theorie in die Praxis um:
PerformanceHintManager und createHintSession initialisieren
Manager über den Systemdienst abrufen und eine Hinweissitzung für den Thread erstellen Thread-Gruppe, die mit derselben Arbeitslast arbeitet.
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);
Bei Bedarf Threads festlegen
Veröffentlicht:
Android 11 (API-Level 34)
Verwenden Sie den setThreads
.
von PerformanceHintManager.Session
, wenn es andere Threads gibt
die später hinzugefügt werden müssen. Wenn Sie z. B. Ihren Physik-Thread erstellen,
und der Sitzung hinzufügen möchten, können Sie diese setThreads
API verwenden.
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);
Wenn Sie niedrigere API-Levels anvisieren, müssen Sie die Sitzung löschen und erstellen Sie jedes Mal eine neue Sitzung, wenn Sie die Thread-IDs ändern müssen.
Tatsächliche Arbeitsdauer melden
Verfolgen Sie die Dauer in Nanosekunden und erstellen Sie einen Bericht nach Abschluss der Arbeit in jedem Zyklus an das System übertragen. Wenn beispielsweise Dies ist für Ihre Rendering-Threads. Rufen Sie dies auf jedem Frame auf.
Um die tatsächliche Zeit zuverlässig zu ermitteln, verwenden Sie:
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();
Beispiel:
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);
Zielarbeitsdauer bei Bedarf aktualisieren
Wenn sich Ihre angestrebte Arbeitsdauer ändert, z. B. wenn der Spieler eine
unterschiedliche Ziel-fps verwenden, rufen Sie die Methode updateTargetWorkDuration
auf,
Methode, um das System zu informieren, damit das Betriebssystem die Ressourcen entsprechend anpassen kann.
mit dem neuen Ziel. Sie müssen es nicht in jedem Frame aufrufen,
wenn sich die Zieldauer ändert.
C++
APerformanceHint_updateTargetWorkDuration(hint_session, target_duration);
Java
hintSession.updateTargetWorkDuration(targetDuration);