6

巨大なファイルのどの部分がメモリにキャッシュされているか知りたいです。そのためにfincoreのコードを使用しています。これは次のように機能します。ファイルはmmapされ、fincoreはアドレス空間をループし、mincoreでページをチェックしますが、ファイルサイズ(数TB)のために非常に長い(数分) )。

代わりに使用済み RAM ページをループする方法はありますか? はるかに高速ですが、それはどこかから使用済みページのリストを取得する必要があることを意味します...しかし、それを可能にする便利なシステムコールが見つかりません。

コードは次のとおりです。

#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
/* } */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/sysinfo.h>


void
fincore(char *filename) {
   int fd;
   struct stat st;

   struct sysinfo info;
   if (sysinfo(& info)) {
    perror("sysinfo");
    return;
   }

   void *pa = (char *)0;
   char *vec = (char *)0;
   size_t pageSize = getpagesize();
   register size_t pageIndex;

   fd = open(filename, 0);
   if (0 > fd) {
      perror("open");
      return;
   }

   if (0 != fstat(fd, &st)) {
      perror("fstat");
      close(fd);
      return;
   }

   pa = mmap((void *)0, st.st_size, PROT_NONE, MAP_SHARED, fd, 0);
   if (MAP_FAILED == pa) {
      perror("mmap");
      close(fd);
      return;
   }

   /* vec = calloc(1, 1+st.st_size/pageSize); */
   /* 2.2 sec for 8 TB */
   vec = calloc(1, (st.st_size+pageSize-1)/pageSize);
   if ((void *)0 == vec) {
      perror("calloc");
      close(fd);
      return;
   }

    /* 48 sec for 8 TB */
   if (0 != mincore(pa, st.st_size, vec)) {
      fprintf(stderr, "mincore(%p, %lu, %p): %s\n",
              pa, (unsigned long)st.st_size, vec, strerror(errno));
      free(vec);
      close(fd);
      return;
   }

   /* handle the results */
   /* 2m45s for 8 TB */
   for (pageIndex = 0; pageIndex <= st.st_size/pageSize; pageIndex++) {
      if (vec[pageIndex]&1) {
         printf("%zd\n", pageIndex);
      }
   }

   free(vec);
   vec = (char *)0;

   munmap(pa, st.st_size);
   close(fd);

   return;
}

int main(int argc, char *argv[]) {
    fincore(argv[1]);

    return 0;
}
4

2 に答える 2

1

リストを表すために必要な情報量は、すべてまたはほぼすべてのページが実際に RAM にある悲観的なケースでは、ビットマップよりもはるかに多くなります (エントリあたり少なくとも 64 ビット対 1 ビット)。そのような API があった場合、20 億ページについてクエリを実行するときに、応答で 16 GB のデータを取得できるように準備する必要があります。さらに、リストなどの可変長構造の処理は、固定長配列の処理よりも複雑であるため、ライブラリ関数、特に低レベルのシステム関数は面倒を避ける傾向があります。

また、実装 (この場合、OS が TLB および Co と対話する方法) についてもよくわかりませんが、(サイズの違いはさておき) ビットマップへの入力は、リストを作成するよりも高速に実行できる可能性があります。情報が抽出されるOSレベルおよびハードウェアレベルの構造。

非常に細かい粒度に関心がない場合は、 を参照してください/proc/<PID>/smaps。マップされたリージョンごとに、メモリにロードされた量を含むいくつかの統計が表示されます (Rssフィールド)。デバッグの目的で、mmap()(実際のタスクを実行するために使用されるメイン マッピングに加えて) 別の呼び出しでファイルのいくつかの領域をマップすると、おそらく別のエントリが取得されるsmapsため、これらの領域の別の統計が表示されます。システムを強制終了せずに何十億ものマッピングを作成することはほぼ確実ではありませんが、ファイルが適切に構造化されている場合は、適切に選択された数十の領域について個別の統計を取得することで、探している答えを見つけるのに役立つ可能性があります。

于 2012-07-06T17:48:37.010 に答える
0

誰によってキャッシュされましたか?

起動後、ファイルがディスク上にあることを考慮してください。その一部は記憶にありません。

これで、ファイルが開かれ、ランダム読み取りが実行されます。

ファイルシステム (カーネルなど) はキャッシュされます。

C 標準ライブラリはキャッシュされます。

カーネルはカーネル モード メモリにキャッシュし、C 標準ライブラリはユーザー モード メモリにキャッシュします。

クエリを発行できる場合は、クエリの直後 (クエリが返される前) に、キャッシュされた問題のデータがキャッシュから削除される可能性もあります。

于 2012-07-06T15:02:41.733 に答える