Giả định cơ bản của tôi là khi các yếu tố giới hạn chỉ của một tiến trình là đĩa và CPU, thì tổng hệ thống "iowait" + mức sử dụng CPU phải bằng ít nhất 100% của một CPU logic. (Trong các trường hợp khác, điều này sẽ không giữ được. Ví dụ: khi tải xuống tệp bằng cách sử dụng wget, mạng thường là yếu tố giới hạn).
Giả định này bị vi phạm bởi một thử nghiệm đơn giản. Đây có phải là mong đợi? Nếu nó được mong đợi, có một tập hợp các điều kiện mà tôi nên mong đợi giả định của mình là đúng không?
Có một số nền tảng về "iowait" ở đây: Làm thế nào để CPU biết có IO đang chờ xử lý? Câu trả lời ở đây trích dẫn ý tưởng phản trực giác, rằng iowait tích lũy "có thể giảm trong một số điều kiện nhất định". Tôi tự hỏi nếu thử nghiệm đơn giản của tôi có thể gây ra một điều kiện không có giấy tờ như vậy?
CẬP NHẬT : Hãy bỏ qua để trả lời .
Câu trả lời có một bài kiểm tra đơn giản hơn so với bài tôi đã sử dụng ban đầu. Tôi bảo tồn câu hỏi ban đầu dưới đây. Câu hỏi ban đầu có thể hiển thị một số chi tiết bổ sung.
Câu hỏi gốc
Trong một thử nghiệm ngắn, tôi sử dụng ddđể yêu cầu kernel tạo các byte ngẫu nhiên và ghi chúng vào một tệp. Tôi chạy ddlệnh bên trong perf stat, chỉ để đếm thời gian CPU bên trong kernel. Tôi cũng chạy nó bên trong perf trace -s, để báo cáo thời gian bên trong write(). Đồng thời, tôi chạy vmstat 5trong một thiết bị đầu cuối khác, để xem hệ thống "iowait".
- Tôi dự kiến tôi sẽ thấy ít nhất một CPU toàn bộ là "không hoạt động", tức là 100% thời gian nó đang chạy hoặc tạm dừng nhưng chờ IO (trạng thái "iowait"). Nó không phải là.
- (Ngoài ra, tôi đã mong đợi để thấy thời gian "iowait" gần như khớp với thời gian viết (). Nhưng nó dường như không làm như vậy.)
Các kết quả chi tiết và môi trường thử nghiệm được hiển thị dưới đây. Cũng hiển thị là một thử nghiệm thay thế, trong đó giả định của tôi đã giữ. Lưu ý: cần phải chạy perf statbên trong perf trace, không phải cách khác. Đây là chi tiết ở đây: "perf stat" (và "time"!) Có hiển thị kết quả không chính xác khi chạy "perf track - s" không?
Thông tin cơ bản về "iowait"
Sau đây là định nghĩa được lấy từ
sartrang chủ:% iowait:
Phần trăm thời gian mà CPU hoặc CPU không hoạt động trong đó hệ thống có yêu cầu I / O đĩa xuất sắc.
Do đó,% iowait có nghĩa là từ quan điểm của CPU, không có tác vụ nào có thể chạy được, nhưng ít nhất một I / O đang được tiến hành. iowait chỉ đơn giản là một dạng thời gian nhàn rỗi khi không có gì có thể được lên lịch. Giá trị có thể có hoặc không hữu ích trong việc chỉ ra vấn đề về hiệu năng, nhưng nó cho người dùng biết rằng hệ thống không hoạt động và có thể mất nhiều công sức hơn.
https://support.hpe.com/hpsc/doc/public/display?docId=c02783994
Ngoài ra còn có một bài viết dài hơn: Hiểu về I / O Wait (hoặc tại sao 0% Idle có thể ổn) . Điều này giải thích làm thế nào bạn có thể thấy định nghĩa rõ ràng từ mã hạt nhân. Mã đã thay đổi phần nào, nhưng ý tưởng vẫn rõ ràng:
/*
* 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;
}
Bài báo cũng cho thấy một số thử nghiệm liên quan trên một hệ thống CPU đơn. Một số thí nghiệm thậm chí sử dụng ddvới if=/dev/urandom ! Tuy nhiên, các thí nghiệm không bao gồm thử nghiệm của tôi dd if=/dev/urandom of=test.out . Nó chỉ sử dụng dd if=/dev/urandom of=/dev/null .
"Chờ đợi" bây giờ khó khăn hơn một chút để nghĩ về chúng tôi bởi vì chúng tôi sử dụng các hệ thống đa CPU, nhưng tôi nghĩ rằng tôi vẫn hiểu nó, dựa trên mã được trích dẫn.
Môi trường
Tôi có bốn CPU logic.
Tôi sử dụng LVM và hệ thống tập tin ext4. Tôi không sử dụng bất kỳ mã hóa nào trên đĩa hoặc hệ thống tập tin của mình. Tôi không có bất kỳ hệ thống tập tin mạng nào được gắn kết, vì vậy tôi không đọc hoặc viết một hệ thống tập tin mạng.
Các kết quả dưới đây là từ kernel 4.20.15-200.fc29.x86_64, sử dụng bộ lập nooplịch IO. Bộ lập cfqlịch IO cũng cho kết quả tương tự.
(Tôi cũng đã thấy kết quả tương tự trên bản dựng kernel dựa trên cấu hình tương tự, nhưng gần với phiên bản kernel 5.1 hơn và sử dụng mq-deadline. Vì vậy, đó là sử dụng blk-mqmã mới ).
Kiểm tra và kết quả
$ 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%
...
Tôi đọc iowaithình từ wacột vmstat. Bạn có thể biết khi nào bài kiểm tra đang chạy bằng cách nhìn vào iocột ( bo= 1K khối đầu ra).
$ 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
Kiểm tra kết quả nơi nó giữ (bên trong VM)
Tôi đã thử cùng một thử nghiệm bên trong máy ảo với 1 CPU, đang chạy kernel 5.0.9-301.fc30.x86_64và sử dụng mq-deadline(và do đó blk-mq). Trong thử nghiệm này, nó hoạt động như thế nào tôi mong đợi nó.
$ 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%
...
Đầu ra của 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
Tôi đã thử nóng - thêm CPU vào VM và kiểm tra lại. Kết quả rất khác nhau: đôi khi nó hiển thị khoảng 0% trong cột nhàn rỗi và đôi khi nó hiển thị khoảng 50% không hoạt động (tức là một trong hai CPU). Trong trường hợp 0% "nhàn rỗi", "iowait" rất cao, tức là có giá trị hơn một CPU. Tức là điểm 2 của tôi không đúng. Tôi có thể chấp nhận một cách bừa bãi giới hạn rõ ràng này của "iowait" trên các hệ thống đa CPU. (Mặc dù tôi không hiểu lắm. Nếu ai đó muốn giải thích chính xác, điều đó sẽ rất tuyệt). Tuy nhiên, "nhàn rỗi" không vượt quá 50% trong cả hai trường hợp, vì vậy những thử nghiệm này vẫn phù hợp với giả định đầu tiên của tôi về "iowait".
Tôi đã thử tắt VM và khởi động nó với 4 CPU. Tương tự, thường thì tôi có chính xác 75% không hoạt động, và đôi khi tôi có mức nhàn rỗi thấp đến 50%, nhưng tôi không thấy quá 75% nhàn rỗi (tức là hơn ba trong số bốn CPU).
Trong khi đó trên hệ thống vật lý có 4 CPU, tôi vẫn có thể tái tạo kết quả của hơn 80% không hoạt động như hình trên.
this_rq()->nr_iowaitlà số lượng tác vụ đang chờ chỉ sử dụng io_schedule() trên CPU hiện tại . Tôi có lầm không?
iowaitcố gắng đo thời gian chờ đợi I / O, nói chung. Nó không được theo dõi bởi một CPU cụ thể, cũng không thể" . Hãy để tôi nhấn mạnh tôi không chắc chắn về điều này, chỉ bày tỏ sự ngạc nhiên.
atop, hoặc atopsar -c 5, bạn sẽ thấy số liệu sử dụng trên mỗi cpu. Chúng bao gồm iowait và các số liệu iowait trên mỗi CPU có thể hiển thị các giá trị khác nhau, khác không :-). Hoặc sar -P ALL 1, nếu bạn không sử dụng atop. Đây là cách iowaitmô hình đã được mở rộng cho các hệ thống nhiều CPU ... Điều tôi không rõ là liệu mô hình này có thực sự có thể sử dụng được không, hoặc liệu đây có phải là cách cho phép mã iowait tiếp tục hoạt động khi chỉ có một CPU trực tuyến, nhưng nó chỉ không đáng tin cậy khác.