ext2,3で、1ディレクトリに大量のファイルがあるとlsが遅い件の対処とか
遅いのは知ってた。で、対処をどうすべきかと考えていたが、自分はlsが遅いのはreaddirとかの関数が遅くて、しょうがないのだと思っていたが、どうもそうではなかった。
lsが遅いのは、それぞれのファイルについて、その名前以外の情報をいつもstatしてたからなのだった。「lsすら遅い」のではなくて「lsするから遅い」のであった。
だから、ファイルの一覧が必要ならば、readdirすればいいだけなのであった。たとえば↓のような、manpageから引っこ抜いただけのようないい加減なコードでも、だいたい動く(SEGVとかするので、さすがにそこは直した)
#include#include #include #include int main(int argc, char *argv[]) { DIR *dirp; struct dirent *dp; if (argc != 2 ) { printf("coundn't open dir\n"); return; } if ( (dirp = opendir(argv[1]) ) == NULL) { printf("coundn't open dir\n"); return; } do { errno = 0; if ( (dp = readdir(dirp) ) != NULL) { (void) printf("%s\n", dp->d_name); } } while (dp != NULL); if (errno != 0) perror("error reading directory "); (void) closedir(dirp); return(0); }
しかし、本当にreaddirは遅くないのか?というと、1ディレクトリに数万個のファイルが有った場合には、それなりに時間がかかるもののようだ。(CPU時間で0.3秒くらい?)
Kernelは2.6.9-42.ELsmp #1 SMPでCentOS4.4 1CPUbogomipsは 4800程度で、strace -c の結果はこんな感じ
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 96.08 0.275670 2484 111 getdents64 3.53 0.010142 16 620 write 0.16 0.000473 158 3 open 0.12 0.000339 339 1 execve 0.03 0.000075 15 5 old_mmap 0.02 0.000045 11 4 brk 0.01 0.000038 10 4 fstat64 0.01 0.000030 30 1 read 0.01 0.000024 8 3 close 0.01 0.000022 11 2 mprotect 0.01 0.000017 17 1 munmap 0.01 0.000016 16 1 1 access 0.00 0.000012 12 1 uname 0.00 0.000007 7 1 mmap2 0.00 0.000005 5 1 fcntl64 0.00 0.000005 5 1 set_thread_area ------ ----------- ----------- --------- --------- ---------------- 100.00 0.286920 760 1 total
極普通のディレクトリでこれを実行しても、getdents64は2,3回がせいぜい。
ちょっと訂正というか、追加情報。
上記の結果は、NFSでマウントしているディレクトリだった。
直付けの場合、何度かreaddirを実行してると、kernelのキャッシュだの、ディスク自体のキャッシュが比較的良く効いて来るようだ。たとえば、1ディレクトリに100万個ぐらいファイルがあっても、getdentsの処理時間が十数マイクロ秒ということもある。(Kernel 2.6.9-42.ELsmp、 1CPUのBogomipsは5500程度)
# strace -c readdir . > /dev/null % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 80.44 0.442220 14 30821 getdents64 19.48 0.107076 8 13018 write 0.03 0.000149 149 1 execve 0.01 0.000054 11 5 old_mmap 0.01 0.000038 13 3 open 0.01 0.000035 35 1 read 0.01 0.000031 8 4 fstat64 0.01 0.000030 8 4 brk 0.00 0.000022 11 2 mprotect 0.00 0.000014 5 3 close 0.00 0.000013 13 1 munmap 0.00 0.000011 11 1 1 access 0.00 0.000008 8 1 mmap2 0.00 0.000008 8 1 fcntl64 0.00 0.000007 7 1 1 ioctl 0.00 0.000007 7 1 uname 0.00 0.000003 3 1 set_thread_area ------ ----------- ----------- --------- --------- ---------------- 100.00 0.549726 43869 2 total