Android 8.0 include test delle prestazioni di binder e hwbinder per la velocità effettiva e una latenza di pochi millisecondi. Sebbene esistano molti scenari per il rilevamento di prestazioni percepibili problemi, l'esecuzione di questi scenari può richiedere molto tempo e i risultati sono spesso non è disponibile prima dell'integrazione di un sistema. Utilizzo del rendimento fornito semplifica i test durante lo sviluppo, rileva problemi gravi e migliorare l'esperienza utente.
I test del rendimento includono le seguenti quattro categorie:
- binder (disponibile in
system/libhwbinder/vts/performance/Benchmark_binder.cpp
- di latenza di binder (disponibile
frameworks/native/libs/binder/tests/schd-dbg.cpp
- velocità effettiva hwbinder (disponibile in
system/libhwbinder/vts/performance/Benchmark.cpp
- latenza hwbinder (disponibile in
system/libhwbinder/vts/performance/Latency.cpp
Informazioni su binder e hwbinder
Binder e hwbinder sono comunicazione tra processi (IPC, Android Inter-Process Communication) che condividono lo stesso driver Linux ma hanno differenze qualitative:
Aspetto | raccoglitore | Hwbinder |
---|---|---|
Finalità | Fornisci uno schema IPC per uso generico per il framework | Comunica con l'hardware |
Proprietà | Ottimizzato per l'utilizzo del framework Android | Bassa latenza di overhead minimo |
Modifica il criterio di pianificazione per il primo piano o lo sfondo | Sì | No |
Argomenti superati | Usa la serializzazione supportata dall'oggetto Parcel | Utilizza i buffer a dispersione ed evita l'overhead per la copia dei dati richiesti Serializzazione del pacco |
Eredità della priorità | No | Sì |
Processi Binder e hwbinder
Un visualizzatore di systrace mostra le transazioni come segue:
Nell'esempio riportato sopra:
- I quattro (4) processi schd-dbg sono processi client.
- I quattro (4) processi del binder sono processi server (il nome inizia con Binder e termina con un numero di sequenza).
- Un processo client è sempre associato a un processo server, dedicato al proprio client.
- Tutte le coppie di processi client-server sono pianificate in modo indipendente dal kernel contemporaneamente.
Nella CPU 1, il kernel del sistema operativo esegue il client per emettere la richiesta. Poi utilizza la stessa CPU quando è possibile per riattivare un processo server, gestire per poi passare nuovamente al contesto una volta completata la richiesta.
Velocità effettiva e latenza
In una transazione perfetta, in cui i processi del client e del server scambiano senza interruzioni, i test di velocità effettiva e latenza non producono messaggi. Tuttavia, quando il kernel del sistema operativo gestisce una richiesta di interruzione (IRQ) dall'hardware, attendere le serrature o semplicemente scegliere di non gestire un messaggio immediatamente, si può formare una bolla di latenza.
Il test della velocità effettiva genera un numero elevato di transazioni con dimensioni del payload, fornendo una buona stima del tempo di transazione regolare (in nei casi migliori) e la velocità effettiva massima che il binder può raggiungere.
Al contrario, il test di latenza non esegue alcuna azione sul payload per ridurre al minimo la normale durata della transazione. Possiamo usare il tempo della transazione per stimare il raccoglitore overhead, calcola le statistiche per il caso peggiore e calcola il rapporto transazioni la cui latenza soddisfa una scadenza specificata.
Gestire le inversioni di priorità
Si verifica un'inversione di priorità quando un thread con priorità più alta è logicamente in attesa di un thread con priorità inferiore. Le applicazioni Real-Time (RT) hanno un problema di inversione di priorità:
Quando si utilizza la pianificazione Linux Completely Fair Scheduler (CFS), un thread possono essere eseguiti anche quando altri thread hanno una priorità più alta. Di conseguenza, le applicazioni con pianificazione CFS gestiscono l'inversione di priorità come previsto e non come un problema. Nei casi in cui il framework Android richieda una pianificazione RT per garantire il privilegio dei thread ad alta priorità, tuttavia, l'inversione della priorità devono essere risolti.
Esempio di inversione della priorità durante una transazione binder (il thread RT è bloccati logicamente da altri thread CFS durante l'attesa di un thread binder di servizio):
Per evitare blocchi, puoi utilizzare l'ereditarietà prioritaria per riassegnare temporaneamente il thread Binder a un thread RT quando gestisce una richiesta da un client RT. Tieni presente che la pianificazione RT ha risorse limitate e deve essere utilizzata con attenzione. In un sistema con n CPU, il numero massimo di istanze RT attuali i thread sono anch'essi n; potrebbe essere necessario attendere altri thread RT (e quindi non rispettano le scadenze) se tutte le CPU sono prese da altri thread RT.
Per risolvere tutte le possibili inversioni di priorità, puoi utilizzare la priorità ereditarietà sia per binder che per hwbinder. Tuttavia, poiché il legante è ampiamente utilizzato nel sistema, l'abilitazione dell'ereditarietà prioritaria per le transazioni binder potrebbe inviare spam al sistema con più thread RT di quanti ne possa servire.
Esegui test della velocità effettiva
Il test della velocità effettiva viene eseguito rispetto alla velocità effettiva delle transazioni binder/hwbinder. Nella un sistema non sovraccarico, le bolle di latenza sono rare e il loro impatto può essere eliminato purché il numero di iterazioni sia sufficientemente elevato.
- Il test della velocità effettiva binder è in corso
system/libhwbinder/vts/performance/Benchmark_binder.cpp
. - Il test della velocità effettiva hwbinder è in
system/libhwbinder/vts/performance/Benchmark.cpp
.
Risultati del test
Esempi di risultati del test della velocità effettiva per le transazioni che utilizzano payload diversi dimensioni:
Benchmark Time CPU Iterations --------------------------------------------------------------------- BM_sendVec_binderize/4 70302 ns 32820 ns 21054 BM_sendVec_binderize/8 69974 ns 32700 ns 21296 BM_sendVec_binderize/16 70079 ns 32750 ns 21365 BM_sendVec_binderize/32 69907 ns 32686 ns 21310 BM_sendVec_binderize/64 70338 ns 32810 ns 21398 BM_sendVec_binderize/128 70012 ns 32768 ns 21377 BM_sendVec_binderize/256 69836 ns 32740 ns 21329 BM_sendVec_binderize/512 69986 ns 32830 ns 21296 BM_sendVec_binderize/1024 69714 ns 32757 ns 21319 BM_sendVec_binderize/2k 75002 ns 34520 ns 20305 BM_sendVec_binderize/4k 81955 ns 39116 ns 17895 BM_sendVec_binderize/8k 95316 ns 45710 ns 15350 BM_sendVec_binderize/16k 112751 ns 54417 ns 12679 BM_sendVec_binderize/32k 146642 ns 71339 ns 9901 BM_sendVec_binderize/64k 214796 ns 104665 ns 6495
- Tempo indica il ritardo di andata e ritorno misurato in tempo reale.
- CPU indica il tempo accumulato durante la pianificazione delle CPU per il test.
- Iterazioni indica il numero di volte in cui la funzione di test eseguito.
Ad esempio, per un payload a 8 byte:
BM_sendVec_binderize/8 69974 ns 32700 ns 21296
...la velocità effettiva massima che il binder può raggiungere viene calcolata come segue:
Velocità effettiva MASSIMA con payload a 8 byte = (8 * 21296)/69974 ~= 2,423 b/ns ~= 2,268 Gb/s
Opzioni di test
Per ottenere i risultati in formato .json, esegui il test con
--benchmark_format=json
argomento:
libhwbinder_benchmark --benchmark_format=json
{
"context": {
"date": "2017-05-17 08:32:47",
"num_cpus": 4,
"mhz_per_cpu": 19,
"cpu_scaling_enabled": true,
"library_build_type": "release"
},
"benchmarks": [
{
"name": "BM_sendVec_binderize/4",
"iterations": 32342,
"real_time": 47809,
"cpu_time": 21906,
"time_unit": "ns"
},
….
}
Esegui test di latenza
Il test di latenza misura il tempo necessario per l'avvio del client inizializzare la transazione, passare al processo server per la gestione e ricevere il risultato. Il test ricerca anche i comportamenti noti dello scheduler che può influire negativamente sulla latenza delle transazioni, ad esempio uno scheduler che non supportare l'ereditarietà della priorità o rispettare il flag di sincronizzazione.
- Il test di latenza del binder è in corso
frameworks/native/libs/binder/tests/schd-dbg.cpp
. - Il test di latenza hwbinder è in corso
system/libhwbinder/vts/performance/Latency.cpp
.
Risultati del test
I risultati (in .json) mostrano le statistiche per la latenza media/migliore/peggiore di scadenze non rispettate.
Opzioni di test
I test di latenza prevedono le seguenti opzioni:
Comando | Descrizione |
---|---|
-i value |
Specifica il numero di iterazioni. |
-pair value |
Specifica il numero di coppie di processi. |
-deadline_us 2500 |
Specifica la scadenza. |
-v |
Ottieni un output dettagliato (debug). |
-trace |
Interrompi la traccia in caso di hit da scadenza. |
Le seguenti sezioni descrivono nel dettaglio ciascuna opzione, descrivono l'utilizzo e forniscono di risultati di esempio.
Specifica le iterazioni
Esempio con un numero elevato di iterazioni e output dettagliato disattivati:
libhwbinder_latency -i 5000 -pair 3
{
"cfg":{"pair":3,"iterations":5000,"deadline_us":2500},
"P0":{"SYNC":"GOOD","S":9352,"I":10000,"R":0.9352,
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996},
"fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
},
"P1":{"SYNC":"GOOD","S":9334,"I":10000,"R":0.9334,
"other_ms":{ "avg":0.19, "wst":2.9 , "bst":0.055, "miss":2, "meetR":0.9996},
"fifo_ms": { "avg":0.16, "wst":3.1 , "bst":0.066, "miss":1, "meetR":0.9998}
},
"P2":{"SYNC":"GOOD","S":9369,"I":10000,"R":0.9369,
"other_ms":{ "avg":0.19, "wst":4.8 , "bst":0.055, "miss":6, "meetR":0.9988},
"fifo_ms": { "avg":0.15, "wst":1.8 , "bst":0.067, "miss":0, "meetR":1}
},
"inheritance": "PASS"
}
I risultati di questi test mostrano quanto segue:
"pair":3
- Crea una coppia client-server.
"iterations": 5000
- Include 5000 iterazioni.
"deadline_us":2500
- La scadenza è 2500us (2,5 ms); la maggior parte delle transazioni dovrebbe soddisfare questo valore.
"I": 10000
- Una singola iterazione di test include due (2) transazioni:
- Una transazione con priorità normale (
CFS other
) - Una transazione con priorità in tempo reale (
RT-fifo
)
- Una transazione con priorità normale (
"S": 9352
- 9352 transazioni vengono sincronizzate nella stessa CPU.
"R": 0.9352
- Indica il rapporto in base al quale il client e il server vengono sincronizzati insieme la stessa CPU.
"other_ms":{ "avg":0.2 , "wst":2.8 , "bst":0.053, "miss":2, "meetR":0.9996}
- Media (
avg
), peggiore (wst
) e migliore (bst
) per tutte le transazioni emesse da un chiamante con priorità normale. Due transazionimiss
la scadenza, per rientrare nell'indice (meetR
) 0,9996. "fifo_ms": { "avg":0.16, "wst":1.5 , "bst":0.067, "miss":0, "meetR":1}
- Simile a
other_ms
, ma per le transazioni emesse dal cliente con Prioritàrt_fifo
. È probabile (ma non obbligatorio) chefifo_ms
ha un risultato migliore diother_ms
, con meno Valoriavg
ewst
e un valore dimeetR
più alto (la differenza può essere ancora più significativa con il caricamento in background).
Nota:il carico in background potrebbe influire sulla velocità effettiva.
e la tupla other_ms
nel test di latenza. Solo il
fifo_ms
potrebbe mostrare risultati simili a condizione che il caricamento in background sia
con una priorità inferiore a RT-fifo
.
Specifica i valori di coppia
Ogni processo del client è abbinato a un processo server dedicato al client,
e ogni coppia può essere pianificata in modo indipendente per qualsiasi CPU. Tuttavia, la CPU
la migrazione non dovrebbe avvenire durante una transazione, purché il flag SYNC sia
honor
.
Accertati che il sistema non sia sovraccarico. Mentre la latenza elevata in un ambiente sovraccaricato
sistema è previsto, i risultati del test per un sistema sovraccarico non forniscono utili
informazioni. Per testare un impianto con una pressione più elevata, usa -pair
#cpu-1
(o -pair #cpu
con cautela). Test con
-pair n
con n > #cpu
sovraccarica
sistema e genera informazioni inutili.
Specifica i valori delle scadenze
Dopo un ampio test degli scenari utente (l'esecuzione del test di latenza su una prodotto idoneo), abbiamo stabilito che la scadenza è di 2,5 ms. Per nuovi per applicazioni con requisiti più elevati (ad esempio 1000 foto/secondo), questo il valore della scadenza cambierà.
Specifica un output dettagliato
Se utilizzi l'opzione -v
, viene visualizzato un output dettagliato. Esempio:
libhwbinder_latency -i 1 -v
-------------------------------------------------- service pid: 8674 tid: 8674 cpu: 1 SCHED_OTHER 0-------------------------------------------------- main pid: 8673 tid: 8673 cpu: 1 -------------------------------------------------- client pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0-------------------------------------------------- fifo-caller pid: 8677 tid: 8678 cpu: 0 SCHED_FIFO 99 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 ??? 99-------------------------------------------------- other-caller pid: 8677 tid: 8677 cpu: 0 SCHED_OTHER 0 -------------------------------------------------- hwbinder pid: 8674 tid: 8676 cpu: 0 SCHED_OTHER 0
- Il thread di servizio viene creato con un oggetto
Priorità
SCHED_OTHER
ed esecuzione inCPU:1
conpid 8674
. - La prima transazione viene quindi avviata da un
fifo-caller
. Per gestire questa transazione, hwbinder esegue l'upgrade del file la priorità del server (pid: 8674 tid: 8676
) sia 99 e la contrassegna anche con una classe di pianificazione temporanea (stampata come???
). Scheduler quindi inserisce il processo del server inCPU:0
e lo sincronizza con con il proprio client. - Il chiamante della seconda transazione ha un
Priorità
SCHED_OTHER
. Il server esegue il downgrade stesso e gestisce il servizio chiamante con prioritàSCHED_OTHER
.
Usa traccia per debug
Puoi specificare l'opzione -trace
per eseguire il debug dei problemi di latenza. Quando
utilizzata, il test di latenza interrompe la registrazione del tracelog nel momento in cui
rilevata la latenza. Esempio:
atrace --async_start -b 8000 -c sched idle workq binder_driver sync freq
libhwbinder_latency -deadline_us 50000 -trace -i 50000 -pair 3
deadline triggered: halt ∓ stop trace log:/sys/kernel/debug/tracing/trace
I seguenti componenti possono influire sulla latenza:
- Modalità build Android. La modalità Eng è solitamente più lenta di modalità utente di debug.
- Framework. Come utilizza il servizio framework
ioctl
per la configurazione nel raccoglitore? - Driver raccoglitore. Il driver supporta l'ottimizzazione il blocco? Contiene tutte le patch di aggiornamento delle prestazioni?
- Versione kernel. Migliore è la capacità in tempo reale del kernel, migliori sono i risultati.
- Configurazione del kernel. La configurazione del kernel contiene
Configurazioni di
DEBUG
comeDEBUG_PREEMPT
eDEBUG_SPIN_LOCK
? - Strumento di pianificazione del kernel. Il kernel ha un sistema di gestione
scheduler (EAS) o scheduler eterogeneo multi-processing (HMP)? Esegui qualsiasi kernel
conducenti (
cpu-freq
autista,cpu-idle
autista,cpu-hotplug
e così via) influiscono sullo scheduler?