8

mmap を使用してコピー オン ライト マッピング (MAP_PRIVATE) を作成すると、特定のアドレスに書き込むとすぐに、このマッピングの一部のページがコピーされます。プログラムのある時点で、どのページが実際にコピーされたかを把握したいと考えています。「mincore」と呼ばれる呼び出しがありますが、それはページがメモリ内にあるかどうかのみを報告します。これは、コピーされているページとは異なります。

どのページがコピーされたかを知る方法はありますか?

4

6 に答える 6

9

MarkRのアドバイスに従って、 pagemapと kpageflags インターフェイスを試してみました。以下は、ページが呼び出されたときにページがメモリ 'SWAPBACKED' にあるかどうかを確認する簡単なテストです。もちろん、1 つの問題が残ります。それは、kpageflags がルートにしかアクセスできないという問題です。

int main(int argc, char* argv[])
{
  unsigned long long pagesize=getpagesize();
  assert(pagesize>0);
  int pagecount=4;
  int filesize=pagesize*pagecount;
  int fd=open("test.dat", O_RDWR);
  if (fd<=0)
    {
      fd=open("test.dat", O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);
      printf("Created test.dat testfile\n");
    }
  assert(fd);
  int err=ftruncate(fd,filesize);
  assert(!err);

  char* M=(char*)mmap(NULL, filesize, PROT_READ|PROT_WRITE, MAP_PRIVATE,fd,0);
  assert(M!=(char*)-1);
  assert(M);
  printf("Successfully create private mapping\n");

テスト セットアップには 4 ページが含まれます。ページ 0 と 2 が汚れています

  strcpy(M,"I feel so dirty\n");
  strcpy(M+pagesize*2,"Christ on crutches\n");

3ページ目から読了。

  char t=M[pagesize*3];

ページ 1 はアクセスされません

pagemap ファイルは、プロセスの仮想メモリを実際のページにマップします。これは、後でグローバル kpageflags ファイルから取得できます。ファイル /usr/src/linux/Documentation/vm/pagemap.txt を読み取ります

  int mapfd=open("/proc/self/pagemap",O_RDONLY);
  assert(mapfd>0);
  unsigned long long target=((unsigned long)(void*)M)/pagesize;
  err=lseek64(mapfd, target*8, SEEK_SET);
  assert(err==target*8);
  assert(sizeof(long long)==8);

ここでは、各仮想ページのページ フレーム番号を読み取ります。

  unsigned long long page2pfn[pagecount];
  err=read(mapfd,page2pfn,sizeof(long long)*pagecount);
  if (err<0)
    perror("Reading pagemap");
  if(err!=pagecount*8)
    printf("Could only read %d bytes\n",err);

仮想フレームごとに、実際のページフラグを読み取ろうとしています。

  int pageflags=open("/proc/kpageflags",O_RDONLY);
  assert(pageflags>0);
  for(int i = 0 ; i < pagecount; i++)
    {
      unsigned long long v2a=page2pfn[i];
      printf("Page: %d, flag %llx\n",i,page2pfn[i]);

      if(v2a&0x8000000000000000LL) // Is the virtual page present ?
        {
        unsigned long long pfn=v2a&0x3fffffffffffffLL;
        err=lseek64(pageflags,pfn*8,SEEK_SET);
        assert(err==pfn*8);
        unsigned long long pf;
        err=read(pageflags,&pf,8);
        assert(err==8);
        printf("pageflags are %llx with SWAPBACKED: %d\n",pf,(pf>>14)&1);
        }
    }
}

全体として、私はこのアプローチに特に満足していません。なぜなら、私たちが一般的にアクセスできないファイルへのアクセスが必要であり、非常に複雑だからです (ページフラグを取得するための単純なカーネル呼び出しはどうですか?)。

于 2010-12-20T05:16:26.247 に答える
3

私は通常mprotect、追跡対象のコピー オン ライト ページを読み取り専用に設定し、指定されたページをダーティとしてマークして書き込みを有効にすることで、結果の SIGSEGV を処理します。

理想的ではありませんが、オーバーヘッドは非常に管理しやすくmincore、 などと組み合わせて使用​​して、ワーキング セットのサイズを管理したり、スワップ アウトが予想されるページのポインター情報を概算したりするなど、より複雑な最適化を行うことができます。ランタイムシステムがカーネルと戦うのではなく、カーネルと協力できるようにします。

于 2011-05-05T02:44:30.103 に答える
2

コピーオンライトは、仮想メモリハードウェアのメモリ保護スキームを使用して実装されます。

読み取り専用ページが書き込まれると、ページフォールトが発生します。ページフォールトハンドラーは、ページにコピーオンライトフラグがあるかどうかを確認します。ある場合は、新しいページが割り当てられ、古いページのコンテンツがコピーされて、書き込みが再試行されます。

新しいページは読み取り専用でもコピーオンライトでもありません。元のページへのリンクは完全に壊れています。

したがって、実行する必要があるのは、ページのメモリ保護フラグをテストすることだけです。

Windowsでは、APIはです。GetWorkingSetの説明を参照してくださいVirtualQueryEx。対応するLinuxAPIが何であるかわかりません。

于 2010-12-19T16:35:01.053 に答える
2

同様の目標を持つ人に回答し、あなたと同様の質問を参照しました。

その質問に対するbmarguliesの答えは、2つのアイデアが組み合わされたときに必要なものに完全に適合すると思います。

于 2011-01-27T00:37:58.437 に答える
2

簡単ではありませんが、これを判断することは可能です。ページが別のページ (おそらく別のプロセス) のコピーであるかどうかを確認するには、次の手順を実行する必要があります (カーネルを最新化します)。

  1. プロセス内の適切なページについては、/proc/pid/pagemap のエントリを読み取ります。
  2. /proc/kpageflags を調べる

次に、メモリ内で 2 つのページが実際には同じページであると判断できます。

これを行うのはかなりトリッキーです。root になる必要があります。また、何を行うにしても、競合状態が発生する可能性がありますが、可能です。

于 2010-12-19T16:08:45.927 に答える
1

そのような API がエクスポートされた覚えはありません。なぜそのようなことをしたいのか(あなたが解決している問題の根本は何ですか?)

/proc/[pid]/smaps (使用/コピー/保存されたページの詳細な統計を提供します) を確認することをお勧めします。

繰り返しますが、なぜそれをしたいのですか?このアプローチが唯一の方法であると確信している場合 (通常、仮想メモリが使用され、忘れられている場合)、そのような機能を処理するカーネル モジュールを作成することを検討してください。

于 2010-12-18T11:10:55.860 に答える