La mia ipotesi di base è che quando i soli fattori limitanti di un processo sono il disco e la CPU, l'utilizzo totale della CPU "iowait" + CPU dovrebbe essere pari almeno al 100% di una CPU logica. (In altri casi questo non regge. Ad esempio quando si scarica un file utilizzando wget, la rete è spesso il fattore limitante).
Questa ipotesi è violata da un semplice test. È previsto? Se è previsto, c'è una serie di condizioni in cui dovrei aspettarmi che la mia ipotesi sia vera?
Ci sono alcuni retroscena su "iowait" qui: come fa una CPU a sapere che c'è IO in sospeso? La risposta qui cita l'idea contro-intuitiva, secondo cui lo iowait cumulativo "può diminuire in determinate condizioni". Mi chiedo se il mio semplice test possa innescare una condizione così non documentata?
AGGIORNAMENTO : saltare alla risposta .
La risposta ha un test più semplice di quello che ho usato originariamente. Ho conservato la domanda originale qui sotto. La domanda originale potrebbe mostrare alcuni dettagli aggiuntivi.
Domanda originale
In un breve test, utilizzo ddper richiedere al kernel di generare byte casuali e scriverli in un file. Eseguo il ddcomando all'interno perf stat, solo per ottenere un conteggio del tempo di CPU trascorso all'interno del kernel. Lo eseguo anche all'interno perf trace -s, per segnalare il tempo trascorso all'interno write(). Allo stesso tempo, corro vmstat 5su un altro terminale, per vedere il sistema "iowait".
- Mi aspettavo di vedere almeno un'intera CPU come "non inattiva", ovvero il 100% delle volte che è in esecuzione o arrestata ma in attesa di IO (stato "iowait"). Non era.
- (Inoltre, mi aspettavo di vedere che il tempo "iowait" corrispondeva approssimativamente al tempo trascorso in write (). Ma non sembrava farlo.)
I risultati dettagliati e l'ambiente di test sono mostrati di seguito. Viene anche mostrato un test alternativo, in cui la mia ipotesi ha tenuto. Nota: era necessario correre perf statall'interno perf trace, non viceversa. Questo è dettagliato qui: "perf stat" (e "time"!) Mostra risultati errati quando si esegue "perf trace - s"?
Informazioni di base su "iowait"
Di seguito è la definizione presa dalla
sarmanpage:% Iowait:
Percentuale di tempo in cui la CPU o le CPU erano inattive durante le quali il sistema aveva una richiesta di I / O su disco in sospeso.
Pertanto,% iowait significa che dal punto di vista della CPU, nessuna attività era eseguibile, ma era in corso almeno un I / O. iowait è semplicemente una forma di tempo di inattività in cui nulla può essere programmato. Il valore può essere utile o meno per indicare un problema di prestazioni, ma indica all'utente che il sistema è inattivo e potrebbe aver richiesto più lavoro.
https://support.hpe.com/hpsc/doc/public/display?docId=c02783994
C'è anche un articolo più lungo: Comprendere I / O Wait (o perché lo 0% inattivo può essere OK) . Questo spiega come è possibile vedere chiaramente la definizione dal codice del kernel. Il codice è leggermente cambiato, ma l'idea è ancora chiara:
/*
* Account for idle time.
* @cputime: the CPU time spent in idle wait
*/
void account_idle_time(u64 cputime)
{
u64 *cpustat = kcpustat_this_cpu->cpustat;
struct rq *rq = this_rq();
if (atomic_read(&rq->nr_iowait) > 0)
cpustat[CPUTIME_IOWAIT] += cputime;
else
cpustat[CPUTIME_IDLE] += cputime;
}
L'articolo mostra anche una serie di esperimenti correlati su un sistema a CPU singola. Alcuni degli esperimenti usano anche ddcon if=/dev/urandom ! Tuttavia gli esperimenti non includono il mio test dd if=/dev/urandom of=test.out . Usa solo dd if=/dev/urandom of=/dev/null .
"IO aspetta" è un po 'più difficile da pensare ora perché usiamo sistemi multi-CPU, ma penso di averlo ancora capito, basato sul codice citato.
Ambiente
Ho quattro CPU logiche.
Uso LVM e il filesystem ext4. Non sto usando alcuna crittografia sul mio disco o filesystem. Non ho alcun filesystem di rete montato, quindi non sto leggendo o scrivendo un filesystem di rete.
I seguenti risultati provengono dal kernel 4.20.15-200.fc29.x86_64, usando lo noopscheduler IO. Anche lo cfqscheduler IO fornisce risultati simili.
(Ho anche visto risultati simili su una build del kernel che si basava su una configurazione simile, ma era più vicina alla versione 5.1 del kernel e all'utilizzo mq-deadline. Quindi utilizzava il nuovo blk-mqcodice).
Test e risultati
$ sudo perf trace -s \
perf stat \
dd if=/dev/urandom of=test.out bs=1M oflag=direct count=3000
3000+0 records in
3000+0 records out
3145728000 bytes (3.1 GB, 2.9 GiB) copied, 31.397 s, 100 MB/s
Performance counter stats for 'dd if=/dev/urandom of=test.out bs=1M oflag=direct count=3000':
18,014.26 msec task-clock # 0.574 CPUs utilized
3,199 context-switches # 0.178 K/sec
4 cpu-migrations # 0.000 K/sec
328 page-faults # 0.018 K/sec
45,232,163,658 cycles # 2.511 GHz
74,538,278,379 instructions # 1.65 insn per cycle
4,372,725,344 branches # 242.737 M/sec
4,650,429 branch-misses # 0.11% of all branches
31.398466725 seconds time elapsed
0.006966000 seconds user
17.910332000 seconds sys
Summary of events:
...
dd (4620), 12156 events, 12.0%
syscall calls total min avg max stddev
(msec) (msec) (msec) (msec) (%)
--------------- -------- --------- --------- --------- --------- ------
read 3007 17624.985 0.002 5.861 12.345 0.21%
write 3003 13722.837 0.004 4.570 179.928 2.63%
openat 12 0.371 0.002 0.031 0.267 70.36%
...
Ho letto la iowaitfigura dalla wacolonna di vmstat. Puoi sapere quando il test è in esecuzione guardando la iocolonna ( bo= 1K blocchi di output).
$ vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 5126892 176512 1486060 0 0 1788 4072 321 414 4 4 83 9 0
1 0 0 5126632 176520 1485988 0 0 0 7 212 405 0 1 99 0 0
0 0 0 5126884 176520 1485988 0 0 0 0 130 283 0 0 99 0 0
0 0 0 5126948 176520 1485908 0 0 0 1 157 325 0 0 99 0 0
0 0 0 5126412 176520 1486412 0 0 115 0 141 284 0 0 99 0 0
0 2 0 5115724 176548 1487056 0 0 0 6019 18737 10733 3 6 89 2 0
1 0 0 5115708 176580 1487104 0 0 3 91840 1276 990 0 13 77 9 0
1 0 0 5115204 176600 1487128 0 0 2 91382 1382 1014 0 14 81 4 0
1 0 0 5115268 176636 1487084 0 0 4 88281 1257 901 0 14 83 3 0
0 1 0 5113504 177028 1487764 0 0 77 92596 1374 1111 0 15 83 2 0
1 0 0 5114008 177036 1487768 0 0 0 113282 1460 1060 0 16 81 2 0
1 0 0 5113472 177044 1487792 0 0 0 110821 1489 1118 0 16 74 10 0
0 0 0 5123852 177068 1487896 0 0 0 20537 631 714 1 3 94 2 0
0 0 0 5123852 177076 1487856 0 0 0 10 324 529 2 1 98 0 0
2 0 0 5123852 177084 1487872 0 0 0 70 150 299 0 0 99 0 0
Risultati dei test in cui si trova (all'interno di una VM)
Ho provato lo stesso test all'interno di una VM con 1 CPU, che eseguiva il kernel 5.0.9-301.fc30.x86_64e utilizzava mq-deadline(e quindi blk-mq). In questo test, ha funzionato come mi aspettavo.
$ sudo perf trace -s \
perf stat \
dd if=/dev/urandom of=test.out bs=1M oflag=direct count=3000
[sudo] password for alan-sysop:
3000+0 records in
3000+0 records out
3145728000 bytes (3.1 GB, 2.9 GiB) copied, 46.8071 s, 67.2 MB/s
Performance counter stats for 'dd if=/dev/urandom of=test.out bs=1M oflag=direct count=3000':
18,734.89 msec task-clock # 0.400 CPUs utilized
16,690 context-switches # 0.891 K/sec
0 cpu-migrations # 0.000 K/sec
328 page-faults # 0.018 K/sec
<not supported> cycles
<not supported> instructions
<not supported> branches
<not supported> branch-misses
46.820355993 seconds time elapsed
0.011840000 seconds user
18.531449000 seconds sys
Summary of events:
...
dd (1492), 12156 events, 38.4%
syscall calls total min avg max stddev
(msec) (msec) (msec) (msec) (%)
--------------- -------- --------- --------- --------- --------- ------
write 3003 28269.070 0.019 9.414 5764.657 22.39%
read 3007 18371.469 0.013 6.110 14.848 0.53%
execve 6 10.399 0.012 1.733 10.328 99.18%
...
Uscita di vmstat 5:
$ vmstat 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 726176 52128 498508 0 0 2040 231 236 731 7 5 77 11 0
0 0 0 726176 52136 498508 0 0 0 10 25 46 0 0 99 1 0
0 0 0 726208 52136 498508 0 0 0 0 29 56 0 0 100 0 0
0 1 0 702280 55944 511780 0 0 2260 13109 4399 9049 3 17 55 25 0
0 1 0 701776 56040 511960 0 0 18 129582 1406 1458 0 73 0 27 0
0 2 0 701524 56156 512168 0 0 22 87060 960 991 0 50 0 50 0
3 1 0 701524 56228 512328 0 0 14 118170 1301 1322 0 68 0 32 0
1 1 0 701272 56260 512392 0 0 6 86426 994 982 0 53 0 46 0
0 2 0 701020 56292 512456 0 0 6 56115 683 660 0 37 0 63 0
3 2 0 700540 56316 512504 0 0 5 33450 446 457 0 26 0 74 0
0 2 0 700860 56332 512536 0 0 3 16998 311 240 0 19 0 81 0
1 2 0 700668 56368 512616 0 0 7 32563 443 428 0 24 0 76 0
1 0 0 700668 56392 512648 0 0 3 20338 245 272 0 12 0 88 0
0 1 0 707096 56408 512920 0 0 54 20913 312 530 0 12 79 8 0
0 0 0 707064 56432 512920 0 0 0 49 39 64 0 0 45 55 0
0 0 0 707064 56432 512920 0 0 0 0 24 46 0 0 100 0 0
0 0 0 707064 56432 512920 0 0 0 80 28 47 0 0 100 0 0
Ho provato ad aggiungere a caldo una CPU alla VM e testare di nuovo. I risultati erano variabili: a volte mostrava circa lo 0% nella colonna inattiva, e talvolta mostrava circa il 50% inattiva (ovvero una CPU su due). Nel caso dello 0% "inattivo", "iowait" era molto alto, vale a dire più di una CPU. Cioè il mio punto di aspettativa 2 non era corretto. Posso accettare a malincuore questa apparente limitazione di "iowait" sui sistemi multi-CPU. (Anche se non lo capisco del tutto. Se qualcuno vuole spiegarlo esattamente, sarebbe fantastico). Tuttavia, in entrambi i casi "inattivo" non era superiore al 50%, quindi questi test erano ancora coerenti con la mia prima ipotesi su "iowait".
Ho provato a spegnere la VM e avviarla con 4 CPU. Allo stesso modo, spesso avevo esattamente il 75% di inattività e talvolta avevo un minimo di 50% di inattività, ma non vedevo più del 75% di inattività (ovvero più di tre CPU su quattro).
Considerando che sul sistema fisico con 4 CPU, posso ancora riprodurre il risultato di oltre l'80% inattivo, come mostrato sopra.
this_rq()->nr_iowaitsia il numero di attività che sono in attesa di essere utilizzate solo io_schedule() sulla CPU corrente . Ho sbagliato?
iowaitcerca di misurare il tempo speso aspettando l'I / O, in generale. Non è monitorato da una CPU specifica, né può essere" . Lasciami sottolineare che non ne sono certo, sto solo esprimendo sorpresa.
atop, o atopsar -c 5vedrai cifre sull'utilizzo per CPU. Includono iowait e le cifre iowait per CPU possono mostrare valori diversi, diversi da zero :-). Oppure sar -P ALL 1, se non si utilizza atop. Questo è il modo in cui il iowaitmodello è stato esteso per i sistemi multi-CPU ... Quello che non sono chiaro è se questo modello è effettivamente utilizzabile o se questo è un modo che consente al codice iowait di continuare a funzionare quando c'è solo una CPU online, ma per il resto non è affidabile.