Usa Simpleperf per valutare le prestazioni di un dispositivo. Simpleperf è uno strumento di profilazione nativo sia per applicazioni che per processi nativi su Android. Usa CPU Profiler per controllare l'utilizzo della CPU dell'app e l'attività dei thread in tempo reale.
Sono disponibili due indicatori di performance visibili all'utente:
- Prestazioni prevedibili e percepibili . L'interfaccia utente (UI) rilascia frame o esegue costantemente il rendering a 60 FPS? L'audio viene riprodotto senza artefatti o scoppi? Quanto è lungo il ritardo tra l'utente che tocca lo schermo e l'effetto visualizzato sul display?
- Tempo necessario per operazioni più lunghe (come l'apertura di applicazioni).
Il primo è più evidente del secondo. Gli utenti in genere notano jank ma non saranno in grado di dire 500 ms rispetto a 600 ms di tempo di avvio dell'applicazione a meno che non stiano guardando due dispositivi fianco a fianco. La latenza al tocco è immediatamente percepibile e contribuisce in modo significativo alla percezione di un dispositivo.
Di conseguenza, in un dispositivo veloce, la pipeline dell'interfaccia utente è la cosa più importante nel sistema oltre a ciò che è necessario per mantenere funzionante la pipeline dell'interfaccia utente. Ciò significa che la pipeline dell'interfaccia utente dovrebbe anticipare qualsiasi altro lavoro non necessario per un'interfaccia utente fluida. Per mantenere un'interfaccia utente fluida, la sincronizzazione in background, il recapito delle notifiche e lavori simili devono essere tutti ritardati se è possibile eseguire il lavoro dell'interfaccia utente. È accettabile scambiare le prestazioni di operazioni più lunghe (runtime HDR+, avvio dell'applicazione, ecc.) per mantenere un'interfaccia utente fluida.
Capacità vs jitter
Quando si considerano le prestazioni del dispositivo, la capacità e il jitter sono due parametri significativi.
Capacità
La capacità è la quantità totale di alcune risorse che il dispositivo possiede in un certo periodo di tempo. Può trattarsi di risorse CPU, risorse GPU, risorse I/O, risorse di rete, larghezza di banda della memoria o qualsiasi metrica simile. Quando si esaminano le prestazioni dell'intero sistema, può essere utile astrarre i singoli componenti e assumere una singola metrica che determini le prestazioni (soprattutto durante l'ottimizzazione di un nuovo dispositivo perché i carichi di lavoro eseguiti su quel dispositivo sono probabilmente fissi).
La capacità di un sistema varia in base alle risorse informatiche online. La modifica della frequenza CPU/GPU è il mezzo principale per modificare la capacità, ma ce ne sono altri come la modifica del numero di core della CPU online. Di conseguenza, la capacità di un sistema corrisponde al consumo di energia; la modifica della capacità si traduce sempre in una variazione simile nel consumo di energia.
La capacità richiesta in un determinato momento è determinata in modo schiacciante dall'applicazione in esecuzione. Di conseguenza, la piattaforma può fare poco per regolare la capacità richiesta per un determinato carico di lavoro e i mezzi per farlo sono limitati ai miglioramenti del runtime (framework Android, ART, Bionic, compilatore/driver GPU, kernel).
Tremore
Mentre la capacità richiesta per un carico di lavoro è facile da vedere, il jitter è un concetto più nebuloso. Per una buona introduzione al jitter come impedimento ai sistemi veloci, fare riferimento a IL CASO DELLA PRESTAZIONE DEL SUPERCOMPUTER MANCANTE: RAGGIUNGERE PRESTAZIONI OTTIMALI SUGLI 8.192 PROCESSORI DI ASCl Q . (È un'indagine sul motivo per cui il supercomputer ASCI Q non ha raggiunto le prestazioni previste ed è un'ottima introduzione all'ottimizzazione di sistemi di grandi dimensioni.)
Questa pagina usa il termine jitter per descrivere ciò che il documento ASCI Q chiama rumore . Il jitter è il comportamento casuale del sistema che impedisce l'esecuzione del lavoro percepibile. Spesso è un lavoro che deve essere eseguito, ma potrebbe non avere requisiti di tempistica rigorosi che ne determinano l'esecuzione in un determinato momento. Poiché è casuale, è estremamente difficile confutare l'esistenza del jitter per un determinato carico di lavoro. È anche estremamente difficile dimostrare che una nota fonte di jitter sia stata la causa di un particolare problema di prestazioni. Gli strumenti più comunemente usati per diagnosticare le cause del jitter (come il tracciamento o la registrazione) possono introdurre il proprio jitter.
Le fonti di jitter sperimentate nelle implementazioni reali di Android includono:
- Ritardo programmatore
- Gestori di interruzioni
- Codice del driver in esecuzione per troppo tempo con la prelazione o gli interrupt disabilitati
- Softirq di lunga durata
- Conflitto di blocco (applicazione, framework, driver del kernel, blocco raccoglitore, blocco mmap)
- Conflitto nel descrittore di file in cui un thread con priorità bassa mantiene il blocco su un file, impedendo l'esecuzione di un thread con priorità alta
- Esecuzione di codice critico per l'interfaccia utente nelle code di lavoro in cui potrebbe essere ritardato
- Transizioni inattive della CPU
- Registrazione
- Ritardi I/O
- Creazione di processi non necessari (ad es. trasmissioni CONNECTIVITY_CHANGE)
- Threshing della cache della pagina causato da memoria libera insufficiente
La quantità di tempo richiesta per un dato periodo di jitter può o meno diminuire all'aumentare della capacità. Ad esempio, se un driver lascia gli interrupt disabilitati mentre attende una lettura da un bus i2c, ci vorrà un periodo di tempo fisso indipendentemente dal fatto che la CPU sia a 384 MHz o 2 GHz. L'aumento della capacità non è una soluzione fattibile per migliorare le prestazioni quando è coinvolto il jitter. Di conseguenza, processori più veloci di solito non migliorano le prestazioni in situazioni con limitazioni di jitter.
Infine, a differenza della capacità, il jitter rientra quasi interamente nel dominio del fornitore del sistema.
Consumo di memoria
Il consumo di memoria è tradizionalmente accusato di scarse prestazioni. Sebbene il consumo in sé non sia un problema di prestazioni, può causare jitter a causa di un sovraccarico di memoria ridotta, riavvii del servizio e thrashing della cache della pagina. La riduzione del consumo di memoria può evitare le cause dirette delle scarse prestazioni, ma potrebbero esserci altri miglioramenti mirati che evitano anche tali cause (ad esempio, bloccare il framework per impedirne il paging fuori quando verrà eseguito il paging subito dopo).
Analisi delle prestazioni iniziali del dispositivo
Partire da un sistema funzionale ma con prestazioni scadenti e tentare di correggere il comportamento del sistema esaminando i singoli casi di scarse prestazioni visibili dall'utente non è una strategia valida. Poiché le scarse prestazioni di solito non sono facilmente riproducibili (ad esempio, jitter) o un problema dell'applicazione, troppe variabili nell'intero sistema impediscono a questa strategia di essere efficace. Di conseguenza, è molto facile identificare erroneamente le cause e apportare piccoli miglioramenti mentre si perdono opportunità sistemiche per correggere le prestazioni in tutto il sistema.
Utilizzare invece il seguente approccio generale quando si apre un nuovo dispositivo:
- Ottieni l'avvio del sistema dall'interfaccia utente con tutti i driver in esecuzione e alcune impostazioni di base del regolatore di frequenza (se si modificano le impostazioni del regolatore di frequenza, ripetere tutti i passaggi seguenti).
- Assicurati che il kernel supporti il
sched_blocked_reason
sched_blocked_reason così come altri tracepoint nella pipeline di visualizzazione che indicano quando il frame viene consegnato al display. - Prendi lunghe tracce dell'intera pipeline dell'interfaccia utente (dalla ricezione dell'input tramite un IRQ allo scanout finale) durante l'esecuzione di un carico di lavoro leggero e coerente (ad esempio, UiBench o il test della palla in TouchLatency) .
- Correggi le cadute di frame rilevate nel carico di lavoro leggero e coerente.
- Ripeti i passaggi 3-4 finché non riesci a eseguire senza fotogrammi persi per oltre 20 secondi alla volta.
- Passa ad altre fonti di jank visibili all'utente.
Altre semplici cose che puoi fare all'inizio della visualizzazione del dispositivo includono:
- Assicurati che il tuo kernel abbia la patch del tracepoint sched_blocked_reason . Questo tracepoint è abilitato con la categoria sched trace in systrace e fornisce la funzione responsabile della sospensione quando quel thread entra in modalità sospensione ininterrotta. È fondamentale per l'analisi delle prestazioni perché il sonno ininterrotto è un indicatore molto comune di jitter.
- Assicurati di avere una traccia sufficiente per la GPU e le pipeline di visualizzazione. Sui recenti SOC Qualcomm, i tracepoint vengono abilitati utilizzando:
adb shell "echo 1 > /d/tracing/events/kgsl/enable"
adb shell "echo 1 > /d/tracing/events/mdss/enable"
Questi eventi rimangono abilitati quando si esegue systrace in modo da poter visualizzare ulteriori informazioni nella traccia sulla pipeline di visualizzazione (MDSS) nella sezione mdss_fb0
. Sui Qualcomm SOC, non vedrai alcuna informazione aggiuntiva sulla GPU nella vista systrace standard, ma i risultati sono presenti nella traccia stessa (per i dettagli, vedi Comprensione di Systrace ).
Ciò che si desidera da questo tipo di tracciamento del display è un singolo evento che indica direttamente che un frame è stato consegnato al display. Da lì, puoi determinare se hai raggiunto con successo il tuo frame time; se l'evento X n si verifica meno di 16,7 ms dopo l'evento X n-1 (supponendo un display a 60 Hz), allora sai di non aver eseguito il jank. Se il tuo SOC non fornisce tali segnali, collabora con il tuo fornitore per ottenerli. Il debug del jitter è estremamente difficile senza un segnale definitivo di completamento del frame.
Utilizzo di benchmark sintetici
I benchmark sintetici sono utili per garantire la presenza della funzionalità di base di un dispositivo. Tuttavia, trattare i benchmark come proxy delle prestazioni percepite del dispositivo non è utile.
Sulla base dell'esperienza con i SOC, le differenze nelle prestazioni dei benchmark sintetici tra i SOC non sono correlate a una differenza simile nelle prestazioni dell'interfaccia utente percettibili (numero di frame persi, tempo di frame al 99° percentile, ecc.). I benchmark sintetici sono benchmark di sola capacità; il jitter influisce sulle prestazioni misurate di questi benchmark solo sottraendo tempo al funzionamento in blocco del benchmark. Di conseguenza, i punteggi dei benchmark sintetici sono per lo più irrilevanti come metrica delle prestazioni percepite dall'utente.
Considera due SOC che eseguono Benchmark X che esegue il rendering di 1000 fotogrammi dell'interfaccia utente e segnala il tempo di rendering totale (un punteggio più basso è migliore).
- SOC 1 esegue il rendering di ogni frame di Benchmark X in 10 ms e ottiene un punteggio di 10.000.
- SOC 2 esegue il rendering del 99% dei fotogrammi in 1 ms ma dell'1% dei fotogrammi in 100 ms e ottiene un punteggio di 19.900, un punteggio notevolmente migliore.
Se il benchmark è indicativo delle prestazioni effettive dell'interfaccia utente, SOC 2 sarebbe inutilizzabile. Supponendo una frequenza di aggiornamento di 60 Hz, SOC 2 avrebbe un frame janky ogni 1,5 secondi di funzionamento. Nel frattempo, SOC 1 (il SOC più lento secondo Benchmark X) sarebbe perfettamente fluido.
Utilizzo delle segnalazioni di bug
Le segnalazioni di bug sono talvolta utili per l'analisi delle prestazioni, ma poiché sono così pesanti, raramente sono utili per il debug di problemi sporadici di jank. Potrebbero fornire alcuni suggerimenti su ciò che il sistema stava facendo in un dato momento, specialmente se il jank era attorno a una transizione dell'applicazione (che è registrata in una segnalazione di bug). Le segnalazioni di bug possono anche indicare quando qualcosa è più ampiamente sbagliato nel sistema che potrebbe ridurne la capacità effettiva (come la limitazione termica o la frammentazione della memoria).
Utilizzo di TouchLatency
Diversi esempi di cattivo comportamento provengono da TouchLatency, che è il carico di lavoro periodico preferito utilizzato per Pixel e Pixel XL. È disponibile in frameworks/base/tests/TouchLatency
e ha due modalità: latenza del tocco e palla che rimbalza (per cambiare modalità, fare clic sul pulsante nell'angolo in alto a destra).
Il test della palla che rimbalza è esattamente come sembra: una palla rimbalza sullo schermo per sempre, indipendentemente dall'input dell'utente. Di solito è anche di gran lunga il test più difficile da eseguire perfettamente, ma più ci si avvicina a correre senza cali di frame, migliore sarà il tuo dispositivo. Il test della palla che rimbalza è difficile perché si tratta di un carico di lavoro banale ma perfettamente coerente che viene eseguito a un clock molto basso (questo presuppone che il dispositivo abbia un regolatore di frequenza; se invece il dispositivo funziona con clock fissi, downclockare CPU/GPU quasi al minimo quando si esegue il test della palla che rimbalza per la prima volta). Quando il sistema si interrompe e gli orologi si avvicinano all'inattività, il tempo CPU/GPU richiesto per frame aumenta. Puoi guardare la palla e vedere le cose jak, e sarai anche in grado di vedere i fotogrammi mancati in Systrace.
Poiché il carico di lavoro è così coerente, è possibile identificare la maggior parte delle fonti di jitter molto più facilmente rispetto alla maggior parte dei carichi di lavoro visibili all'utente tenendo traccia di ciò che è esattamente in esecuzione sul sistema durante ogni frame mancante anziché nella pipeline dell'interfaccia utente. I clock inferiori amplificano gli effetti del jitter rendendo più probabile che qualsiasi jitter causi un frame caduto. Di conseguenza, più TouchLatency è vicino a 60 FPS, meno è probabile che tu abbia comportamenti di sistema errati che causano sporadici errori di riproduzione difficili in applicazioni più grandi.
Poiché il jitter è spesso (ma non sempre) invariante della velocità di clock, utilizzare un test che viene eseguito a clock molto bassi per diagnosticare il jitter per i seguenti motivi:
- Non tutto il jitter è invariante della velocità di clock; molte fonti consumano solo tempo della CPU.
- Il governatore dovrebbe avvicinare il tempo medio del frame alla scadenza abbassando il tempo, in modo che il tempo speso per eseguire il lavoro non dell'interfaccia utente possa spingerlo oltre il limite per far cadere un frame.