Configura tracciamento di sistema

Puoi configurare il tracciamento del sistema per acquisire un Profilo di CPU e thread della tua app in un breve periodo di tempo. Poi puoi utilizzare il report di output da una traccia di sistema per migliorare le prestazioni dei dispositivi.

Configura una traccia di sistema basata sul gioco

Lo strumento Systrace è disponibile in due modi:

Systrace è uno strumento di basso livello che:

  • Fornisce dati di fatto. Systrace acquisisce l'output direttamente dal kernel, in modo che le metriche acquisite siano quasi identiche a quelle rilevate da una serie le chiamate di sistema registreranno.
  • Consuma poche risorse. Systrace presenta un overhead molto basso sulla solitamente inferiore all'1% perché trasmette i flussi di dati in un buffer in memoria.

Impostazioni ottimali

È importante assegnare allo strumento un insieme ragionevole di argomenti:

  • Categorie:l'insieme migliore di categorie da attivare per un sistema basato su giochi. le tracce sono: {sched, freq, idle, am, wm, gfx, view, sync, binder_driver, hal, dalvik}.
  • Dimensione del buffer: una regola generale prevede una dimensione del buffer di 10 MB per core CPU consente una traccia di circa 20 secondi. Ad esempio, se un dispositivo ha un due CPU quad-core (8 core in totale), un valore appropriato da passare Il programma systrace ha una dimensione di 80.000 kB (80 MB).

    Se il cambio di contesto cambia spesso, aumenta il buffer a 15 MB per core CPU.

  • Eventi personalizzati: se definisci eventi personalizzati eventi da acquisire nel gioco, attiva il flag -a, che consente a Systrace di includere questi eventi personalizzati nel di output.

Se utilizzi la riga di comando systrace usa questo comando per acquisire una traccia di sistema che applica le best practice per l'insieme di categorie, il buffer dimensioni ed eventi personalizzati:

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

Se utilizzi l'app di sistema Systrace su un dispositivo, completa i seguenti passaggi acquisire una traccia di sistema che applica le best practice per la serie di categorie, il buffer dimensioni ed eventi personalizzati:

  1. Attiva l'opzione Trace di cui è possibile eseguire il debug.

    A questa impostazione, il dispositivo deve avere a disposizione 256 MB o 512 MB (a seconda la CPU ha 4 o 8 core) e ogni pezzo di memoria da 64 MB deve disponibile come blocco contiguo.

  2. Scegli Categorie, poi attiva le categorie nel seguente elenco:

    • am: Gestore attività
    • binder_driver: driver del kernel Binder
    • dalvik: Dalvik VM
    • freq: frequenza CPU
    • gfx: immagini
    • hal: moduli hardware
    • idle: CPU inattiva
    • sched: pianificazione della CPU
    • sync: sincronizzazione
    • view: visualizza sistema
    • wm: gestore finestre
  3. Attiva il tracciamento dei record.

  4. Carica il gioco.

  5. Eseguire nel gioco le interazioni corrispondenti al gameplay la cui le prestazioni del dispositivo che vuoi misurare.

  6. Poco dopo aver riscontrato un comportamento indesiderato nel gioco, attiva il sistema il tracciamento.

Hai acquisito le statistiche sul rendimento necessarie per analizzare ulteriormente il problema.

Per risparmiare spazio su disco, le tracce del sistema sul dispositivo salvano i file in una traccia compressa (*.ctrace). Per decomprimere questo file durante la generazione di un report, utilizza la classe a riga di comando e includi l'opzione --from-file:

python systrace.py --from-file=/data/local/traces/my_game_trace.ctrace \
  -o my_systrace_report.html

Migliorare aree specifiche di rendimento

Questa sezione evidenzia diversi problemi di prestazioni comuni relativi ai giochi mobile. descrive come identificare e migliorare questi aspetti del tuo gioco.

Velocità di caricamento

I giocatori vogliono entrare in azione il più velocemente possibile, quindi sono importanti per migliorare quanto più possibile i tempi di caricamento del tuo gioco. Le seguenti di solito aiutano i tempi di caricamento:

  • Esegui il caricamento lento. Se utilizzi gli stessi asset per più asset scene o livelli nel gioco, carica questi asset una sola volta.
  • Riduci le dimensioni degli asset. In questo modo, puoi raggruppare i file di queste risorse con l'APK del tuo gioco.
  • Utilizza un metodo di compressione efficiente su disco. Un esempio di questo metodo è zlib.
  • Utilizza IL2CPP anziché in formato mono. Si applica solo se utilizzi Unity. IL2CPP offre le prestazioni di esecuzione dei tuoi script C#.
  • Trasforma il tuo gioco in multithread. Per ulteriori dettagli, vedi la frequenza fotogrammi e coerenza.

Coerenza della frequenza fotogrammi

Uno degli elementi più importanti dell'esperienza di gameplay è ottenere una una frequenza fotogrammi più elevata. Per facilitare il raggiungimento di questo obiettivo, segui le tecniche di ottimizzazione trattate in questa sezione.

Multi-threading

Quando si sviluppano per più piattaforme, è naturale posizionare tutte le attività all'interno del gioco in un solo thread. Sebbene questo metodo di esecuzione sia semplice, da implementare in molti motori di gioco, è tutt'altro che ottimale se viene eseguito su Android dispositivi mobili. Di conseguenza, i giochi a thread singolo spesso si caricano lentamente e non dispongono di una frequenza fotogrammi più elevata.

Lo strumento Systrace mostrato nella Figura 1 mostra il comportamento tipico di un gioco in esecuzione su una sola CPU alla volta:

Diagramma dei thread
all'interno di una traccia di sistema

Figura 1. Report Systrace per un gioco a thread unico
di Gemini Advanced.

Per migliorare le prestazioni del tuo gioco, configuralo con più thread. In genere, il modello migliore è avere 2 thread:

  • Un thread del gioco, che contiene i moduli principali del gioco e invia il rendering tramite comandi SQL.
  • Un thread di rendering, che riceve comandi di rendering e li traduce in comandi grafici che la GPU di un dispositivo può utilizzare per visualizzare una scena.

L'API Vulkan espande questo modello, data la sua capacità di eseguire il push di due comuni buffer in parallelo. Con questa funzione, puoi distribuire più elementi thread su più CPU, migliorando ulteriormente il tempo di rendering di una scena.

Puoi anche apportare alcune modifiche specifiche del motore per migliorare prestazioni multi-threading:

  • Se stai sviluppando il tuo gioco con il motore grafico Unity, attiva la Opzioni di Rendering multi-thread e skining GPU.
  • Se utilizzi un motore di rendering personalizzato, assicurati che il comando di rendering la pipeline e la pipeline di comando graphic siano allineate correttamente; altrimenti potrebbero causare ritardi nella visualizzazione delle scene del gioco.

Dopo aver applicato queste modifiche, dovresti vedere che il gioco occupa almeno 2 CPU contemporaneamente, come mostrato nella Figura 2:

Diagramma dei thread
all'interno di una traccia di sistema

Figura 2. Report Systrace per un gioco a più thread
di Gemini Advanced.

Caricamento elemento UI

Diagramma di un frame
  stack all'interno di un'analisi di sistema
Figura 3. Report Systrace per un gioco che esegue il rendering di decine di UI contemporaneamente
di Gemini Advanced.

Quando si crea un gioco ricco di funzionalità, si ha la tentazione di mostrare molte opzioni diverse e azioni al player contemporaneamente. Per mantenere una frequenza fotogrammi coerente, Tuttavia, è importante considerare le dimensioni relativamente ridotte dei display mobile. e mantieni la tua UI il più semplice possibile.

Il report Systrace mostrato nella Figura 3 è un esempio di frame dell'interfaccia utente che tentativo di eseguire il rendering di troppi elementi rispetto allo spazio le funzionalità di machine learning.

Un buon obiettivo è ridurre il tempo di aggiornamento dell'interfaccia utente a 2-3 millisecondi. Puoi aggiornamenti rapidi grazie a ottimizzazioni simili alle seguenti:

  • Aggiorna solo gli elementi spostati sullo schermo.
  • Limita il numero di texture e livelli dell'interfaccia utente. Prova a combinare chiamate grafiche, come tonalità e texture, che utilizzano lo stesso materiale.
  • Rimanda le operazioni di animazione degli elementi alla GPU.
  • Eseguire una ricerca di frustum e occlusione più aggressiva.
  • Se possibile, esegui operazioni di disegno utilizzando l'API Vulkan. La chiamata di estrazione l'overhead è più basso su Vulkan.

Consumo energetico

Anche dopo aver apportato le ottimizzazioni descritte nella sezione precedente, rilevare che la frequenza fotogrammi del gioco si deteriora entro i primi 45-50 minuti il gameplay. Inoltre, il dispositivo potrebbe iniziare a riscaldarsi e consumare di più della batteria nel tempo.

In molti casi, questo insieme indesiderato di temperature e consumo energetico è correlato alla distribuzione del carico di lavoro tra le CPU del dispositivo. Per aumentare l'efficienza del consumo energetico del gioco, applica le best practice mostrate le sezioni seguenti.

Mantenere i thread che usano molta memoria in una sola CPU

Su molti dispositivi mobili, le cache L1 risiedono su CPU specifiche e cache L2 che risiedono nell'insieme di CPU che condividono lo stesso orologio. Per massimizzare i successi della cache L1, in genere è meglio mantenere il thread principale del gioco, oltre a qualsiasi che usano molta memoria, in esecuzione su una singola CPU.

Rimanda il lavoro di breve durata a CPU con potenza inferiore

La maggior parte dei motori di gioco, incluso Unity, sa di dover rimandare le operazioni dei thread dei worker a a una CPU diversa rispetto al thread principale del gioco. Tuttavia, il motore a conoscenza dell'architettura specifica di un dispositivo e non è in grado di prevedere i carico di lavoro.

La maggior parte dei dispositivi system-on-a-chip ha almeno 2 orologi condivisi, uno per CPU veloci del dispositivo e uno per le CPU lente del dispositivo. Una conseguenza di ciò è che, se una CPU veloce deve funzionare alla massima velocità, tutte le anche altre CPU veloci funzionano alla massima velocità.

Il report di esempio mostrato nella Figura 4 mostra un gioco che sfrutta la velocità CPU. Tuttavia, questo elevato livello di attività genera una grande quantità di energia e calore. rapidamente.

Diagramma dei thread
all'interno di una traccia di sistema

Figura 4. Report Systrace che mostra un'assegnazione non ottimale dei thread a le CPU del dispositivo
di Gemini Advanced.

Per ridurre il consumo energetico complessivo, è consigliabile suggerire allo scheduler che lavori di minore durata, come il caricamento di audio, i thread di lavoro in esecuzione e l'esecuzione del coreografo, fatti riferire all'insieme di CPU lente di un dispositivo. Trasferisci il più possibile di questo lavoro sulle CPU lente, mantenendo al contempo con la frequenza fotogrammi desiderata.

La maggior parte dei dispositivi elenca le CPU lente prima di quelle veloci, ma non si può dare per scontato che il SOC del dispositivo utilizza questo ordine. Per verificare, esegui comandi simili a quelli mostrato in questo rilevamento della topologia CPU codice su GitHub.

Dopo aver capito quali sono le CPU lente sul tuo dispositivo, puoi affinità per i thread di breve durata, che lo scheduler del dispositivo . Per farlo, aggiungi il seguente codice in ogni thread:

#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);

Stress termico

Quando i dispositivi si riscaldano troppo, possono limitare la CPU e/o la GPU e questo può influisce sui giochi in modi inaspettati. Giochi che includono una grafica complessa, di calcolo o di attività di rete sostenuta hanno maggiori probabilità di riscontrare problemi.

Utilizza l'API termica per monitorare le variazioni di temperatura sul dispositivo e intervenire per mantieni un consumo energetico inferiore e una temperatura del dispositivo più bassa. Quando il dispositivo segnala stress termico, interrompi le attività in corso per ridurre consumo di energia. Ad esempio, riduci la frequenza fotogrammi o la tassellazione poligonale.

Innanzitutto, dichiara l'oggetto PowerManager vengono inizializzati nel metodo onCreate(). Aggiungi un listener di stato termico all'oggetto.

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);
    }
}

Definisci le azioni da eseguire quando il listener rileva uno stato modifica. Se il tuo gioco utilizza C/C++, aggiungi il codice ai livelli di stato termico in onThermalStatusChanged() per chiamare il tuo codice di gioco nativo utilizzando JNI o utilizzare l'API Thermal nativa.

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;
        }
    }
};

Latenza touch-to-display

I giochi che eseguono il rendering dei frame il più velocemente possibile creano uno scenario legato alla GPU, in cui il buffer del frame è sovraccarico. La CPU deve attendere la GPU, causando un notevole ritardo tra l'input di un giocatore e quello che prende l'input l'effetto sullo schermo.

Per determinare se puoi migliorare il pacing dei frame del gioco, completa la procedura seguenti passaggi:

  1. Genera un report Systrace che includa le categorie gfx e input. Queste categorie comprendono misurazioni particolarmente utili per determinare latenza touch-to-display.
  2. Controlla la sezione SurfaceView di un report di Systrace. Un buffer sovraccarico provoca l'oscillazione del numero di prelievi del buffer in sospeso tra 1 e 2, come mostrato Figura 5:

    Diagramma di
coda del buffer all&#39;interno di una traccia di sistema

    Figura 5. Il report Systrace mostra un buffer sovraccarico che periodicamente troppo pieno per accettare comandi di disegno
    di Gemini Advanced.

Per mitigare questa incoerenza nel pacing del frame, completa le azioni descritte nelle seguenti sezioni:

Integra l'API Android Frame Pacing nel tuo gioco

L'API Android Frame Pacing ti aiuta scambi frame e definisci un intervallo di scambio in modo che il gioco mantenga un con una frequenza fotogrammi più elevata.

Riduci la risoluzione delle risorse non UI del tuo gioco

I display sui dispositivi mobili moderni contengono molti più pixel di quelli che un player può avere di processo, quindi è corretto eseguire il sottocampionamento in modo che un'esecuzione di 5 o perfino 10 pixel contiene un solo colore. Data la struttura della maggior parte delle cache display, è meglio ridurre la risoluzione in una sola dimensione.

Tuttavia, non ridurre la risoluzione degli elementi UI del gioco. È importante di mantenere lo spessore della linea su questi elementi in modo da mantenere una dimensione sufficientemente grande dimensioni del touch target per tutti dai giocatori.

Uniformità del rendering

Quando SurfaceFlinger si aggancia a un buffer del display per mostrare una scena nel gioco, l'attività della CPU aumenta temporaneamente. Se si verificano questi picchi nell'attività della CPU in modo non uniforme, potrebbero verificarsi stuttering nel gioco. Diagramma nella Figura 6 ne illustri il motivo:

Diagramma dei frame
manca una finestra Vsync perché hanno iniziato a disegnare troppo tardi

Figura 6. Report Systrace che mostra come un frame può perdere una Vsync
di Gemini Advanced.

Se un frame inizia a disegnarsi troppo tardi, anche solo per pochi millisecondi, potrebbe non nella finestra di visualizzazione successiva. Il frame deve quindi attendere che venga raggiunta la visualizzato (33 millisecondi quando un gioco viene eseguito a 30 f/s), notevole ritardo dal punto di vista del giocatore.

Per risolvere questa situazione, utilizza la strategia Android Frame Pacing (Pacing del frame Android) API, che presenta sempre un nuovo frame in un Fronte d'onda VSync.

Stato memoria

Quando esegui il gioco per un periodo di tempo prolungato, è possibile che il sul dispositivo per riscontrare errori di esaurimento della memoria.

In questo caso, controlla l'attività della CPU in un report Systrace e verifica con quale frequenza il sistema sta effettuando chiamate al daemon kswapd. Se ci sono molte chiamate durante l'esecuzione del gioco, è meglio esaminare più attentamente come funziona è la gestione e la pulizia della memoria.

Per ulteriori informazioni, vedi Gestire in modo efficace la memoria nei giochi.

Stato del thread

Quando esplori gli elementi tipici di un report Systrace, puoi visualizzare La quantità di tempo trascorsa da un determinato thread in ogni possibile thread selezionando thread all'interno del report, come mostrato nella Figura 7:

Diagramma di un
Report Systrace

Figura 7. Il report Systrace che mostra in che modo la selezione di un thread provoca la report per visualizzare un riepilogo dello stato per quel thread
di Gemini Advanced.

Come mostrato nella Figura 7, potresti scoprire che i thread del gioco non si trovano nella "in esecuzione" o "eseguibile" tutte le volte che si desidera. Il seguente elenco mostra diversi motivi comuni per cui un determinato thread potrebbe essere periodicamente transizione a uno stato insolito:

  • Se un thread rimane in sospensione per un periodo di tempo prolungato, potrebbe soffrire dalla contesa del blocco o dall'attesa dell'attività GPU.
  • Se un thread è costantemente bloccato su I/O, stai leggendo troppi dati dal disco alla volta, o il gioco è stupendo.
di Gemini Advanced.

Risorse aggiuntive

Per ulteriori informazioni su come migliorare le prestazioni del tuo gioco, consulta quanto segue risorse aggiuntive:

Video