systrace è lo strumento principale per analizzare le prestazioni dei dispositivi Android. Tuttavia, si tratta di un wrapper intorno agli altri strumenti. È il wrapper lato host atrace, l'eseguibile lato dispositivo che controlla lo spazio utente tracciare e configurare ftrace, nonché il meccanismo di tracciamento principale in Linux in un kernel. systrace utilizza atrace per abilitare il tracciamento, quindi legge il buffer ftrace e aggrega tutto in un visualizzatore HTML autonomo. (Mentre i kernel più recenti supportano per Linux Advanced Berkeley Packet Filtro (eBPF), la seguente documentazione riguarda il kernel 3.18 (senza eFPF), che è quello usato sui Pixel/Pixel XL.
systrace è di proprietà dei team di Google Android e Google Chrome ed è open source nell'ambito Progetto catapult. Nella oltre a systrace, Catapult include altre utilità utili. Ad esempio: ftrace ha più funzionalità di quelle che possono essere attivate direttamente da systrace o atrace e contiene alcune funzionalità avanzate fondamentali per il debug delle prestazioni per risolvere problemi di produzione e facilità d'uso. (Queste funzioni richiedono l'accesso root e spesso un nuovo kernel.)
Esegui systrace
Quando esegui il debug del tremolio su Pixel/Pixel XL, inizia con quanto segue :
./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000
Se combinata con gli indicatori di tracciamento aggiuntivi richiesti per GPU e display dell'attività della pipeline, questo ti permette di tracciare dall'input dell'utente al frame visualizzato sullo schermo. Imposta la dimensione del buffer su un valore grande per evitare di perdere (perché senza un buffer di grandi dimensioni alcune CPU non contengono eventi dopo in qualche punto della traccia).
Quando esegui una verifica systrace, tieni presente che ogni evento viene viene attivato da qualcosa sulla CPU.
Poiché systrace è basato su ftrace e ftrace viene eseguito sulla CPU, qualcosa sulla CPU deve scrivere il buffer ftrace che registra le modifiche hardware. Ciò significa che se vuoi sapere perché lo stato di un recinto del display è cambiato, vedere cosa era in esecuzione sulla CPU nel punto esatto della transizione (qualcosa in esecuzione nella CPU ha attivato la modifica nel log). Questo è alla base dell'analisi del rendimento utilizzando systrace.
Esempio: frame di lavoro
Questo esempio descrive un valore systrace per una normale pipeline dell'interfaccia utente. Per continuare
Con l'esempio, scarica il file ZIP delle tracce
(che include anche altre tracce a cui si fa riferimento in questa sezione), decomprimi il file,
e apri il file systrace_tutorial.html
nel browser. Attenzione
che questo systrace è un file di grandi dimensioni; a meno che non usi systrace nelle tue attività quotidiane
al lavoro, probabilmente si tratta di una traccia molto più grande con molte più informazioni di quelle
mai visti prima in una singola traccia.
Per un carico di lavoro periodico e coerente, come Touch Latenza, la pipeline UI contiene quanto segue:
- EventThread in SurfaceFlinger riattiva il thread dell'interfaccia utente dell'app, segnalando che è ora per eseguire il rendering di un nuovo frame.
- L'app esegue il rendering di un frame nel thread dell'interfaccia utente, in RenderThread e hwuiTasks, utilizzando CPU e delle risorse GPU. Questa è la maggior parte della capacità spesa per la UI.
- L'app invia il frame sottoposto a rendering a SurfaceFlinger utilizzando un binder, quindi SurfaceFlinger va in sospensione.
- Un secondo EventThread in SurfaceFlinger attiva SurfaceFlinger per l'attivazione di composizione e di visualizzazione. Se SurfaceFlinger stabilisce che non è necessario intervenire fatto, si riattiva.
- SurfaceFlinger gestisce la composizione utilizzando Hardware Composer (HWC)/Hardware Composer 2 (HWC2) o GL. Composizione HWC/HWC2 è più veloce e ha una potenza inferiore, ma ha delle limitazioni a seconda del sistema su un chip (SoC). In genere questa operazione richiede circa 4-6 ms, ma può sovrapporsi al passaggio 2 perché Android le app hanno sempre un triplo buffer. (Sebbene le app abbiano sempre un triplo buffer, ci sono potrebbe essere un solo frame in attesa in attesa in SurfaceFlinger, che viene quindi visualizzato è identica al doppio buffering).
- SurfaceFlinger invia l'output finale a un conducente del fornitore di nuovo a dormire, in attesa della riattivazione EventThread.
Esaminiamo il frame che inizia da 15.409 ms:
.La Figura 1 mostra un normale frame circondato da frame normali, quindi è una buona punto di partenza per comprendere come funziona la pipeline UI. La riga del thread dell'interfaccia utente per Latenza tocco include colori diversi in momenti diversi. Le barre indicano stati diversi per il thread:
- Grigio. Dormire.
- Blu. Eseguibile (potrebbe essere eseguito, ma lo scheduler non lo ha fatto) selezionato per l'esecuzione).
- Verde. È in esecuzione (lo scheduler pensa che in esecuzione).
- Rosso. Sonno continuo (generalmente dormire sulla serratura) nel kernel). Può essere indicativo del carico di I/O. Estremamente utile per il debug o problemi di prestazioni.
- Arancione. Sonno senza interruzioni a causa del carico I/O.
Per visualizzare il motivo del sonno senza interruzioni (disponibile nel
sched_blocked_reason
tracepoint), seleziona il gruppo di continuità rosso
porzione di sonno.
Mentre EventThread è in esecuzione, il thread UI per Touch Latenza diventa eseguibili. Per vedere cosa l'ha attivato, fai clic sulla sezione blu.
.La figura 2 mostra il thread UI TouchLatenza attivata da tid 6843, che corrisponde a EventThread. Il thread UI si riattiva, esegue il rendering di un frame e accoda per il consumo da parte di SurfaceFlinger.
.Se il tag binder_driver
è abilitato in una traccia, puoi selezionare un'opzione
binder per visualizzare le informazioni su tutti i processi
transazione.
La Figura 4 mostra che, a 15.423,65 ms, Binder:6832_1 in SurfaceFlinger diventa eseguibile a causa di tid 9579, che è RenderThread di TouchLatenza. Puoi anche consulta codeBuffer su entrambi i lati della transazione binder.
Durante la coda Buffer sul lato SurfaceFlinger, il numero i frame da 1 a 2.
.La figura 5 mostra il triplo buffering, in cui sono presenti due frame completati e un terzo dell'app sta per iniziare. Questo perché abbiamo già abbandonato alcuni frame, quindi l'app conserva due frame in attesa anziché uno per cercare di evitare l'interruzione ulteriormente dei frame.
Poco dopo, il thread principale di SurfaceFlinger viene riattivato da un secondo EventThread, può inviare il vecchio frame in sospeso sul display:
.SurfaceFlinger blocca innanzitutto il vecchio buffer in sospeso, determinando il conteggio del buffer in sospeso diminuisce da 2 a 1.
.Dopo aver bloccato il buffer, SurfaceFlinger imposta la composizione e invia il metodo
frame finale al display. (Alcune di queste sezioni sono abilitate nell'ambito
tracepoint mdss
, quindi potrebbe non essere incluso nel SoC.)
Successivamente, mdss_fb0
si riattiva sulla CPU 0. mdss_fb0
è il
thread del kernel della pipeline display per l'output di un frame sottoposto a rendering al display.
Possiamo vedere mdss_fb0
come riga separata nella traccia (scorri verso il basso fino
).
mdss_fb0
si sveglia, corre per un breve momento, entra in un sonno ininterrotto
e poi si riattiva.
Esempio: frame non funzionante
Questo esempio descrive una procedura di sistema utilizzata per eseguire il debug del tremolio di Pixel/Pixel XL. A
segui l'esempio, scarica il file zip
file di tracce (che include altre tracce a cui viene fatto riferimento
), decomprimi il file e apri il file systrace_tutorial.html
nel tuo
del browser.
Quando apri systrace, vedrai qualcosa di simile a questo:
.Quando cerchi jank, controlla la riga FrameFailed in SurfaceFlinger.
FrameNon è un miglioramento della qualità della vita fornito da HWC2. Durante la visualizzazione
systrace per altri dispositivi, la riga Framepers potrebbe non essere presente se il dispositivo
non utilizza HWC2. In
nel caso in cui l'oggetto FrameNon sia correlato, con SurfaceFlinger che manca uno dei suoi
runtime estremamente regolari e un conteggio del buffer in sospeso per l'app invariato
(com.prefabulated.touchlatency
) in modalità vsync.
La figura 11 mostra un frame mancato a 15598.29&nbps;ms. SurfaceFlinger si è svegliato brevemente alle ore l'intervallo vsync e si è ripreso a dormire senza fare nulla, il che significa SurfaceFlinger ha stabilito che non valeva la pena provare a inviare un frame al display di nuovo. Perché?
Per comprendere la suddivisione della pipeline per questo frame, esamina prima la sezione l'esempio di frame di lavoro riportato sopra per vedere come appare una normale pipeline dell'interfaccia utente in systrace. Quando hai finito, torna al frame mancante e torna indietro. Nota che SurfaceFlinger si attiva e va subito a dormire. Quando viene visualizzato il numero di in attesa da Touch Latenza, ci sono due frame (un buon indizio capire cosa sta succedendo).
.Il fatto che SurfaceFlinger contiene frame non è un problema dell'app. Inoltre, SurfaceFlinger si sta svegliando all'ora corretta, quindi non è un SurfaceFlinger problema. Se SurfaceFlinger e l'app sembrano normali, probabilmente problema del driver.
Poiché le tracce di mdss
e sync
sono abilitate,
possiamo ottenere informazioni sulle recinzioni (condivise tra il conducente del display e
SurfaceFlinger) che controllano quando i frame vengono inviati al display.
Queste recinzioni sono elencate alla voce mdss_fb0_retire
, che
indica quando è visualizzato un frame. Questi recinti sono forniti come
che fanno parte della categoria di traccia sync
. A quali recinti corrispondono
eventi particolari in SurfaceFlinger dipendono dal SOC e dallo stack di driver,
collabora con il fornitore del tuo SOC per capire il significato delle categorie di recinzioni nel tuo
le tracce audio.
La Figura 13 mostra un frame visualizzato per 33 ms, non 16,7 ms come previsto. A metà di questa sezione, il frame dovrebbe essere stato sostituito con uno nuovo. ma non lo era. Visualizza il frame precedente e cerca qualsiasi cosa.
.La Figura 14 mostra 14,482 ms per frame. Il segmento a due frame rotto è stato di 33,6 ms, che è più o meno come ci aspettiamo per due frame (il rendering viene eseguito a 60 Hz, 16,7 ms per frame, ossia vicino). Ma 14,482 ms non è vicino a 16,7 ms, qualcosa che non va nella tubazione del display.
Indaga esattamente dove finisce quella recinzione per determinare cosa la controlla.
.Una coda di lavoro contiene __vsync_retire_work_handler
, ovvero
in funzione quando il recinto cambia. Osservando il codice sorgente del kernel, puoi vedere che
ma fa parte del driver del display. Sembra che si trovi nel punto critico
per la pipeline di visualizzazione, in modo che venga eseguita il più rapidamente possibile. È
eseguibile per circa 70 noi (non un lungo ritardo di pianificazione), ma è una coda di lavoro
potrebbero non essere programmati in modo accurato.
Controlla il frame precedente per verificare se ciò ha contribuito al risultato. a volte si tremolano possono sommarsi nel tempo e causare una scadenza non rispettata.
.La linea eseguibile sul kworker non è visibile perché lo spettatore la ruota
bianco quando è selezionato, ma le statistiche raccontano: 2,3 ms di scheduler
il ritardo per parte del percorso critico della pipeline di visualizzazione è non valido.
Prima di continuare, correggi il ritardo spostando questa parte del
visualizzare il percorso critico della pipeline da una coda di lavoro (che viene eseguita come
SCHED_OTHER
thread CFS) a un SCHED_FIFO
dedicato
kthread. Questa funzione richiede garanzie di temporizzazione che le code di lavoro non possono (e non sono
fornire.
È questo il motivo del jank? È difficile dire con certezza. Al di fuori di casi facili da diagnosticare come il conflitto di blocchi del kernel che causano i thread durante il sonno, le tracce solitamente non specificano il problema. È possibile che questo tremolio sia la causa della caduta del frame? Certamente. La i tempi di fence dovrebbero essere di 16,7 ms, ma non sono affatto simili a quelli nei frame fino al frame caduto. Dato il grado di stretto accoppiamento della pipeline display è che è possibile che il tremolio dei tempi del recinto abbia causato un calo frame.
In questo esempio, la soluzione prevedeva la conversione
__vsync_retire_work_handler
da una coda di lavoro a un
kthread. Ciò ha portato a notevoli miglioramenti del tremolio e a una riduzione del jank
prova della palla che rimbalza. Le tracce successive mostrano tempi di recinto che si muovono molto vicini
a 16,7 ms.