9

Linuxでは、プロセスがシステムに(仮想)メモリを要求すると、vma(プロセスの仮想メモリの記述子)に登録されますが、すべての仮想の物理ページは呼び出し時に予約されません。後で、プロセスがこのページにアクセスすると、エラーが発生し(アクセスによりページフォールト割り込みが生成されます)、PF#ハンドラーが物理ページを割り当て、プロセスページテーブルを更新します。

2つのケースがあります。読み取りが書き込み保護されているゼロページ(特別なグローバル事前ゼロ化ページ)へのリンクに変わる可能性がある場合の障害。書き込みの失敗(ゼロページと、必要なだけでまだ物理的にマップされていないページの両方)は、実際のプライベート物理ページの割り当てになります。

mmap(および内部的にmmapでもあるbrk / sbrk)の場合、このメソッドはページごとです。すべてのmmapされた領域は、全体としてvmaに登録されます(開始アドレスと終了アドレスがあります)。ただし、スタックには開始アドレスしかないため、他の方法で処理されます(通常のプラットフォームでは高いアドレス、低いアドレスに成長します)。

質問は:

スタックの近くにある新しい未割り当てメモリにアクセスすると、PF#を取得して大きくなります。スタックの隣のページではなく、スタックから10ページまたは100ページ離れているページにアクセスした場合、この成長はどのように処理されますか?

例えば

int main() {
  int *a = alloca(100); /* some useful data */
  int *b = alloca(50*4096); /* skip 49 pages */
  int *c = alloca(100);

  a[0]=1;
 /* no accesses to b - this is untouched hole of 49 pages */
  c[0]=1;

}

このプログラムは、スタックに割り当てられた2つまたは50のプライベート物理ページを取得しますか?

カーネルに単一のページフォールトに数十の物理ページを割り当ててから、ページごとに数十のページフォールトを割り当てるように依頼することは有益だと思います(1つの割り込み+1つのコンテキストスイッチ+Nのページ割り当て要求に対する単純でキャッシュフレンドリーなループとNの割り込み+ N個のコンテキストスイッチ+N個のページ割り当て(mmコードがIcacheから削除される可能性がある場合)。

4

2 に答える 2

4

このコードで:

int main() {
  int *a = alloca(100); /* some useful data */
  int *b = alloca(50*4096); /* skip 49 pages */
  int *c = alloca(100);
  int i;
#if TOUCH > 0
  a[0] = 1;               // [1]
#endif
#if TOUCH > 1
  c[0] = 1;               // [2]
#endif
#if TOUCH > 2
  for (i=0; i<25; i++)    // [3]
    b[i*1024] = 1;
#endif
#if TOUCH > 3
  for (i=25; i<50; i++)   // [4]
    b[i*1024] = 1;
#endif
  return 0;
}

そして、このスクリプト:

for i in 1 2 3 4; do
  gcc d.c -DTOUCH=$i
  echo "Upto [$i]" $(perf stat ./a.out 2>&1 | grep page-faults)
done

出力:

Upto [1] 105 page-faults # 0.410 M/sec
Upto [2] 106 page-faults # 0.246 M/sec
Upto [3] 130 page-faults # 0.279 M/sec
Upto [4] 154 page-faults # 0.290 M/sec
于 2012-12-21T02:12:52.007 に答える
3

mremapスタックの自動拡張は、「スタック」としてカウントされる仮想アドレス領域のサイズを変更するための自動呼び出しと考えることができます。それが処理されると、スタック領域またはバニラmmap領域へのページフォールトは同じように処理されます。つまり、一度に1ページずつ処理されます。

したがって、51ページではなく、2ページが割り当てられることになります。@perrealの経験的回答はこれを検証します...

質問の最後の部分では、連続したページフォールトのコストは、「巨大なページ」の開発につながる要因の1つです。Linuxには、ページフォールト処理を「バッチ処理」する他の方法はないと思います。何かをするかもmadviseしれませんが、ストレージ上のバッキングページを検索しているページフォールトの非常に高価な部分をほとんど最適化していると思います)。ゼロページにマップされるスタックページフォールトは、比較すると比較的軽量です。

于 2012-12-22T17:14:57.317 に答える