API Thermal

Uscita:

Android 11 (livello API 30) - API Thermal

Android 12 (livello API 31) - API NDK

(Anteprima) Android 15 (DP1) - getThermalHeadroomThresholds()

Le prestazioni potenziali della tua app sono limitate dallo stato termico del dispositivo, che può variare in base a caratteristiche quali meteo, utilizzo recente e design termico del dispositivo. I dispositivi possono mantenere un livello di prestazioni elevato solo per un periodo di tempo limitato prima di essere limitati termicamente. Un obiettivo chiave dell'implementazione dovrebbe essere il raggiungimento degli obiettivi di prestazioni senza superare i limiti termici. l'API Thermal permette di farlo senza ottimizzazioni specifiche per i dispositivi. Inoltre, durante il debug dei problemi di prestazioni, è importante sapere se lo stato termico del dispositivo limita le prestazioni. Inoltre, durante il debug dei problemi di prestazioni, è importante sapere se lo stato termico del dispositivo limita le prestazioni.

In genere i motori di gioco hanno parametri di prestazioni di runtime che possono regolare il carico di lavoro applicato dal motore al dispositivo. Ad esempio, questi parametri possono impostare il numero di thread worker, l'affinità dei thread worker per i core grandi e piccoli, le opzioni di fedeltà GPU e le risoluzioni del framebuffer. In Unity Engine, gli sviluppatori di giochi possono regolare il carico di lavoro modificando le Impostazioni qualità utilizzando il plug-in Adaptive Performance. Per Unreal Engine, utilizza Impostazioni di scalabilità per regolare i livelli qualitativi in modo dinamico.

Quando un dispositivo si avvicina a uno stato termico non sicuro, il gioco può evitare di essere limitato riducendo il carico di lavoro attraverso questi parametri. Per evitare la limitazione, devi monitorare lo stato termico del dispositivo e regolare proattivamente il carico di lavoro del motore grafico. Quando il dispositivo si surriscalda, per dissipare il calore il carico di lavoro deve scendere al di sotto del livello di prestazioni sostenibili. Quando il margine termico scende a livelli più sicuri, il gioco può aumentare di nuovo le impostazioni di qualità, ma assicurarsi di trovare un livello di qualità sostenibile per un tempo di gioco ottimale.

Puoi monitorare lo stato termico del dispositivo eseguendo il polling del metodo getThermalHeadroom. Questo metodo prevede per quanto tempo il dispositivo potrà mantenere il livello di prestazioni attuale senza surriscaldarsi. Se il tempo è inferiore all'importo necessario per eseguire il carico di lavoro, il gioco dovrebbe ridurre il carico di lavoro a un livello sostenibile. Ad esempio, il gioco può passare a core più piccoli, ridurre la frequenza fotogrammi o la fedeltà.

Pre-integrazione dell'API ADPF Thermal
Figura 1. Margine termico senza monitorare attivamente getThermalHeadroom
Post-integrazione dell'API ADPF Thermal
Figura 2. Margine termico con monitoraggio attivo di "getThermalHeadroom"

Acquisisci gestore termico

Per utilizzare l'API Thermal, devi prima acquisire Thermal Manager

C++

AThermalManager* thermal_manager = AThermal_acquireManager();

Java

PowerManager powerManager = (PowerManager)this.getSystemService(Context.POWER_SERVICE);

Per un maggiore controllo, prevedi il margine termico a x secondi di anticipo

Puoi chiedere al sistema di prevedere la temperatura x secondi prima del carico di lavoro attuale. In questo modo avrai un controllo più granulare e più tempo per reagire, riducendo il carico di lavoro per evitare l'attivazione della limitazione termica.

Il risultato va da 0,0 f (nessuna limitazione, THERMAL_STATUS_NONE) a 1,0 f (limitata eccessiva, THERMAL_STATUS_SEVERE). Se hai livelli di qualità grafica diversi nei tuoi giochi, puoi seguire le nostre linee guida relative al margine termico.

C++

float thermal_headroom = AThermal_getThermalHeadroom(10);
ALOGI("ThermalHeadroom in 10 sec: %f", thermal_headroom);

Java

float thermalHeadroom = powerManager.getThermalHeadroom(10);
Log.d("ADPF", "ThermalHeadroom in 10 sec: " + thermalHeadroom);

In alternativa, affidati allo stato termico per maggiore chiarezza

Ogni modello di dispositivo può essere progettato in modo diverso. Alcuni dispositivi potrebbero essere in grado di distribuire meglio il calore e quindi di resistere a un margine termico più elevato prima di essere limitati. Se vuoi leggere un raggruppamento semplificato di intervalli di intervalli termici, puoi controllare lo stato termico per comprendere il valore di margine termico sul dispositivo attuale.

C++

AThermalStatus thermal_status = AThermal_getCurrentThermalStatus(thermal_manager);
ALOGI("ThermalStatus is: %d", thermal_status);

Java

int thermalStatus = powerManager.getCurrentThermalStatus();
Log.d("ADPF", "ThermalStatus is: " + thermalStatus);

Ricevi una notifica quando cambia lo stato termico

Puoi anche evitare di eseguire il polling di thermalHeadroom fino a quando thermalStatus non raggiunge un determinato livello (ad esempio: THERMAL_STATUS_LIGHT). Per farlo, puoi registrare un callback per consentire al sistema di inviarti una notifica ogni volta che lo stato cambia.

C++

int result = AThermal_registerThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether you have previously registered callback that
  // hasn’t been unregistered
}

Java

// PowerManager.OnThermalStatusChangedListener is an interface, thus you can
// also define a class that implements the methods
PowerManager.OnThermalStatusChangedListener listener = new
  PowerManager.OnThermalStatusChangedListener() {
    @Override
    public void onThermalStatusChanged(int status) {
        Log.d("ADPF", "ThermalStatus changed: " + status);
        // check the status and flip the flag to start/stop pooling when
        // applicable
    }
};
powerManager.addThermalStatusListener(listener);

Al termine, ricordati di rimuovere il listener

C++

int result = AThermal_unregisterThermalStatusListener(thermal_manager, callback);
if ( result != 0 ) {
  // failed, check whether the callback has been registered previously
}

Java

powerManager.removeThermalStatusListener(listener);

Pulizia

Al termine, dovrai ripulire il termico manager che hai acquisito. Se utilizzi Java, il riferimento di PowerManager può essere eliminato automaticamente. Tuttavia, se utilizzi l'API Java tramite JNI e hai conservato un riferimento, ricordati di ripulire il riferimento.

C++

AThermal_releaseManager(thermal_manager);

Per una guida completa su come implementare l'API Thermal in un gioco C++ nativo utilizzando sia l'API C++ (API NDK) che l'API Java (tramite JNI), consulta la sezione API Thermal integrata nella sezione Codelab sull'adattabilità.

Linee guida per il margine termico

Puoi monitorare lo stato termico del dispositivo eseguendo il polling del metodo getThermalHeadroom. Questo metodo prevede per quanto tempo il dispositivo potrà mantenere il livello di prestazioni attuale prima di raggiungere THERMAL_STATUS_SEVERE. Ad esempio, se getThermalHeadroom(30) restituisce 0,8, significa che entro 30 secondi il margine di miglioramento dovrebbe raggiungere 0,8, ovvero 1,0, a una distanza di 0,2 da una limitazione grave. Se il tempo è inferiore alla quantità necessaria per eseguire il carico di lavoro, il gioco dovrebbe ridurre il carico di lavoro a un livello sostenibile. Ad esempio, il gioco può ridurre la frequenza fotogrammi, la fedeltà o ridurre il lavoro di connettività di rete.

Stati termici e significato

Limitazioni dei dispositivi dell'API Thermal

Esistono alcune limitazioni note o requisiti aggiuntivi dell'API Thermal dovuti alle implementazioni dell'API termica su dispositivi meno recenti. Di seguito sono riportate le limitazioni e le relative soluzioni:

  • Non chiamare l'API GetThermalHeadroom() troppo spesso. In questo modo, l'API restituirà NaN. Dovresti chiamarla al massimo una volta al secondo.
  • Se il valore iniziale di GetThermalHeadroom() è NaN, l'API non è disponibile sul dispositivo
  • Se GetThermalHeadroom() restituisce un valore alto (ad es. 0,85 o più) e GetCurrentThermalStatus() restituisce comunque THERMAL_STATUS_NONE, è probabile che lo stato non venga aggiornato. Utilizza l'euristica per stimare lo stato di limitazione termica corretto oppure utilizza semplicemente getThermalHeadroom() senza getCurrentThermalStatus().

Esempio di euristica:

  1. Verifica che l'API Thermal sia supportata. isAPISupported() controlla il valore della prima chiamata a getThermalHeadroom per assicurarsi che non sia 0 o NaN e ignora l'utilizzo dell'API se il primo valore è 0 o NaN.
  2. Se getCurrentThermalStatus() restituisce un valore diverso da THERMAL_STATUS_NONE, il dispositivo viene limitato termicamente.
  3. Se getCurrentThermalStatus() continua a restituire THERMAL_STATUS_NONE, non significa necessariamente che il dispositivo non sia sottoposto a una limitazione termica. Questo potrebbe significare che getCurrentThermalStatus() non è supportato sul dispositivo. Controlla il valore restituito di getThermalHeadroom() per verificare la condizione del dispositivo.
  4. Se getThermalHeadroom() restituisce un valore maggiore di 1,0, lo stato potrebbe essere effettivamente THERMAL_STATUS_SEVERE o superiore, ridurre immediatamente il carico di lavoro e mantenere un carico di lavoro inferiore fino a quando getThermalHeadroom() restituisce un valore inferiore
  5. Se getThermalHeadroom() restituisce un valore pari a 0,95, lo stato potrebbe effettivamente essere THERMAL_STATUS_MODERATE o superiore, riduci immediatamente il carico di lavoro e tieni d'occhio l'attenzione per evitare letture maggiori
  6. Se getThermalHeadroom() restituisce un valore pari a 0,85, lo stato potrebbe essere in realtà THERMAL_STATUS_LIGHT; mantieni il controllo e, se possibile, riduci il carico di lavoro

Pseudocodice:

  bool isAPISupported() {
    float first_value_of_thermal_headroom = getThermalHeadroom();
    if ( first_value_of_thermal_headroom == 0 ||
      first_value_of_thermal_headroom == NaN ) {
        // Checked the thermal Headroom API's initial return value
        // it is NaN or 0,so, return false (not supported)
        return false;
    }
    return true;
  }
  
  if (!isAPISupported()) {
    // Checked the thermal Headroom API's initial return value, it is NaN or 0
    // Don’t use the API
  } else {
      // Use thermalStatus API to check if it returns valid values.
      if (getCurrentThermalStatus() > THERMAL_STATUS_NONE) {
          // The device IS being thermally throttled
      } else {
      // The device is not being thermally throttled currently. However, it
      // could also be an indicator that the ThermalStatus API may not be
      // supported in the device.
      // Currently this API uses predefined threshold values for thermal status
      // mapping. In the future  you may be able to query this directly.
      float thermal_headroom = getThermalHeadroom();
      if ( thermal_headroom > 1.0) {
            // The device COULD be severely throttled.
      } else  if ( thermal_headroom > 0.95) {
            // The device COULD be moderately throttled.
      } else if ( thermal_headroom > 0.85) {
            // The device COULD be experiencing light throttling.
      }
    }
  }

Diagramma:

Esempio euristico ADPF
Figura 3.Esempio di euristica per determinare il supporto dell'API Thermal sui dispositivi meno recenti