สมมติฐานพื้นฐานของฉันคือเมื่อกระบวนการ 'จำกัด ปัจจัยเพียงอย่างเดียวคือดิสก์และ CPU ดังนั้นการใช้งาน CPU "iowait" + ระบบทั้งหมดควรเท่ากับ 100% อย่างน้อยหนึ่งโลจิคัล CPU (ในกรณีอื่น ๆ สิ่งนี้จะไม่ถูกเก็บไว้เช่นเมื่อดาวน์โหลดไฟล์โดยใช้wgetเครือข่ายมักเป็นปัจจัย จำกัด )
สมมติฐานนี้ถูกละเมิดโดยการทดสอบอย่างง่าย คาดหวังหรือไม่ หากคาดว่าจะมีเงื่อนไขใดบ้างที่ฉันควรคาดว่าการสันนิษฐานของฉันจะเป็นจริงหรือไม่?
มีพื้นหลังเกี่ยวกับ "iowait" อยู่ที่นี่: CPU รู้ได้อย่างไรว่ามี IO ค้างอยู่ คำตอบที่นี่เป็นการเสนอราคาแนวคิดแบบตอบโต้ง่าย ๆ ว่าไอโออิทแบบสะสม "อาจลดลงในเงื่อนไขบางประการ" ฉันสงสัยว่าการทดสอบอย่างง่ายของฉันสามารถเปิดใช้งานเงื่อนไขที่ไม่มีเอกสารหรือไม่?
คำตอบมีการทดสอบที่ง่ายกว่าที่ฉันเคยใช้ ฉันเก็บคำถามเดิมไว้ด้านล่าง คำถามเดิมอาจแสดงรายละเอียดเพิ่มเติมบางอย่าง
คำถามเดิม
ในการทดสอบสั้น ๆ ฉันใช้ddเพื่อขอเคอร์เนลเพื่อสร้างไบต์แบบสุ่มและเขียนลงในไฟล์ ฉันรันddคำสั่งด้านในperf statเพื่อรับจำนวนเวลา CPU ที่ใช้ภายในเคอร์เนล ฉันก็วิ่งเข้าไปข้างในperf trace -sเพื่อรายงานเวลาที่ใช้write()ไป ในเวลาเดียวกันฉันทำงานvmstat 5ในสถานีอื่นเพื่อดูระบบ "iowait"
- ฉันคาดหวังว่าฉันจะเห็น CPU ทั้งหมดอย่างน้อยหนึ่งตัวเป็น "ไม่ได้ใช้งาน" นั่นคือ 100% ของเวลาที่กำลังทำงานหรือหยุดทำงาน แต่รอสถานะ IO ("iowait") มันไม่ใช่
- (นอกจากนี้ฉันคาดหวังว่าจะเห็นเวลา "iowait" ตรงกับเวลาที่ใช้ในการเขียน () แต่ดูเหมือนจะไม่ทำเช่นนั้น)
ผลลัพธ์โดยละเอียดและสภาพแวดล้อมการทดสอบแสดงไว้ด้านล่าง ก็แสดงให้เห็นว่าเป็นการทดสอบทางเลือกที่ฉันถือสมมติฐาน หมายเหตุ: จำเป็นต้องเรียกใช้perf statภายในperf traceไม่ใช่วิธีอื่น นี่คือรายละเอียดที่นี่: "perf stat" (และ "time"!) แสดงผลลัพธ์ที่ไม่ถูกต้องเมื่อเรียกใช้ "perf trace-s" หรือไม่
ข้อมูลความเป็นมาของ "iowait"
ต่อไปนี้เป็นคำจำกัดความที่นำมาจาก
sarmanpage:% iowait:
เปอร์เซ็นต์เวลาที่ CPU หรือ CPU ไม่ได้ทำงานในระหว่างที่ระบบมีดิสก์ I / O ที่ค้างอยู่
ดังนั้น% iowait จึงหมายความว่าจากมุมมองของ CPU ไม่มีภารกิจใดถูกรันได้ แต่อย่างน้อยหนึ่ง I / O กำลังดำเนินการอยู่ iowait เป็นเพียงรูปแบบของเวลาว่างเมื่อไม่มีอะไรสามารถกำหนด ค่าอาจหรือไม่อาจมีประโยชน์ในการระบุปัญหาประสิทธิภาพ แต่มันบอกผู้ใช้ว่าระบบไม่ได้ใช้งานและอาจมีการทำงานมากขึ้น
https://support.hpe.com/hpsc/doc/public/display?docId=c02783994
นอกจากนี้ยังมีบทความอีกต่อไป: การทำความเข้าใจของ I / O รอ (หรือทำไม 0% ไม่ได้ใช้งานสามารถ OK) สิ่งนี้อธิบายวิธีที่คุณสามารถดูคำจำกัดความที่ชัดเจนจากโค้ดเคอร์เนล รหัสมีการเปลี่ยนแปลงบ้าง แต่แนวคิดยังคงชัดเจน:
/*
* 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;
}
บทความนี้ยังแสดงจำนวนของการทดลองที่เกี่ยวข้องในระบบ CPU เดียว การทดลองบางอย่างใช้ddกับif=/dev/urandom ! dd if=/dev/urandom of=test.out อย่างไรก็ตามการทดลองไม่รวมถึงการทดสอบของฉัน dd if=/dev/urandom of=/dev/null มันใช้เพียง
"รอ IO" เป็นเรื่องยากมากที่จะคิดในขณะนี้เพราะเราใช้ระบบหลาย CPU แต่ฉันคิดว่าฉันยังคงเข้าใจมันตามรหัสที่ยกมา
สิ่งแวดล้อม
ฉันมี CPU เชิงตรรกะสี่ตัว
ฉันใช้ LVM และระบบไฟล์ ext4 ฉันไม่ได้ใช้การเข้ารหัสบนดิสก์หรือระบบไฟล์ของฉัน ฉันไม่มีระบบไฟล์เครือข่ายใด ๆ เลยฉันเลยไม่อ่านหรือเขียนระบบไฟล์เครือข่าย
ผลลัพธ์ด้านล่างมาจากเคอร์เนล4.20.15-200.fc29.x86_64โดยใช้ตัวnoopจัดกำหนดการ IO เครื่องมือcfqจัดกำหนดการ IO ยังให้ผลลัพธ์ที่คล้ายกัน
(ฉันได้เห็นผลลัพธ์ที่คล้ายกันในการสร้างเคอร์เนลซึ่งเป็นไปตามการกำหนดค่าที่คล้ายกัน แต่ใกล้เคียงกับเคอร์เนลเวอร์ชัน 5.1 และการใช้mq-deadlineดังนั้นจึงใช้blk-mqรหัสใหม่)
การทดสอบและผลลัพธ์
$ 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%
...
ผมอ่านiowaitตัวเลขจากคอลัมน์wa vmstatคุณสามารถบอกได้ว่าเมื่อใดที่การทดสอบกำลังทำงานโดยดูที่ioคอลัมน์ ( bo= 1K บล็อกเอาต์พุต)
$ 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
ผลการทดสอบที่จะเก็บไว้ (ภายใน VM)
ฉันลองทดสอบเดียวกันภายใน VM ด้วย 1 CPU ซึ่งใช้เคอร์เนล5.0.9-301.fc30.x86_64และใช้งานmq-deadline(และด้วยเหตุนี้ blk-mq) ในการทดสอบนี้ใช้งานได้ตามที่คาดหวัง
$ 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%
...
ผลลัพธ์ของ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
ฉันลองเพิ่ม CPU ไปยัง VM และทดสอบอีกครั้ง ผลลัพธ์เป็นตัวแปร: บางครั้งมันแสดงให้เห็นประมาณ 0% ในคอลัมน์ว่างและบางครั้งก็แสดงว่าไม่ได้ใช้งานประมาณ 50% (นั่นคือหนึ่งในสอง CPU) ในกรณีของ 0% "idle", "iowait" นั้นสูงมากนั่นคือมี CPU มากกว่าหนึ่งตัว นั่นคือจุดคาดหวังของฉัน 2 ไม่ถูกต้อง ฉันสามารถยอมรับข้อ จำกัดนี้อย่างชัดเจนของ "iowait" ในระบบมัลติซีพียู (แม้ว่าฉันจะไม่เข้าใจเลยทีเดียวถ้ามีคนต้องการอธิบายอย่างแน่นอน อย่างไรก็ตาม "ว่าง" ไม่สูงกว่า 50% ในทั้งสองกรณีดังนั้นการทดสอบเหล่านี้ยังคงสอดคล้องกับข้อสันนิษฐานแรกของฉันเกี่ยวกับ "iowait"
ฉันพยายามปิด VM ลงและเริ่มด้วย 4 CPU ในทำนองเดียวกันบ่อยครั้งที่ฉันมีการใช้งาน 75% อย่างแน่นอนและบางครั้งฉันมีการใช้งานที่ต่ำเป็น 50% แต่ฉันไม่ได้เห็นการใช้งานมากกว่า 75% (เช่นมากกว่าสามในสี่ CPU)
ในขณะที่ระบบฟิสิคัลที่มี CPU 4 ตัวฉันยังคงสามารถทำซ้ำผลลัพธ์ได้มากกว่า 80% ที่ไม่ได้ใช้งานตามที่แสดงไว้ด้านบน
this_rq()->nr_iowaitเป็นจำนวนของงานที่กำลังรอใช้io_schedule() บน CPU ปัจจุบันเท่านั้น ฉันผิดหรือเปล่า?
iowaitพยายามที่จะวัดเวลาที่ใช้ในการรอคอยสำหรับ I / O ในทั่วไป. ก็ไม่ได้ติดตามโดย CPU ที่เฉพาะเจาะจงและไม่สามารถ" ให้ฉันเครียดฉันไม่แน่ใจเรื่องนี้แค่แสดงความประหลาดใจ
atopหรือatopsar -c 5คุณจะเห็นตัวเลขการใช้งานต่อซีพียู ซึ่งรวมถึง iowait และตัวเลข iowait ต่อซีพียูสามารถแสดงค่าที่แตกต่างและไม่เป็นศูนย์ :-) หรือถ้าคุณไม่ได้ใช้sar -P ALL 1 atopนี่เป็นวิธีที่iowaitรุ่นขยายสำหรับระบบมัลติซีพียู ... สิ่งที่ฉันไม่ชัดเจนคือรุ่นนี้ใช้งานได้จริงหรือไม่หรือนี่เป็นวิธีที่ทำให้รหัส iowait ทำงานต่อไปได้เมื่อมี CPU เพียงตัวเดียว ออนไลน์ แต่มันก็ไม่น่าไว้ใจอย่างอื่น