Performance Hint API

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">
</ph> Verhalten des Linux-Planers
Abbildung 1: Der Governor kann ca. 200 ms benötigen, um die CPU-Frequenz zu erhöhen oder zu verringern. ADPF arbeitet mit dem Dynamic Voltage and Frequency Scaling System (DVFS) zusammen, um die beste Leistung pro Watt zu erzielen.

Die PerformanceHint API abstrahiert mehr als DVFS-Latenzen

<ph type="x-smartling-placeholder">
</ph> ADPF-Zusammenfassungen mehr als DVFS-Latenzen
Abbildung 2: Das ADPF-Team weiß, wie man die beste Entscheidung für Sie trifft.
<ph type="x-smartling-placeholder">
    </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:

  1. 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>
      1. In Cocos erhalten der Haupt-Engine-Thread und der Rendering-Thread einen Sitzung
      2. Binden Sie in Unity das Adaptive Performance Android Provider-Plug-in ein.
      3. 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
  2. Das Spiel sollte dies frühzeitig tun, mindestens 2 ms und vorzugsweise mehr als 4 ms. bevor eine Sitzung mehr Systemressourcen benötigt.
  3. 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);