web-dev-qa-db-ja.com

ライトバックキャッシュ( `dirty`)は、dirty_background_ratioよりもさらに少なく制限されているようです。それは何によって制限されていますか?この制限はどのように計算されますか?

Linux 4.18.16-200.fc28.x86_64をテストしています。 free -hによると、私のシステムには合計7.7GのRAMが搭載されています。

vm.dirty*sysctlのデフォルト値があります。 dirty_background_ratioは10、dirty_ratioは20です。私が読んだすべてに基づいて、Linuxがダーティキャッシュの書き込みをRAMの10%に達すると開始することを期待しています:0.77G。また、バッファリングされたwrite()呼び出しは、ダーティキャッシュがRAMの20%(1.54G)に達したときにブロックする必要があります。

dd if=/dev/zero of=~/test bs=1M count=2000を実行し、dirtyatopフィールドを監視しました。 ddコマンドの実行中、dirty値は約0.5Gに落ち着きました。これは、ダーティバックグラウンドしきい値(0.77G)よりも大幅に低くなっています。どうすればいいの?何が欠けていますか?

dirty_expire_centisecsは3000なので、それが原因ではないと思います。私はdirty_expire_centisecsを100に、dirty_writeback_centisecsを10に下げて、dirtyが制限されているかどうかを確認することもしました。これは結果を変えませんでした。

私は最初、この調査の一環としてこれらの所見を書きました: 2013年に「USBスティックストール」の問題が報告されたのはなぜですか?既存の「No-I/Oダーティスロットル」コードでこの問題が解決されなかったのはなぜですか?


2つのしきい値の中間-15%= 1.155G-write()呼び出しが曲線で抑制(遅延)されることを理解しています。ただし、この天井の下にある場合、遅延は追加されません。ダーティページを生成するプロセスは、「フリーラン」が許可されます。

私が理解しているように、スロットリングはダーティキャッシュを15%以上に保ち、20%のハードリミットに達するのを防ぐことを目的としています。すべての状況を保証するものではありません。しかし、私は1つのddコマンドで単純なケースをテストしています。デバイスが達成する書き込み速度と一致するように、write()呼び出しを単純に制限する必要があると思います。

(いくつかの複雑な例外があるため、単純な保証はありません。たとえば、スロットルコードは、課す遅延を最大200ミリ秒に制限します。ただし、プロセスの目標レート制限が1秒あたり1ページ未満の場合はそうではありません。その場合、厳格なレート制限が適用されます。)

  • Documentation/sysctl/vm.txt -Linux v4.18
  • No-I/Oダーティスロットリング -2011 LWN.net。
  • (dirty_background_ratio + dirty_ratio)/ 2ダーティデータの合計...は、プロセスのスロットルを開始したときのダーティデータの量です- Jan Kara、201

  • ユーザーは、グローバル(バックグラウンド+ダーティ)/ 2 = 15%のしきい値を超えるとアプリケーションが抑制され、約17.5%のバランスが取られることに気付くでしょう。パッチを適用する前の動作は、20%のダーティブルメモリでスロットルすることです。

    --commit 143dfe8611a6、 " writeback:IO-less balance_dirty_pages() "

  • メモリ管理サブシステムは、デフォルトでダーティページをシステムのメモリの最大15%に制限しようとします。必要に応じて、ページがダーティになっているレートとクリーンアップできるレートに一致するように、多くのページをダーティにするプロセスをスロットルする、「魔法の関数」というbalance_dirty_pages()があります。 書き戻しおよび制御グループ 、2015 LWN.net。

  • balance_dirty_pages() Linux4.18.16の場合。
4
sourcejedi

Documentation/sysctl/vm.txt を見てください:

dirty_ratio

含む 空きページと再利用可能なページを含む利用可能な総メモリの割合、ディスク書き込みを生成しているプロセス自体がダーティデータの書き込みを開始するページ数。

使用可能なメモリの合計がシステムメモリの合計と等しくない

使用可能なメモリは global_dirtyable_memory() で計算されます。これは、空きメモリとページキャッシュの合計に相当します。スワップ可能なページ(つまり、匿名のメモリ割り当て、ファイルによってサポートされていないメモリ)は含まれません。

この動作は Linux 3.14(2014) 以降に適用されます。この変更前は、スワップ可能なページがglobal_dirtyable_memory()の合計に含まれていました。

ddコマンドの実行中の統計の例:

_$ while true; do grep -E '^(Dirty:|Writeback:|MemFree:|Cached:)' /proc/meminfo | tr '\n' ' '; echo; sleep 1; done
MemFree:         1793676 kB Cached:          1280812 kB Dirty:                 4 kB Writeback:             0 kB
MemFree:         1240728 kB Cached:          1826644 kB Dirty:            386128 kB Writeback:         67608 kB
MemFree:         1079700 kB Cached:          1983696 kB Dirty:            319812 kB Writeback:        143536 kB
MemFree:          937772 kB Cached:          2121424 kB Dirty:            312048 kB Writeback:        112520 kB
MemFree:          755776 kB Cached:          2298276 kB Dirty:            389828 kB Writeback:         68408 kB
...
MemFree:          136376 kB Cached:          2984308 kB Dirty:            485332 kB Writeback:         51300 kB
MemFree:          101340 kB Cached:          3028996 kB Dirty:            450176 kB Writeback:        119348 kB
MemFree:          122304 kB Cached:          3021836 kB Dirty:            552620 kB Writeback:          8484 kB
MemFree:          101016 kB Cached:          3053628 kB Dirty:            501128 kB Writeback:         61028 kB
_

最後の行は、約3,150,000 kBの「使用可能な」メモリと、合計562,000kBのデータがライトバックまたはライトバックを待機していることを示しています。それは17.8%になります。比率はそのレベルの上下で変動しているように見えましたが、多くの場合15%近くでした。 [〜#〜] edit [〜#〜]:これらの数字はよく見えますが、この方法を信用しないでください。それはまだ正しい計算ではなく、非常に間違った結果をもたらす可能性があります。フォローアップを参照してください ここ


私はこれを難しい方法で見つけました:

balance_dirty_pages()のトレースポイント があることに気づきました。これは、「スロットルアルゴリズムのダイナミクスの分析」に使用できます。だから私はperfを使用しました:

_$ Sudo perf list '*balance_dirty_pages'

List of pre-defined events (to be used in -e):

  writeback:balance_dirty_pages                      [Tracepoint event]
...
$ Sudo perf record -e writeback:balance_dirty_pages dd if=/dev/zero of=~/test bs=1M count=2000
$ Sudo perf script
_

dirtyが低かったため、setpoint(4096バイトのページで測定)が予想よりも低かったことがわかりました。コードをトレースしました。つまり、トレースポイント定義のfreerunにも同様に低い値が必要であり、これは_(thresh + bg_thresh) / 2_ ...に設定され、global_dirtyable_memory()に戻りました。

4
sourcejedi