내 기본 가정은 프로세스의 제한 요소가 디스크와 CPU 인 경우 총 시스템 “iowait”+ CPU 사용량은 하나의 논리 CPU의 100 % 이상이어야한다는 것입니다. (다른 경우에는 유지되지 않습니다. 예를 들어를 사용하여 파일을 다운로드 할 때 wget
네트워크가 종종 제한 요소입니다).
이 가정은 간단한 테스트로 위반됩니다. 이것이 예상됩니까? 이 예상되는 경우, 나는 일련의 조건이 해야 내 가정이 성립 기대는?
여기에 “iowait”에 대한 배경이 있습니다 : CPU는 IO 보류가 있는지 어떻게 알 수 있습니까? 여기에 대한 답변은 반 직관적 인 아이디어를 인용하며, 누적 된 iowait는 “특정 조건에서 감소 할 수 있습니다”. 간단한 테스트가 문서화되지 않은 조건을 트리거 할 수 있는지 궁금합니다.
업데이트 : 답변으로 건너 뛰십시오 .
대답은 원래 사용했던 것보다 간단한 테스트를 거쳤습니다. 아래의 원래 질문을 유지했습니다. 원래 질문에는 몇 가지 추가 세부 사항이 표시 될 수 있습니다.
원래 질문
간단한 테스트 dd
에서 커널에 임의 바이트를 생성하여 파일에 쓰도록 요청합니다. 커널 내에서 보낸 CPU 시간 수를 얻기 위해 dd
inside 명령을 실행합니다 perf stat
. 또한 내부 perf trace -s
에서 보낸 시간을보고하기 위해 내부 에서 실행합니다 write()
. 동시에, 나는 vmstat 5
“iowait”시스템을보기 위해 다른 터미널에서 실행 합니다.
- 나는 적어도 하나의 전체 CPU를 “유휴 상태가 아닌”것으로 볼 것으로 예상했다. 즉, 100 %는 실행 중이거나 정지되었지만 IO ( “iowait”상태)를 기다리는 시간이다. 아니었다.
- (또한 “iowait”시간이 write ()에 소비 된 시간과 거의 일치 할 것으로 예상했지만 그렇게하지는 않았습니다.)
자세한 결과 및 테스트 환경은 다음과 같습니다. 또한 내 가정이 채택한 대체 테스트도 나와 있습니다. 참고 : 다른 방법이 아닌 perf stat
내부 를 실행해야했습니다 perf trace
. 이 여기에 자세히 설명되어 있습니다 합니까 “반환 한 통계”(그리고 “시간”!) “트레이스를 규칙적 -의”실행할 때 잘못된 결과를 보여?
“iowait”에 대한 배경 정보
다음은
sar
맨 페이지 에서 가져온 정의입니다 .% iowait :
시스템에 미해결 디스크 I / O 요청이있는 동안 CPU가 유휴 상태 인 시간의 백분율입니다.
따라서 % iowait는 CPU 관점에서 실행할 수있는 작업이 없지만 하나 이상의 I / O가 진행 중임을 의미합니다. iowait는 예약 할 수없는 유휴 시간의 한 형태입니다. 이 값은 성능 문제를 나타내는 데 유용하거나 유용하지 않을 수 있지만 사용자에게 시스템이 유휴 상태이고 더 많은 작업을 수행 할 수 있음을 알려줍니다.
https://support.hpe.com/hpsc/doc/public/display?docId=c02783994
더 긴 기사 : I / O 대기 이해 (또는 0 % 유휴 상태가 양호한 이유)도 있습니다. 커널 코드에서 정의를 명확하게 볼 수있는 방법에 대해 설명합니다. 코드가 약간 변경되었지만 아이디어는 여전히 명확합니다.
/*
* 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 wait”는 멀티 CPU 시스템을 사용하기 때문에 지금 생각하기가 조금 까다 롭지 만 인용 코드를 기반으로 여전히 이해하고 있다고 생각합니다.
환경
4 개의 논리 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 내부에서 보유한 테스트 결과
커널을 실행하고 (따라서 blk-mq)를 5.0.9-301.fc30.x86_64
사용 하는 1 CPU의 VM에서 동일한 테스트를 시도했습니다 mq-deadline
. 이 테스트에서는 예상대로 작동했습니다.
$ 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
VM에 CPU를 추가하고 다시 테스트했습니다. 결과는 가변적입니다. 때로는 유휴 열에서 약 0 %를 보여 주었고 때로는 유휴 상태 (약 두 CPU 중 하나)에서 약 50 %를 보였습니다. 0 % “idle”의 경우 “iowait”는 매우 높았습니다 (예 : 하나 이상의 CPU 가치). 즉 내 기대 지점 2가 올바르지 않습니다. 다중 CPU 시스템에서 이러한 “iowait”의 명백한 한계를 확실하게 수용 할 수 있습니다. (나는 그것을 이해하지 못하지만. 누군가 그것을 정확하게 설명하고 싶다면, 그것은 좋을 것입니다). 그러나 “유휴”는 두 경우 모두 50 %를 넘지 않았으므로 이러한 테스트는 여전히 “iowait”에 대한 나의 첫 가정과 일치했습니다.
VM을 종료하고 4 개의 CPU로 시작했습니다. 마찬가지로, 종종 유휴 상태가 정확히 75 %이고 때로는 유휴 상태가 50 %에 불과하지만 유휴 상태가 75 %를 넘지 않았습니다 (예 : 4 개의 CPU 중 3 개 이상).
CPU가 4 개인 실제 시스템에서 위와 같이 80 % 이상의 유휴 결과를 여전히 재현 할 수 있습니다.
답변
내용 공지 :이 게시물에는 다양한 Linux 토론 및 코드에 대한 링크가 포함되어 있습니다. 링크 된 일부 컨텐츠가 StackExchange 또는 Linux 의 현재 행동 강령을 충족하지 않습니다 . 대부분 그들은 “코드를 모욕하지만 [사람은 아님]”. 그러나 일부 언어가 사용되므로 단순히 반복해서는 안됩니다. 그러한 언어를 모방, 파문 또는 토론하지 않도록 요청합니다.
다시 : iowait 대 유휴 계정이 “일관되지 않음”-iowait가 너무 낮습니다
Peter Zijlstra는 다음과 같이 썼습니다.
Alan Jenkins는 2019 년 7 월 5 일 금요일 12:25:46 PM +0100에 다음과 같이 썼습니다.
CPU “iowait”시간이 잘못보고 된 것 같습니다. 왜 이런 일이 일어날 수 있는지 아십니까?
iowait는 정상적인 의미가없는 마법의 난수이기 때문입니다. 개인적으로 ABI를 제외한 모든 것을 삭제하고 싶습니다 .
또한 nr_iowait () 근처의 주석을 참조하십시오
감사. 나는 [현재 문서에서 언급 된 문제들]을 다른 문제로 생각하지만, 내 문제를 “수정”할 필요가 많지 않다는 것을 의미합니다.
내 문제를 찾았습니다. 이미 5 년 전에 발견되었으므로 해결하기가 쉽지 않습니다.
“iowait”시간은 다음 함수에 의해 업데이트됩니다 account_idle_time()
.
/*
* 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;
}
기존 타이머 인터럽트 ( “tick”)로 “샘플링”하여 CPU 시간 을 근사화 하면 예상대로 작동합니다 . 그러나 유휴 시간 동안 전원을 절약하기 위해 틱을 끄면 작동하지 않을 수 있습니다 NO_HZ_IDLE
. 성능상의 이유로 틱을 끄면 NO_HZ_FULL
시작해야하기 때문에 실패 할 수도 있습니다 VIRT_CPU_ACCOUNTING
. 대부분의 Linux 커널은 절전 기능을 사용합니다. 일부 임베디드 시스템은이 기능을 사용하지 않습니다. 내 설명은 다음과 같습니다.
IO가 완료되면 장치는 인터럽트를 보냅니다 . 커널 인터럽트 핸들러는를 사용하여 프로세스를 깨 웁니다 try_to_wake_up()
. nr_iowait
카운터 에서 하나를 뺍니다 .
if (p->in_iowait) {
delayacct_blkio_end(p);
atomic_dec(&task_rq(p)->nr_iowait);
}
프로세스가 유휴 CPU에서 깨어 난 경우 해당 CPU가를 호출합니다 account_idle_time()
. 적용되는 구성에 따라 tick_nohz_account_idle_ticks()
from __tick_nohz_idle_restart_tick()
또는 from vtime_task_switch()
에서 호출됩니다 finish_task_switch()
.
이때까지 ->nr_iowait
벌써 감소했습니다. 0으로 줄이면 iowait 시간이 기록되지 않습니다.
이 효과는 다를 수 있습니다. 프로세스가 깨어 난 CPU에 따라 다릅니다. 프로세스가 IO 완료 인터럽트를 수신 한 동일한 CPU에서 깨어 난 경우, 유휴 시간 ->nr_iowait
은 감소 하기 전에 더 일찍 설명 될 수 있습니다 . 필자의 경우 CPU 0이 ahci 인터럽트를 처리하여 처리합니다 watch cat /proc/interrupts
.
간단한 순차적 읽기로 이것을 테스트했습니다.
dd if=largefile iflag=direct bs=1M of=/dev/null
를 사용하여 명령을 CPU 0에 고정하면 taskset -c 0 ...
iowait에 대한 “올바른”값이 표시됩니다. 다른 CPU에 고정하면 훨씬 낮은 값을 볼 수 있습니다. 명령을 정상적으로 실행하면 커널 버전 사이에서 변경된 스케줄러 동작에 따라 다릅니다. 최근 커널 (4.17, 5.1, 5.2-rc5-ish)에서는 “iowait”시간이 그 비율로 줄어들 기 때문에 명령이 CPU 0에서 1/4의 시간을 소비하는 것으로 보입니다.
(설명되지 않음 : 가상 머신에서이 테스트를 실행하면 각 CPU (또는 모든 CPU)에 대해 “올바른”iowait를 재현하는 것 같습니다. IRQ_TIME_ACCOUNTING
이 기능은 VM 외부의 테스트에서도 사용되지만이 관련이있을 수 있습니다 .
또한 억제 NO_HZ_IDLE
가 4.17 이상 4.16 또는 4.15에서는 각 CPU에 대해 “올바른”iowait를 제공 하는 이유를 정확하게 확인 하지 못했습니다.
내 가상 머신에서이 테스트를 실행하면 각 CPU (또는 모든 CPU)에 대해 “올바른”iowait를 재현하는 것 같습니다. 때문 IRQ_TIME_ACCOUNTING
입니다. VM 외부의 테스트에서도 사용되지만 VM 내부에서 테스트 할 때 더 많은 인터럽트가 발생합니다. 특히, “dd”가 실행되는 가상 CPU에는 초당 1000 개 이상의 “함수 호출 인터럽트”가 있습니다.
그래서 당신은 내 설명의 세부 사항에 너무 많이 의존해서는 안됩니다 🙂
여기에 “iowait”에 대한 배경이 있습니다 : CPU는 IO 보류가 있는지 어떻게 알 수 있습니까? 여기에 대한 답변은 반 직관적 인 아이디어를 인용하며, 누적 된 iowait는 “특정 조건에서 감소 할 수 있습니다”. 간단한 테스트가 문서화되지 않은 조건을 트리거 할 수 있는지 궁금합니다.
예.
내가 이것을 처음봤을 때 나는 “딸꾹질”에 대한 이야기를 발견했다. 또한 누적 “iowait”시간이 비단 조임을 보여줌으로써 문제가 설명되었습니다. 즉, 때로는 뒤로 점프합니다 (감소). 위의 테스트만큼 간단하지 않았습니다.
그러나 조사한 결과 동일한 근본적인 문제가 발견되었습니다. Peter Zijlstra와 Hidetoshi Seto가 각각 솔루션을 제안하고 프로토 타이핑했습니다. 표지 메시지에 문제가 설명되어 있습니다.
[RFC PATCH 0/8] 재 작업 iowait 회계 (2014-07-07)
나는 이것 이상의 진보의 증거를 찾지 못했다. 세부 사항 중 하나에 대한 열린 질문이있었습니다. 또한 전체 시리즈는 PowerPC, S390 및 IA64 CPU 아키텍처를위한 특정 코드를 다루었습니다. 그래서 이것은 수정하기가 쉽지 않다고 말합니다.