システム「iowait」に関する私の基本的な仮定は成り立たない


13

私の基本的な仮定は、プロセスの唯一の制限要因がディスクとCPUである場合、システムの「iowait」とCPUの合計使用量は、1つの論理CPUの少なくとも100%に等しくなることです。(他の場合、これは保持されません。たとえば、を使用してファイルをダウンロードする場合wget、ネットワークが制限要因になることがよくあります)。

この仮定は単純なテストに違反しています。これは予想されますか?それが期待されている場合は、私は一連の条件が存在しなければならない私の仮定が成り立つことを期待しますか?

ここに「iowait」についての背景があります:CPUはIO保留があることをどのように知るのですか? ここでの答えは、累積iowaitが「特定の条件で減少する可能性がある」という直感に反するアイデアを引用しています。私の簡単なテストがそのような文書化されていない状態を引き起こしているのではないかと思いますか?

更新答えにスキップしてください。

答えには、最初に使用したものよりも簡単なテストがあります。以下の元の質問を保存しました。元の質問に追加の詳細が表示される場合があります。

元の質問

短いテストではdd、カーネルにランダムバイトの生成を要求し、それらをファイルに書き込むために使用します。カーネル内で費やされたCPU時間のカウントを取得するためだけに、ddコマンドを実行しperf statます。内部perf trace -sで費やした時間を報告するために内部で実行しwrite()ます。同時に、vmstat 5別のターミナルで実行して、システム「iowait」を確認します。

  1. 少なくとも1つのCPU全体が「非アイドル」、つまり、100%の時間、実行中または停止しているがIOを待機している(「iowait」状態)として表示されると予想していました。そうではありませんでした。
  2. (また、「iowait」の時間は、write()で費やされた時間とほぼ一致することを期待していました。しかし、そうではなかったようです。)

詳細な結果とテスト環境を以下に示します。また、別のテストも示していますが、ここでは私の仮定が当てはまりました。注:perf statinside を実行する必要がありましたがperf trace、その逆ではありません。詳細については、「perf trace-s」を実行すると、「perf stat」(および「time」!)に誤った結果が表示されますか?

「iowait」に関する背景情報

以下は、sarマンページから取られた定義です。

%iowait:

1つまたは複数のCPUがアイドル状態であった間に、システムに未処理のディスクI / O要求があった時間の割合。

したがって、%iowaitは、CPUの観点からは、実行可能なタスクはないが、少なくとも1つの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システムを使用しているため、今は少し注意が必要ですが、引用符で囲まれたコードに基づいて理解できていると思います。

環境

4つの論理CPUがあります。

私はLVMとext4ファイルシステムを使用します。ディスクまたはファイルシステムで暗号化を使用していません。ネットワークファイルシステムがまったくマウントされていないため、ネットワークファイルシステムの読み取りまたは書き込みを行っていません。

以下の結果は4.20.15-200.fc29.x86_64noopIOスケジューラを使用したkernelからのものです。cfqIOスケジューラも同様の結果が得られます。

(同様の構成に基づいたカーネルビルドでも同様の結果が見られましたが、カーネルバージョン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%
...

iowaitwaコラムから図を読みましたvmstatio列(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内)

1 CPUのVM内で同じテストを試みましたが、これはカーネル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%のアイドルが表示されることもありました(2つのCPUのうち1つ)。0%の「アイドル」の場合、「iowait」は非常に高く、複数のCPUに相当します。すなわち、私の期待ポイント2は正しくありませんでした。マルチCPUシステムでの「iowait」のこの明らかな制限を、しぶしぶ受け入れることができます。(私はそれをよく理解していませんが、誰かがそれを正確に説明したいなら、それは素晴らしいでしょう)。ただし、どちらの場合も「アイドル」は50%を超えていなかったため、これらのテストは「iowait」に関する最初の仮定と一致していました。

VMをシャットダウンして、4つのCPUで起動しようとしました。同様に、多くの場合、アイドル状態は正確に75%であり、50%程度のアイドル状態であったこともありましたが、75%以上のアイドル状態はありませんでした(4つのCPUのうち3つ以上)。

一方、4つのCPUを備えた物理システムでは、上記のように80%以上のアイドル状態の結果を再現できます。


2つの期待に少し注釈を付けてください。実際の価値があなたの予想より多かったのか少なかったのか追加していただけますか 私はこれが生データにあることを理解しています、それはもう少し読みやすいでしょう。1 CPU(100%)を期待する理由については、私には少しわかりません。リンクの1つと引用するカーネルコードに基づいて、1回のIO操作ですべてのIDLE時間をIOWAIT時間に切り替えます(4コアすべて-400%)。
フィリップクーリング

@PhilipCouling「少なくとも1つのCPU全体を「非アイドル」と見なすと予想していましたが、そうではありませんでした」。アイドル時間は予想よりも長く、iowaitの時間が予想よりも短いことに責任があります。カーネルコードでthis_rq()->nr_iowaitio_schedule() 、現在のCPUのみで使用待機しているタスクの数だと思います。私が間違っている?
sourcejedi

1
確かではありませんが、そうだとしたら驚きです。この驚きは、Stephen Kittiowait一般にI / Oの待機時間を測定しようとしています。特定のCPUによって追跡されず、追跡することもできません」と答えていることと一致しています。私はこれを確信していませんが、ただ驚きを表明しています。
フィリップクーリング

@PhilipCoulingを実行する場合atop、またはatopsar -c 5、CPUごとの使用量の数値が表示されます。それらにはiowaitが含まれ、CPUごとのiowaitの数値は異なるゼロ以外の値を表示できます:-)。またはsar -P ALL 1、使用しない場合atop。これは、iowaitモデルがマルチCPUシステム用に拡張された方法です...このモデルが実際に使用できるかどうか、またはCPUが1つしかないときにiowaitコードが動作し続けることができるかどうかは不明ですオンラインですが、それ以外の場合は信頼できません。
sourcejedi

回答:


7

内容の通知:この投稿には、さまざまなLinuxのディスカッションとコードへのリンクが含まれています。一部のリンクされたコンテンツは、StackExchangeまたはLinuxの現在の行動規範を満たしていません。ほとんどの場合、「コードをins辱しますが、人をult辱します」。ただし、一部の言語は使用されますが、繰り返さないでください。そのような言語を模倣したり、オウムしたり、議論したりしないようにしてください。


再:iowait対アイドルアカウンティングは「一貫性がない」-iowaitが低すぎる

2019年5月7日12:38に、Peter Zijlstraは次のように書いています:

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;
}

これは、従来のタイマー割り込み(「ティック」)で「サンプリング」することでCPU時間概算している場合、期待どおりに機能します。ただし、電力を節約するためにアイドル時間中にティックをオフにすると動作しない場合があります- NO_HZ_IDLE。あなたはダニは、パフォーマンス上の理由のためにオフにすることを可能にする場合にも、失敗する可能性があります- NO_HZ_FULL-それは、起動が必要ですので、VIRT_CPU_ACCOUNTING。。ほとんどのLinuxカーネルは、省電力機能を使用しています。一部の組み込みシステムは、どちらの機能も使用しません。ここに私の説明があります:

IOが完了すると、デバイスは割り込みを送信します。カーネル割り込みハンドラーは、を使用してプロセスを起動しtry_to_wake_up()ます。nr_iowaitカウンターから1を引きます:

if (p->in_iowait) {
    delayacct_blkio_end(p);
    atomic_dec(&task_rq(p)->nr_iowait);
}

プロセスがアイドルCPUで起動されると、そのCPUはを呼び出しますaccount_idle_time()。適用される構成に応じて、これはfrom tick_nohz_account_idle_ticks()から__tick_nohz_idle_restart_tick()、またはfrom vtime_task_switch()から呼び出されます。finish_task_switch()

この時点で、->nr_iowaitすでに減少しています。ゼロに減らすと、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で「正しい」iowaitが再現されるようになった理由。IRQ_TIME_ACCOUNTINGこの機能はVM以外のテストでも使用されていますが

また、抑制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と瀬戸秀俊によってそれぞれプロトタイプが作成されました。問題はカバーメッセージで説明されています。

[RFC PATCH 0/8] iowaitアカウンティングの手直し(2014-07-07)

これ以上の進歩の証拠は見つかりませんでした。詳細の1つに未解決の質問がありました。また、このシリーズ全体では、PowerPC、S390、およびIA64 CPUアーキテクチャの特定のコードに触れました。だから、これは修正するのは簡単ではないと言います。


2
確認または拒否できますか(vmstatを使用):カーネル4.15は、アイドル状態が有効または無効に関係なく、期待どおりに動作します。カーネル4.16は、あなたが期待していることには関係ありません。vmstatはを使用しているようです/proc/statが、私はを使用/sys/devices/system/cpu/cpu*/cpuidle/state*/usageしており、私の知る限りでは常に正確です(+-数%)。いくつかの新しい情報が存在しないため、古いカーネルではツールを使用できません。ダニは0アイドル状態で停止したことがないので、私は、TEST1とTEST3が同じ結果を与えることを期待している注
ダグSmythies

1
/sys/devices/system/cpu/cpu*/cpuidle/state*/time上に書くつもりでした。カーネル4.15から4.16の間で一度、次に4.16から4.17の間で、カーネルを二分することしか考えられません。2番目の二分法は、最初の二分法から得られた知識でより速く進むかもしれません。たぶん数日のうちに、今それをする時間がありません。
ダグスミシーズ

1
@DougSmythiesありがとうございます!テストは元のテストと同じように機能します。以下のための私の結果4.15.0-1.fc28とは、4.16.0-300.fc28あなたに同意します。
sourcejedi

OK linux-pmリストへの返信の準備ができたと思います。誰かが洞察を得て、カーネルの二分法を回避できることを願っています。
ダグスミティーズ

1
@DougSmythies wtf。最初の二分法(4.15-4.16)は、github.com / torvalds / linux / commit / 806486c377e3に「sched / fair:prev_cpuがアイドル状態の場合は移行しないでください」を与えます。したがってtaskset -c 0、v4.15でテストしました...でddコマンドを実行するとtaskset -c 2、「正しい」iowaitが得られます。他のCPUに固定すると、「間違った」iowaitが発生します。そしてcpu2は、dd私が使用しない場合に終わる場所tasksetです。(atop以前はCPUごとのiowait時間を表示していました)。しかし、現在の振る舞いを説明するために、2番目の二分法を見ています。偶然にも、2回目の変更でこれについてのコメントがあったかもしれません。
sourcejedi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.