Utilizza Simpleperf per valutare le prestazioni di un dispositivo. Simpleperf è uno strumento di profilazione nativo sia per le app sia per i processi nativi su Android. Utilizza CPU Profiler per ispezionare l'utilizzo della CPU dell'app e l'attività dei thread in tempo reale.
Esistono due indicatori del rendimento visibili agli utenti:
- Rendimento prevedibile e percepibile. L'interfaccia utente perde frame o esegue il rendering in modo coerente a 60 FPS? L'audio viene riprodotto senza artefatti o scoppiettii? Quanto dura il ritardo tra il tocco dello schermo da parte dell'utente e la visualizzazione dell'effetto sul display?
- Tempo necessario per le operazioni più lunghe (ad esempio l'apertura di app).
Il primo è più evidente del secondo. In genere gli utenti notano il jitter, ma non sono in grado di distinguere un tempo di avvio dell'app di 500 ms da uno di 600 ms, a meno che non stiano guardando due dispositivi affiancati. La latenza tocco è immediatamente visibile e contribuisce in modo significativo alla percezione di un dispositivo.
Di conseguenza, in un dispositivo veloce, la pipeline dell'interfaccia utente è l'elemento più importante nel sistema, oltre a ciò che è necessario per mantenerla funzionale. Ciò significa che la pipeline dell'interfaccia utente deve anticipare qualsiasi altro lavoro non necessario per un'interfaccia utente fluida. Per mantenere un'interfaccia utente fluida, la sincronizzazione in background, l'invio di notifiche e operazioni simili devono essere ritardate se è possibile eseguire operazioni relative all'interfaccia utente. È accettabile sacrificare le prestazioni di operazioni più lunghe (runtime HDR+, avvio dell'app e così via) per mantenere un'interfaccia utente fluida.
Capacità rispetto al jitter
Quando si valuta il rendimento del dispositivo, capacità e jitter sono due metriche significative.
Capacità
La capacità è la quantità totale di una risorsa posseduta dal dispositivo per un determinato 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 esamini il rendimento dell'intero sistema, può essere utile astrarre i singoli componenti e assumere una singola metrica che ne determina il rendimento (soprattutto quando ottimizzi un nuovo dispositivo, in quanto i carichi di lavoro eseguiti su quel dispositivo sono probabilmente fissi).
La capacità di un sistema varia in base alle risorse di calcolo online. La modifica della frequenza della CPU/GPU è il mezzo principale per modificare la capacità, ma esistono altri metodi, ad esempio la modifica del numero di core della CPU online. Di conseguenza, la capacità di un sistema corrisponde al consumo di energia; la variazione della capacità comporta sempre una variazione simile del consumo di energia.
La capacità richiesta in un determinato momento è determinata in modo schiacciante dall'app 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 di runtime (framework Android, ART, Bionic, compilatori/driver GPU, kernel).
Tremolio
Sebbene la capacità richiesta per un carico di lavoro sia facile da vedere, il jitter è un concetto più sfumato. Per una buona introduzione al jitter come impedimento per i sistemi rapidi, ti consigliamo di leggere il documento intitolato The Case of the Missing Supercomputer Performance: Achieving Optimal Performance on the 8,192 processors of ASCI 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.)
In questa pagina il termine jitter viene utilizzato per descrivere ciò che il documento ASCI Q definisce rumore. Il jitter è il comportamento casuale del sistema che impedisce l'esecuzione di un lavoro percepibile. Spesso si tratta di attività che devono essere eseguite, ma che potrebbero non avere requisiti di tempistica rigorosi che ne determinano l'esecuzione in un momento specifico. Poiché è randomico, è estremamente difficile dimostrare l'esistenza del jitter per un determinato carico di lavoro. È inoltre estremamente difficile dimostrare che una fonte nota di jitter sia stata la causa di un determinato problema di prestazioni. Gli strumenti più comunemente utilizzati per diagnosticare le cause del jitter (come il monitoraggio o la registrazione) possono introdurre il proprio jitter.
Le sorgenti di jitter riscontrate nelle implementazioni reali di Android include:
- Ritardo pianificatore
- Gestori delle interruzioni
- Il codice del driver è in esecuzione per troppo tempo con la preemption o le interruzioni disattivate
- Softirq a lunga esecuzione
- Conflitto blocco (app, framework, driver del kernel, blocco binder, blocco mmap)
- Concorrenza dei descrittori file in cui un thread con priorità bassa detiene il blocco di un file, impedendo l'esecuzione di un thread con priorità elevata
- Eseguire codice critico per l'interfaccia utente nelle code di lavoro dove potrebbe essere ritardato
- Transizioni in stato inattivo della CPU
- Logging
- Ritardi I/O
- Creazione di processi non necessari (ad es. trasmissioni
CONNECTIVITY_CHANGE
) - Thrashing della cache di pagina causato da memoria libera insufficiente
Il tempo necessario per un determinato periodo di jitter può diminuire o meno con l'aumento della capacità. Ad esempio, se un driver lascia disabilitate le interruzioni mentre è in attesa di una lettura da un bus I2C, impiegherà un determinato periodo di tempo indipendentemente dal fatto che la CPU operi a 384 MHz o 2 GHz. L'aumento della capacità non è una soluzione praticabile per migliorare le prestazioni in presenza di jitter. Di conseguenza, i processori più veloci in genere non migliorano le prestazioni in situazioni con jitter limitato.
Infine, a differenza della capacità, il jitter è quasi interamente nel dominio del fornitore del sistema.
Consumo di memoria
Il consumo di memoria è tradizionalmente considerato responsabile del cattivo rendimento. Anche se il consumo in sé non è un problema di prestazioni, può causare jitter tramite il sovraccarico di lowmemorykiller, i riavvii dei servizi e il thrashing della cache di pagina. Ridurre il consumo di memoria può evitare le cause dirette del cattivo rendimento, ma potrebbero esserci altri miglioramenti mirati che evitano anche queste cause (ad esempio, bloccare il framework per impedire che venga espulso dalla memoria quando verrà inserito poco dopo).
Analizzare il rendimento iniziale del dispositivo
Partire da un sistema funzionale, ma con scarso rendimento, e tentare di correggere il comportamento del sistema esaminando singoli casi di scarso rendimento visibili all'utente non è una strategia valida. Poiché il cattivo rendimento solitamente non è facilmente riproducibile (ad es. jitter) o non è un problema dell'app, troppe variabili nel sistema completo impediscono l'efficacia di questa strategia. Di conseguenza, è molto facile identificare erroneamente le cause e apportare miglioramenti minori, perdendo al contempo opportunità sistemiche per correggere il rendimento dell'intero sistema.
Utilizza invece il seguente approccio generale quando avvii un nuovo dispositivo:
- Fai in modo che il sistema si avvii nell'interfaccia utente con tutti i driver in esecuzione e alcune impostazioni di base del regolatore della frequenza (se modifichi le impostazioni del regolatore della frequenza, ripeti tutti i passaggi riportati di seguito).
- Assicurati che il kernel supporti il tracepoint
sched_blocked_reason
nonché altri tracepoint nella pipeline di visualizzazione che indicano quando il frame viene inviato al display. - Acquisisci tracce lunghe dell'intera pipeline dell'interfaccia utente (dalla ricezione dell'input tramite un IRQ al controllo finale) durante l'esecuzione di un carico di lavoro leggero e coerente (ad esempio UiBench o il test della palla in TouchLatency).
- Risolvi i cali di frame rilevati nel workload leggero e coerente.
- Ripeti i passaggi 3-4 finché non riesci a eseguire la riproduzione senza perdite di frame per più di 20 secondi alla volta.
- Passa ad altre sorgenti di balbuzie visibili all'utente.
Ecco altre semplici operazioni che puoi eseguire all'inizio della configurazione del dispositivo:
- Assicurati che il kernel abbia la patch del tracepoint sched_blocked_reason. Questo punto di traccia viene attivato con la categoria di traccia sched in systrace e fornisce la funzione responsabile del sonno quando il thread entra in sospensione non interrompibile. È fondamentale per l'analisi del rendimento perché il sonno ininterrotto è un indicatore molto comune di jitter.
- Assicurati di avere un monitoraggio sufficiente per le pipeline della GPU e del display. Nei SoC Qualcomm recenti, i tracepoint sono abilitati utilizzando:
adb shell "echo 1 > /d/tracing/events/kgsl/enable"
adb shell "echo 1 > /d/tracing/events/mdss/enable"
Questi eventi rimangono attivi quando esegui systrace, in modo da poter visualizzare ulteriori informazioni nella traccia sulla pipeline di visualizzazione (MDSS) nella sezione mdss_fb0
. Sui SoC Qualcomm, non vengono visualizzate altre informazioni sulla GPU nella visualizzazione systrace standard, ma i risultati sono presenti nella traccia stessa (per maggiori dettagli, consulta Informazioni su systrace).
Da questo tipo di monitoraggio della visualizzazione, ti serve un singolo evento che indique direttamente che un frame è stato visualizzato. Da qui, puoi determinare se hai raggiunto il tempo del frame.Se l'evento Xn avviene meno di 16,7 ms dopo l'evento Xn-1 (supponendo un display a 60 Hz), puoi sapere che non hai riscontrato problemi di judder. Se il tuo SOC non fornisce questi indicatori, collabora con il tuo fornitore per ottenerli. Il debug del jitter è estremamente difficile senza un segnale definitivo del completamento del frame.
Utilizzare benchmark sintetici
I benchmark sintetici sono utili per verificare la presenza della funzionalità di base di un dispositivo. Tuttavia, trattare i benchmark come sostituti del rendimento percepito del dispositivo non è utile.
In base alle esperienze con gli SOC, le differenze nel rendimento dei benchmark sintetici tra gli SOC non sono correlate a una differenza simile nel rendimento percepito dell'interfaccia utente (numero di frame persi, tempo del frame del 99° percentile e così via). I benchmark sintetici sono benchmark solo per la capacità; il jitter influisce sul rendimento misurato di questi benchmark solo sottraendo tempo all'operazione collettiva 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 il benchmark X che esegue il rendering di 1000 frame dell'interfaccia utente e segnala il tempo di rendering totale (un punteggio più basso è migliore).
- SOC 1 esegue il rendering di ogni frame del benchmark X in 10 ms e ottiene un punteggio di 10.000.
- SOC 2 esegue il rendering del 99% dei frame in 1 ms,ma dell'1% dei frame in 100 ms e ottiene un punteggio di 19.900, un punteggio notevolmente migliore.
Se il benchmark è indicativo del rendimento effettivo dell'interfaccia utente, la certificazione SOC 2 non sarebbe utilizzabile. Supponendo una frequenza di aggiornamento di 60 Hz, SOC 2 avrebbe un frame discontinuo ogni 1,5 secondi di funzionamento. Nel frattempo, il SOC 1 (il SOC più lento in base al benchmark X) sarebbe perfettamente fluido.
Utilizzare le segnalazioni di bug
A volte i report di bug sono utili per l'analisi del rendimento, ma poiché sono molto pesanti, raramente sono utili per il debug di problemi di aggiornamento sporadici. Potrebbero fornire alcuni suggerimenti su cosa stava facendo il sistema in un determinato momento, soprattutto se il problema si è verificato durante una transizione di app (che viene registrata in una segnalazione di bug). I report di bug possono anche indicare quando c'è un problema più generale con il sistema che potrebbe ridurre la sua capacità effettiva (ad esempio la throttling termica o la frammentazione della memoria).
Utilizzare TouchLatency
Diversi esempi di cattivo comportamento provengono da TouchLatency, che è il carico di lavoro periodico preferito utilizzato per Pixel e Pixel XL. È disponibile all'indirizzo
frameworks/base/tests/TouchLatency
e ha due modalità: latenza tocco
e palla che rimbalza (per cambiare modalità, fai clic sul pulsante nell'angolo in alto a
destra).
Il test della palla che rimbalza è esattamente così semplice come sembra: una palla rimbalza intorno allo schermo per sempre, indipendentemente dall'input dell'utente. Di solito è anche il test più difficile da eseguire perfettamente, ma più si avvicina all'esecuzione senza perdite 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 una frequenza molto bassa (si presume che il dispositivo abbia un governatore della frequenza; se invece il dispositivo funziona con frequenze fisse, riduci la frequenza della CPU/GPU al minimo quando esegui il test della palla che rimbalza per la prima volta). Quando il sistema entra in stato di riposo e le frequenze si avvicinano allo stato inattivo, il tempo richiesto per CPU/GPU per frame aumenta. Puoi guardare la palla e vedere le cose che non vanno e potrai anche vedere i frame mancanti in systrace.
Poiché il carico di lavoro è molto coerente, puoi identificare la maggior parte delle fonti di jitter molto più facilmente rispetto alla maggior parte dei carichi di lavoro visibili all'utente monitorando cosa viene eseguito esattamente sul sistema durante ogni frame perso anziché nella pipeline dell'interfaccia utente. Le frequenze inferiori amplificano gli effetti del jitter aumentando la probabilità che si verifichi un calo di frame. Di conseguenza, più il valore di TouchLatency è vicino a 60 FPS, meno è probabile che si verifichino comportamenti di sistema errati che causano scatti sporadici e difficili da riprodurre nelle app più grandi.
Poiché il jitter è spesso (ma non sempre) indipendente dalla frequenza di clock, utilizza un test che viene eseguito a frequenze di clock molto basse per diagnosticare il jitter per i seguenti motivi:
- Non tutto il jitter è indipendente dalla frequenza di clock; molte sorgenti consumano solo tempo della CPU.
- Il governatore dovrebbe avvicinare il tempo del frame medio alla scadenza riducendo la frequenza, in modo che il tempo impiegato per eseguire attività non relative all'interfaccia utente possa spingerlo oltre il limite per far cadere un frame.