readを使った読み込みではバッファサイズを多めにしていたのでfgetcよりも早くファイルが読めました。サイズをいろいろ変えて時間を確認してみます。
このプログラムを使います。
takk@deb9:~/tmp$ cat -n readwrite.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6
7 int main(int argc, char* argv[])
8 {
9 char buf[1000];
10 int fd;
11 int size,bufsize;
12 bufsize=atoi(argv[1]);
13 fd = open ("test.dat", O_RDONLY);
14 while(1){
15 size = read(fd, buf, bufsize);
16 if(size == 0)break;
17 write(1,buf,size);
18 }
19 close(fd);
20 return 0;
21 }
takk@deb9:~/tmp$
ついでにtest.datが1Gは大きすぎて待ち時間が長くなるので、100Mぐらいのデータに作り直し。
takk@deb9:~/tmp$ rm test.dat takk@deb9:~/tmp$ truncate -s100M test.dat
バッファサイズを指定できるプログラムをビルドします。
takk@deb9:~/tmp$ gcc readwrite.c takk@deb9:~/tmp$
最初は1000Byte。
takk@deb9:~/tmp$ time ./a.out 1000 >/dev/null real 0m0.173s user 0m0.004s sys 0m0.044s takk@deb9:~/tmp$
次に100Byte。10分の1にしたのですが、時間は10倍にはなってません。
takk@deb9:~/tmp$ time ./a.out 100 >/dev/null real 0m0.820s user 0m0.044s sys 0m0.220s takk@deb9:~/tmp$
さらに10分の1。それなりに時間がかかるようになってきました。
9倍ぐらいです。
takk@deb9:~/tmp$ time ./a.out 10 >/dev/null real 0m7.277s user 0m0.348s sys 0m2.052s takk@deb9:~/tmp$
元のバッファサイズ1000Byteとくらべて、1Byteは、1000分の1でも、処理時間は1000倍以上かかってます。バッファは大切ですね。
takk@deb9:~/tmp$ time ./a.out 1 >/dev/null real 1m9.033s user 0m3.580s sys 0m19.316s takk@deb9:~/tmp$
さて、前回のfgetcを使ったプログラムですが、処理時間はこのぐらいです。fgetcは、バッファを使った読み込みらしいので速いです。
takk@deb9:~/tmp$ time ./b.out > /dev/null real 0m3.789s user 0m1.220s sys 0m0.028s takk@deb9:~/tmp$
readによる読み込み(20Byteバッファ)と同じぐらいの時間になります。
takk@deb9:~/tmp$ time ./a.out 20 >/dev/null real 0m3.676s user 0m0.188s sys 0m1.016s takk@deb9:~/tmp$
fgetcで20Byteぐらいのバッファになってるということでしょうか。
気になるのでソースを探します。glibcから。
たいてい関数名.cなので、感で検索。
takk@deb9:~/src/glibc-2.24$ find -name 'fgetc.c' takk@deb9:~/src/glibc-2.24$
見つかりません。
grepにします。
takk@deb9:~/src/glibc-2.24$ grep -r fgetc.c ChangeLog.6: * libio/fgetc.c: Use _IO_cleanup_region_start and ChangeLog.6: * libio/fgetc.c: Avoid a warning by casting _IO_funlockfile for ChangeLog.6: * stdio/fgetc.c: Likewise. ChangeLog.6: * libio/fgetc.c: Use __libc_cleanup_region_* macros instead ChangeLog.7: * libio/fgetc.c: Likewise. ChangeLog.7: * stdio/fgetc.c: Likewise. ChangeLog.9: * libio/fgetc.c: Removed. ChangeLog.13: * stdio/fgetc.c: File removed. ChangeLog.8: * libio/fgetc.c: Call _IO_cleanup_region_end with 0 and call ChangeLog.5: * libio/clearerr.c, libio/feof.c, libio/ferror.c, libio/fgetc.c, ChangeLog.5: libio/ferror.c, libio/fgetc.c, libio/filedoalloc.c, libio/fileno.c, takk@deb9:~/src/glibc-2.24$
ChangeLog.13に、fgetc.cがRemoved.とあります。結構前に削除されているようです。
面倒なので、gdb動かします。
(gdb) b main
Breakpoint 1 at 0x7d8: file fgetcfputc.c, line 7.
(gdb) r
Starting program: /home/takk/tmp/b.out
Breakpoint 1, main () at fgetcfputc.c:7
7 fp = fopen("test.dat","r");
(gdb) n
8 while((c=fgetc(fp)) != -1){
(gdb) s
_IO_getc (fp=0x555555756010) at getc.c:34
34 getc.c: そのようなファイルやディレクトリはありません.
(gdb)
getc.cというファイルの_IO_getcという関数でした。
続く


コメント