2012-07-06 4 views
5

巨大なファイルのどの部分がメモリにキャッシュされているか知りたい。私はfincoreからいくつかのコードを使用しています。これは、この方法で動作します。ファイルがmmapedされ、fincoreがアドレススペースをループし、mincoreでページをチェックしますが、ファイルサイズ(数TB) )。Linux:メモリ内のページを特定する

代わりに使用済み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; 
} 
+2

1つの8 TBファイルをマッピングするには、2億の4kページが必要です。 48秒間の「ミニコア」の実行時間は、調べられる44.7Mpages /秒を意味する。これがいかに速く進むと思うか? 'printf()'で数百億〜数十億行の行を印刷することも、世界で最速のものではありません。 –

+0

私はmmap/mincoreがそれより速くなることを望んでいません。私が望むのは、ループの長さを減らすことです。おそらく少ないページをスキャンすることによって可能です。 – wazoox

+0

'printf'は通常非常に遅い操作です。それを 'activePages ++'のようなものに置き換えて、ループを処理するのにかかる時間を確認してください。 'vec'がまだ2 GiBであり、' mincore'を呼び出すことさえ、 'vec'に割り当てられた仮想アドレス空間の中で物理メモリが触れられているので、キャッシュの内容を変更するかもしれません。 –

答えて

0

は?

ブート後にファイルがディスク上にあると考えてください。その部分は記憶されていません。

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

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

C標準ライブラリがキャッシングされます。

カーネルは、ユーザーモードメモリのC標準ライブラリであるカーネルモードメモリにキャッシュされます。

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

+0

iscsiターゲットなので、ディスクキャッシュにカーネルによってキャッシュされます。キャッシュの使用状況と進化を時間とともに監視したいと思います。 – wazoox

1

リストを表すために必要な情報量は、すべてまたはほとんどすべてのページが実際にRAMに入っている悲観的なケースでは、ビットマップよりもはるかに高い - 少なくとも64対1ビット/エントリ。このようなAPIがある場合は、20億ページ分のデータを照会するときに、返信に16 GBのデータを取得する準備が必要です。さらに、リストなどの可変長構造体を扱うことは、固定長配列を扱うより複雑です。したがって、ライブラリ関数、特にローレベルのシステム関数は、この面倒を避ける傾向があります。

私は実装(OSがTLBやCoとこの場合はどのようにやりとりするか)についてはあまりよく分かりませんが、ビットマップを埋めても情報が抽出されるOSおよびハードウェアレベルの構造によるリスト。

粒度が非常に細かいことを心配していない場合は、/proc/<PID>/smapsをご覧ください。マップされた各領域に対して、メモリにどれだけロードされたかを含むいくつかの統計情報が表示されます(Rssフィールド)。実際のタスクを実行するために使用されるメインマッピングに加えて別のmmap()コールを使用してファイルの一部の領域をマップするデバッグの場合は、おそらくsmapsに別のエントリがあり、したがってこれらの領域の個別の統計情報が表示されます。ほとんどの場合、システムを強制終了せずに何十億ものマッピングを作成することはほとんどできませんが、ファイルがうまく構成されていれば、選択した数十の地域だけ別の統計を持つことができます。

+0

私は確かにスワップを試みた。しかし何らかの理由で、他のプロセスによってマップされたメモリページは報告されないので、この特定のケースでは私を助けません。私が実際に探しているのは、MMUの仮想アドレスから物理アドレスへのアクセスです:) – wazoox

関連する問題