元の質問

元の質問

私の基本的な仮定は、プロセスの唯一の制限要因がディスクとCPUの場合、システム全体の「iowait」+ CPU使用量が少なくとも1つの論理CPUの100%に等しくなければならないことです。 (これが事実以外の状況もあります。たとえば、ダウンロードしたファイルを使用する場合、ネットワークが制限要因であるwgetことがよくあります。)

簡単なテストはこの仮定に違反します。これが期待されるか。それが予想される場合、私ができる一連の条件はありますか?しなければならない私は仮説が真実であると期待していますか?

「iowait」の背景情報は以下の通りです。CPUは、IOが保留中であるかどうかをどうやって知ることができますか? ここへの答えは、累積iowaitが「特定の条件下で減少する可能性がある」という反直観的なアイデアを引用しています。私の簡単なテストが文書化されていない状況を引き起こす可能性があるかどうか疑問に思います。

修正する:お願いします回答にスキップ

答えは私が最初に使用したよりも簡単なテストです。以下に元の質問を残しました。元の質問にはいくつかの追加の詳細が表示されることがあります。

元の質問

短いテストでは、ddカーネルにランダムなバイトを生成し、それをファイルに書き込むように要求しました。カーネルで消費されたCPU時間を計算するためにdd内部で命令を実行しました。perf stat私も内部を実行しperf trace -s、内部で過ごした時間を報告しましたwrite()。同時にvmstat 5別の端末を実行して「iowait」システムを確認しました。

  1. 私は、少なくともCPU全体が「アイドル状態ではない」状態、つまり100%実行中または停止しているがIO(「iowait」状態)を待っている状態を見ることを期待しています。いいえ。
  2. (また、「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使用してカーネルからインポートされます。noopIOスケジューラcfqも同様の結果を提供しました。

(同様の構成に基づいていますが、カーネルバージョン5.1に近いですmq-deadlineblk-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出力ブロック)を見ると、テストが実行されている時期がわかります。wavmstatiobo

$ 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アーキテクチャの特定のコードをカバーしています。それで、この問題を解決するのは簡単ではないと言いたいのです。

おすすめ記事