私の基本的な仮定は、プロセスの唯一の制限要因がディスクとCPUの場合、システム全体の「iowait」+ CPU使用量が少なくとも1つの論理CPUの100%に等しくなければならないことです。 (これが事実以外の状況もあります。たとえば、ダウンロードしたファイルを使用する場合、ネットワークが制限要因であるwget
ことがよくあります。)
簡単なテストはこの仮定に違反します。これが期待されるか。それが予想される場合、私ができる一連の条件はありますか?しなければならない私は仮説が真実であると期待していますか?
「iowait」の背景情報は以下の通りです。CPUは、IOが保留中であるかどうかをどうやって知ることができますか? ここへの答えは、累積iowaitが「特定の条件下で減少する可能性がある」という反直観的なアイデアを引用しています。私の簡単なテストが文書化されていない状況を引き起こす可能性があるかどうか疑問に思います。
修正する:お願いします回答にスキップ。
答えは私が最初に使用したよりも簡単なテストです。以下に元の質問を残しました。元の質問にはいくつかの追加の詳細が表示されることがあります。
元の質問
短いテストでは、dd
カーネルにランダムなバイトを生成し、それをファイルに書き込むように要求しました。カーネルで消費されたCPU時間を計算するためにdd
内部で命令を実行しました。perf stat
私も内部を実行しperf trace -s
、内部で過ごした時間を報告しましたwrite()
。同時にvmstat 5
別の端末を実行して「iowait」システムを確認しました。
- 私は、少なくともCPU全体が「アイドル状態ではない」状態、つまり100%実行中または停止しているがIO(「iowait」状態)を待っている状態を見ることを期待しています。いいえ。
- (また、「iowait」の時間がwrite()に費やされた時間とほぼ一致すると予想しましたが、そうではありません。)
詳細な結果とテスト環境を以下に示します。また、私の仮説が裏付けられている別のテストも表示されます。注:perf stat
内部で実行する必要があり、perf trace
反対方向に実行しないでください。詳細は次のとおりです。「パフォーマンストレース -s」を実行すると、「パフォーマンス統計」(および「時間」!)が間違った結果を表示しますか?
「iowait」の背景情報
マンページからインポートされた定義は次のとおりです
sar
。%io は次を待ちます:
システムに未解決のディスクI / O要求がある間に1つ以上のCPUがアイドル状態になった時間の割合。
したがって、%iowaitはCPUの観点からは実行できませんが、少なくとも1つの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待機」について考えるのはマルチCPUシステムを使用しているので、今は少しトリッキーですが、参照されたコードを見るとまだ理解していると思います。
環境
論理CPUが4つあります。
LVMとext4ファイルシステムを使用してください。ディスクやファイルシステムに暗号化を使用しません。ネットワークファイルシステムがまったくマウントされていないため、ネットワークファイルシステムで読み書きできません。
以下の結果はIOスケジューラを4.20.15-200.fc29.x86_64
使用してカーネルからインポートされます。noop
IOスケジューラcfq
も同様の結果を提供しました。
(同様の構成に基づいていますが、カーネルバージョン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
私は列からこの数字を読みました。列(= 1K出力ブロック)を見ると、テストが実行されている時期がわかります。wa
vmstat
io
bo
$ 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
テスト結果(仮想マシン内部)
カーネルを実行し(それで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%が表示されることがあり、約50%(つまり、2つのCPUのうちの1つ)が表示されることがあります。 0%「idle」では、「iowait」が非常に高いです。つまり、CPU値が2つ以上です。つまり、私が予想した2番の項目が間違っていました。とても受け入れられないこれマルチCPUシステムにおける「iowait」の明らかな制限(それでもよく理解できません。誰かが正確に説明したいと思います。)しかし、どちらの場合も「idle」が50%を超えないので、これらのテストは「iowait」の私の最初の仮説とまだ一致しています。
仮想マシンをシャットダウンしてから4つのCPUで始めました。同様に、アイドル状態は正確に75%で表示されることが多く、時には50%まで低くなりますが、アイドル状態は75%以上(たとえば、4つのCPUのうち3つ以上)は表示されません。
4つのCPUを搭載した物理システムでは、上記の80%アイドル結果を再現できます。
ベストアンサー1
コンテンツ通知:この記事には、さまざまなLinuxディスカッションとコードへのリンクが含まれています。一部のリンクされたコンテンツは現行行動規範に準拠していません。スタック交換またはLinux。ほとんどの人は「[人ではなく]コードを侮辱しています。」使用されている言語に関係なく繰り返してはいけません。そのような言語を模倣したり、オウムのように真似したり、議論をすることを控えてください。
Re:iowaitがアイドルアカウントと「一貫していない」 - iowaitが低すぎる
2019年5月7日12:38に、Peter Zijlstraは次のように書きました。
2019年7月5日金曜日の午後12時25分46秒+0100で、Alan Jenkinsは次のように書きました。
私の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;
}
これは私が期待したように機能します。おおよそのCPU時間「サンプリング」は、従来のタイマ割り込み(「ティック」)を使用して実行されます。ただし、節電のためにアイドル時間中にチェックをオフにすると、機能しなくなる可能性がありますNO_HZ_IDLE
。パフォーマンス上の理由からティックをオフにすることを許可しても失敗することがあります。NO_HZ_FULL
ブートが必要だからです。VIRT_CPU_ACCOUNTING
。ほとんどのLinuxカーネルは省電力機能を使用します。一部の組み込みシステムでは、これら2つの機能を使用していません。私の説明は次のとおりです。
IOが完了すると、デバイスは邪魔する。カーネル割り込みハンドラは、次を使用してプロセスを起動します。try_to_wake_up()
。カウンターを1ずつ減らします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()
から__tick_nohz_idle_restart_tick()
またはvtime_task_switch()
から呼び出されますfinish_task_switch()
。
この時は->nr_iowait
縮小しました。ゼロに減らすと、iowait時間は記録されません。
この効果はさまざまです。つまり、プロセスが起きたCPUによって異なります。 IO完了割り込みを受信するのと同じCPUでプロセスが起きている場合は、->nr_iowait
アイドル時間が短くなる前に早く計算できます。私の場合、CPU 0が処理されていることがわかりました。アーチを見て中断します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に対して「正しい」iowaitが再現されるように見えます。これが関連している可能性があると思います。IRQ_TIME_ACCOUNTING
この機能は、仮想マシンの外部テストにも使用されました。
NO_HZ_IDLE
抑制すると、4.17+ではCPUごとに「正しい」iowaitが提供されますが、4.16または4.15では提供されない理由を正確に確認できませんでした。
私の仮想マシンでこのテストを実行すると、CPUごとに「正しい」iowaitが再現されるようです。このためです IRQ_TIME_ACCOUNTING
。 VM 外部テストにも使用されますが、VM 内部でテストすると、より多くのハングが発生します。特に、「dd」が実行されている仮想CPUには、1秒あたり1000を超える「関数呼び出し割り込み」があります。
だから私の説明の詳細に頼ってはいけません :-)
「iowait」の背景情報は以下の通りです。CPUは、IOが保留中であるかどうかをどうやって知ることができますか? ここへの答えは、累積iowaitが「特定の条件下で減少する可能性がある」という反直観的なアイデアを引用しています。私の簡単なテストが文書化されていない状況を引き起こす可能性があるかどうか疑問に思います。
はい。
最初にこのコンテンツを検索したときに「しゃっくり」という用語が見つかりました。また、累積された「iowait」時間が単調ではないことを示すことによって問題を説明します。つまり、後方にジャンプ(減少)する場合もあります。上記のテストほど単純ではありません。
しかし、調査を行ったところ、同じ根本的な問題が発見されました。 Peter ZijlstraとHidetoshi Setoはそれぞれソリューションを提案し、プロトタイプを作成しました。この問題はカバーメッセージに記載されています。
[RFCパッチ0/8] iowait会計リワーク(2014-07-07)
それ以外は進展があるという証拠が見つかりませんでした。詳細の1つに答えのない質問があります。さらに、シリーズ全体はPowerPC、S390、およびIA64 CPUアーキテクチャの特定のコードをカバーしています。それで、この問題を解決するのは簡単ではないと言いたいのです。