web-dev-qa-db-ja.com

スワップオフはどのように遅くなりますか?

どういうわけか私はたまたま14 GBのメモリをスワップアウトしました。犯人を殺した後、私は再びたくさんの空きメモリを持っているので、私は 重要なデータを取り込む をもう一度できると思った。したがって、32 GBのうち5 GBが使用され、14 GBのスワップ領域が使用されたため、swapoff -a....そして4時間後、約半分の作業が終了しました。

つまり、1 MB /秒未満ですが、200 MB /秒を簡単にコピーできます。私のスワップは暗号化されていますが、すべての通常のパーティションも暗号化されており、 aes-ni を使用すると、顕著なCPU負荷が発生しません(スワップスペースを埋めるのに数分しかかかりませんでした)。 swapoffを最適化する特別な理由はないようですが、どうしてそんなに遅くなるのでしょうか?


さらにデータを追加するだけです。メインメモリは32 GBで、4つのハードディスクのそれぞれに32 GBのスワップ領域があります(確かに過剰ですが、誰が気にしますか?)。スワップ領域全体を(復号化して)5分未満で読み取ることができます。

time -p Sudo sh -c 'for i in /dev/mapper/cryptswap?; do md5sum $i & done; wait'
014a2b7ef300e11094134785e1d882af  /dev/mapper/cryptswap1
a6d8ef09203c1d8d459109ff93b6627c  /dev/mapper/cryptswap4
05aff81f8d276ddf07cf26619726a405  /dev/mapper/cryptswap3
e7f606449327b9a016e88d46049c0c9a  /dev/mapper/cryptswap2
real 264.27

パーティションの一部を読み取ることは、すべてを読み取ることよりも遅くなることはありません。しかし、その約1/10の読み取りには、約100倍の時間がかかります。

swapoffの間、CPUはほとんどアイドル(おそらく1コアの10%)であり、ディスク(LEDによって「測定」)も同様でした。また、スワップスペースが次々とオフになっていることもわかりました。

82
maaartinus

最初に、ハードドライブから何が期待できるかを見てみましょう。ハードドライブは、200 MB /秒を順次実行できます。シーク時間を考慮に入れると、ずっと遅くなる可能性があります。任意の例を選択するには、Seagateの最新の3 TBディスクの1つである ST3000DM001 の仕様を見てください。

  • 最大持続データレート:210 MB /秒

  • 平均読み取りを求める:<8.5 ms

  • セクターあたりのバイト数:4,096

シークする必要がなく、スワップがディスクのエッジの近くにある場合は、最大レート=210 MB/s

ただし、スワップデータが完全に断片化されている場合、最悪のシナリオでは、読み取るすべてのセクターを探し回る必要があります。つまり、8.5 msごとに4 KB、または4 KB/0.0085 =470 KB/sのみを読み取ることができます。

だから、すぐに、ハードドライブの速度に逆らって走っているのは考えられないではありません。


とはいえ、swapoffの実行速度が非常に遅く、ページが順不同で読み込まれる場合は特に順不同でページを読み取る必要があるのはばかげているように見えます。しかし、それはカーネルがどのように機能するかだけかもしれません。 Ubuntuバグレポート #486666 は同じ問題について説明しています:

_The swap is being removed at speed of 0.5 MB/s, while the
hard drive speed is 60 MB/s;
No other programs are using harddrive a lot, system is not under
high load etc.

Ubuntu 9.10 on quad core.

Swap partition is encrypted.
Top (atop) shows near 100% hard drive usage
  DSK | sdc | busy 88% | read 56 | write 0 | avio 9 ms |
but the device transfer is low (kdesysguard)
  0.4 MiB/s on /dev/sdc reads, and 0 on writes
_

回答の1つは次のとおりです。

_It takes a long time to sort out because it has to rearrange and flush the
memory, as well as go through multiple decrypt cycles, etc. This is quite
normal
_

バグレポートは未解決のままクローズされました。

Mel Gormanの本 " Linux Virtual Memory Managerについて "は少し古くなっていますが、これは処理が遅いことに同意します。

エリアの非アクティブ化を担当する関数は、予想どおり十分にsys_swapoff()と呼ばれます。この関数は、主に_swap_info_struct_の更新に関係しています。ページアウトされた各ページのページングの主なタスクは、try_to_unuse()の責任です。これは、非常に費用がかかります。

speeding up swapoff 」という件名のlinux-kernelメーリングリストでは、2007年からもう少し議論があります-彼らが議論している速度は、あなたが見ているものよりも少し速いです。


swapoffはめったに使用されないため、これはおそらく一般的に無視される興味深い質問です。本当に追跡したい場合、最初のステップはディスクの使用パターンをより注意深く監視しようとすることだと思います(多分atopiostat、またはperfsystemtapなどのさらに強力なツールを使用します)。探しているものは、過度のシーク、小さなI/O操作、データの継続的な書き換えや移動などです。

58
Jim Paris

SSDを搭載したラップトップでも同じ問題が発生しているため、シーク時間は問題になりません。

私は 代替説明 を見つけました。ここに抜粋があります

現在の動作方法であるswapoffは、スワップパーティション内のスワップアウトされた各メモリページを調べ、それを使用するすべてのプログラムを見つけようとします。すぐに見つけられない場合は、実行中のすべてのプログラムのページテーブルを調べて見つけます。最悪の場合、パーティション内のスワップアウトされたすべてのページのすべてのページテーブルがチェックされます。そうです。同じページテーブルが何度も何度もチェックされます。

したがって、それは何よりもカーネルの問題です。

37
Nick Craig-Wood

うん、swapoffメカニズムは恐ろしく非効率的です。回避策は簡単です。プロセスを繰り返し処理する代わりに、スワップされたページを繰り返し処理します。これを使用pythonスクリプト(私は提携していません):

_git clone https://github.com/wiedemannc/deswappify-auto
_

デーモンの動作モードは、しばしば休止状態になっているデスクトップ/ラップトップ専用です。サーバーシステムでデーモンとして実行することはありません。フォアグラウンドで実行し、いくつかのプロセスを処理したと報告されるまで待ってから、停止してから実行してください。

_swapoff /dev/x
_

ほとんどのページがスワップとメモリの両方に存在するようになったので、swapoffを実行する必要はほとんどなく、非常に高速になります(数百MB /秒)。

先の歴史セクション

前述のpythonスクリプトは、この回答の残りに基づいています。これは、私の改善でした この古い回答 によって作成されましたjlong​​。スクリプトの方がはるかに安全であるため、私は最後の防御線として残りの回答のみを試すことをお勧めします

_Perl -we 'for(`ps -e -o pid,args`) { if(m/^ *(\d+) *(.{0,40})/) { $pid=$1; $desc=$2; if(open F, "/proc/$pid/smaps") { while(<F>) { if(m/^([0-9a-f]+)-([0-9a-f]+) /si){ $start_adr=$1; $end_adr=$2; }  elsif(m/^Swap:\s*(\d\d+) *kB/s){ print "SSIZE=$1_kB\t gdb --batch --pid $pid -ex \"dump memory /dev/null 0x$start_adr 0x$end_adr\"\t2>&1 >/dev/null |grep -v debug\t### $desc \n" }}}}}' | sort -Vr | head
_

これはおそらく2秒で実行され、実際には何も実行せず、上位10のメモリセグメントをリストします(実際には、ワンライナーがより多く印刷されます。はいIdoワンライナーが大好きです。 ;コマンドを確認してリスクを受け入れ、シェルにコピーして貼り付けます。これらは実際にはスワップから読み取られます)。

_...Paste the generated one-liners...
swapoff /your/swap    # much faster now
_

メインのワンライナーは安全です(私にとって)。ただし、多くの/ procを読み取ります。

手動検査用に準備されたサブコマンドは安全ではありません。各コマンドは、スワップからメモリセグメントを読み取る間、1つのプロセスをハングさせます。したがって、一時停止を許容しないプロセスでは安全ではありません。私が見た転送速度は、毎分1ギガバイトのオーダーでした。 (前述のpythonスクリプトはその欠陥を取り除きました)。

もう1つの危険は、システムに過度のメモリ負荷をかけることです。そのため、通常の_free -m_で確認してください。

それは何をするためのものか?

_for(`ps -e -o pid,args`) {

  if(m/^ *(\d+) *(.{0,40})/) { 
    $pid=$1; 
    $desc=$2; 

    if(open F, "/proc/$pid/smaps") { 

      while(<F>) { 

        if(m/^([0-9a-f]+)-([0-9a-f]+) /si){ 
          $start_adr=$1; 
          $end_adr=$2; 
        } elsif( m/^Swap:\s*(\d\d+) *kB/s ){
          print "SSIZE=$1_kB\t gdb --batch --pid $pid -ex \"dump memory /dev/null 0x$start_adr 0x$end_adr\"\t2>&1 >/dev/null |grep -v debug\t### $desc \n" 
        }
      }
    }
  }
}
_

このPerlスクリプトの出力は、スワップされたページをメモリに呼び戻す一連のgdbコマンドdump memory (range)です。

出力はサイズから始まるため、_| sort -Vr | head_を介して簡単に渡して、サイズ(SSIZE)で上位10個の最大セグメントを取得できます。 _-V_は、バージョン番号に適した並べ替えを表しますが、私の目的には適しています。数値ソートを機能させる方法がわかりませんでした。

23
kubanczyk

スワップオフ中に、使用中のスワップスロットが検出されると、カーネルは最初にページをスワップします。次に、関数unuse_process()は、スワップインされたばかりのページに対応するすべてのページテーブルエントリを見つけようとし、ページテーブルに必要な更新を行います。検索は徹底的で非常に時間がかかります:(システム全体の)すべてのメモリ記述子にアクセスし、ページテーブルエントリを1つずつ調べます。

「Linuxカーネル3rdバージョンについて」の724ページを参照してください。

11
Leslie