この記事の番外編?的な記事。もっと早くならんかねを検証してみる。前回よりもファイル数を倍くらいにしてる(違う検証をしてたらこうなってしまっただけ)ので前回のデータとの単純な比較は出来ないです。
前回の最速のソース
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <dirent.h> int main(int argc, char **argv) { DIR *dir; struct dirent *dp; char path[512]; if(setvbuf(stdout, NULL, _IOFBF, 2147483647) != 0 ){ printf("setvbuf error\n"); } if(argc<=1){ strcpy(path,"."); } else { strcpy(path,argv[1]); } if((dir=opendir(path))==NULL){ perror("opendir"); exit(1); } for(dp=readdir(dir);dp!=NULL;dp=readdir(dir)){ fprintf(stdout, "%s\n",dp->d_name); } }
これに対してtimeとstraceをするとgetdetns64の数を減らしてあげることができればさらに早くすることはできそう
root@master001:/tmp/lstest2# time ./a.out lstest > ls.lst real 0m2.612s user 0m0.124s sys 0m0.675s root@master001:/tmp/lstest2# strace -c ./a.out lstest > ls.lst % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 92.06 0.555802 261 2125 getdents64 7.79 0.047044 7 6133 write ------ ----------- ----------- --------- --------- ---------------- 100.00 0.603770 72 8296 2 total
getdents(2)のmanを見るとどうやらbufferを取ることが出来るっぽいのでやってみる。syscall(2)で呼ぶ必要がある
#define _GNU_SOURCE #include <dirent.h> /* DT_* 定数の定義 */ #include <fcntl.h> #include <stdint.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/syscall.h> #define handle_error(msg) \ do { perror(msg); exit(1); } while (0) struct linux_dirent { unsigned long d_ino; off_t d_off; unsigned short d_reclen; char d_name[]; }; #define BUF_SIZE 1024 * 1024 // ここのサイズを変化させて計測してみた int main(int argc, char *argv[]) { int fd; long nread; char buf[BUF_SIZE]; struct linux_dirent *d; char d_type; fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY); if (fd == -1) handle_error("open"); for (;;) { nread = syscall(SYS_getdents, fd, buf, BUF_SIZE); if (nread == -1) handle_error("getdents"); if (nread == 0) break; for (long bpos = 0; bpos < nread;) { d = (struct linux_dirent *) (buf + bpos); d_type = *(buf + bpos + d->d_reclen - 1); printf("%s\n", d->d_name); bpos += d->d_reclen; } } exit(0); }
BUF_SIZEをそれぞれ以下のように変えてファイル数を固定にしてそれぞれ計測してみた。
BUF_SIZE | seconds | usecs/call | calls |
---|---|---|---|
1KB | 0.880076 | 12 | 68795 |
4KB | 0.680982 | 39 | 17036 |
16KB | 0.605966 | 142 | 4250 |
128KB | 0.602617 | 1132 | 532 |
512KB | 0.584683 | 4363 | 134 |
1MB | 0.559468 | 8227 | 68 |
2MB | 0.613253 | 17521 | 35 |
大体1MBあたりが一番早くなりそうであった。元のソースと30回のずつの平均を比較すると5%程度高速化することが分かった。
- 前回: 2.911s
- 今回: 2.774s
感想
いつ使えるか分からない話ではあるが勉強にはなったのでよかった