Linux上で任意のファイルがページキャッシュに乗っているかどうか調べるCで書かれたプログラムを見つけたので、コンパイルして実行してみた。
Linux上のとあるファイルがページキャッシュに乗っているかどうかを調べたいなーと思ってGoogle先生にご相談したところ、こんなコマンドを教えてくれた。
ファイルをメモリにマップして、mincore(2)でページごとにRAMに存在するかどうかをチェックしているらしい。
mmapしても即メモリにロードされるわけではないのかぁ。
Cの部分だけ抜き出して、単体で動かしてみた。
#include <errno.h> /* errno */ #include <fcntl.h> /* fcntl, open */ #include <stdio.h> /* perror, fprintf, stderr, printf */ #include <stdlib.h> /* exit, calloc, free */ #include <string.h> /* strerror */ #include <sys/stat.h> /* stat, fstat */ #include <sys/types.h> /* size_t */ #include <unistd.h> /* sysconf, close */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> void fincore(char *filename) { int fd; struct stat st; void *pa = (char *)0; char *vec = (char *)0; register size_t n = 0; size_t pageSize = getpagesize(); register size_t pageIndex; int sum = 0; printf("pagesize: %ld\n", pageSize); fd = open(filename, 0); if (0 > fd) { perror("open"); return; } if (0 != fstat(fd, &st)) { perror("fstat"); close(fd); return; } printf("filesize: %ld\n", st.st_size); pa = mmap((void *)0, st.st_size, PROT_NONE, MAP_SHARED, fd, 0); if (MAP_FAILED == pa) { perror("mmap"); close(fd); return; } printf("page num: %ld\n", (st.st_size+pageSize-1)/pageSize); /* vec = calloc(1, 1+st.st_size/pageSize); */ vec = calloc(1, (st.st_size+pageSize-1)/pageSize); if ((void *)0 == vec) { perror("calloc"); close(fd); return; } if (0 != mincore(pa, st.st_size, vec)) { /* perror("mincore"); */ 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 */ for (pageIndex = 0; pageIndex <= st.st_size/pageSize; pageIndex++) { if (vec[pageIndex]&1) { //printf("%lu\n", (unsigned long)pageIndex); sum++; } } free(vec); vec = (char *)0; munmap(pa, st.st_size); close(fd); printf("in memory pages: %d\n", sum); return; } int main(int argc, char **argv) { fincore(argv[1]); }ファイルがキャッシュに乗ってのっているかどうかを調べる - lambda {|diary| lambda { diary.succ! } }.call(hatena)
とりあえず、コピペしてコンパイルして実行してみる。
コンパイルする
oel11gr2 root% gcc -o fincore_min fincore_min.c oel11gr2 root% ls -l fincore_min* -rwxr-xr-x 1 root root 6825 Nov 11 02:09 fincore_min -rw-r--r-- 1 root root 1974 Nov 11 01:56 fincore_min.c
使ってみる
- free コマンドで cached のサイズを確認しておく。
oel11gr2 root% free total used free shared buffers cached Mem: 1035064 225656 809408 0 15992 161140 -/+ buffers/cache: 48524 986540 Swap: 2096472 0 2096472
- 今回、ページキャッシュに乗せるファイル「dummy」のサイズは100MB。
oel11gr2 root% ls -lh dummy -rw-r--r-- 1 root root 100M Nov 11 02:16 dummy
- ページキャッシュに乗っているページは0個。
oel11gr2 root% ./fincore_min dummy pagesize: 4096 filesize: 104857600 page num: 25600 in memory pages: 0
- ファイルを読み込んで、ページキャッシュに乗せる。
oel11gr2 root% cat dummy > /dev/null
- 見事に全ページがページキャッシュに乗っている。
oel11gr2 root% ./fincore_min dummy pagesize: 4096 filesize: 104857600 page num: 25600 in memory pages: 25600
- free で cached を確認すると、100MB増えている。
oel11gr2 root% free total used free shared buffers cached Mem: 1035064 329804 705260 0 16140 263764 -/+ buffers/cache: 49900 985164 Swap: 2096472 0 2096472
- キャッシュを解放する。
oel11gr2 root% echo 3 > /proc/sys/vm/drop_caches
- ページキャッシュに乗っているページが 0 個になる。
oel11gr2 root% ./fincore_min dummy pagesize: 4096 filesize: 104857600 page num: 25600 in memory pages: 0
参考
追記(2012/11/14):
Documentation/filesystems/proc.txt には以下の通り書かれていました。
drop_caches ----------- Writing to this will cause the kernel to drop clean caches, dentries and inodes from memory, causing that memory to become free. To free pagecache: echo 1 > /proc/sys/vm/drop_caches To free dentries and inodes: echo 2 > /proc/sys/vm/drop_caches To free pagecache, dentries and inodes: echo 3 > /proc/sys/vm/drop_caches