読み込みバッファサイズ

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という関数でした。

続く

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA