mmap(2) を使うと速いとか言われているので試してみた。

以下サンプルコード。 ubuntu9.10 で辞書ファイルが二つあったのでそれを開くようにしている。

  • gcc -DUSE_READ test.c とすると read(2) 版
  • gcc test.c とすると mmap(2) 版

となるようにしている。

#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>


const char *files[] = {
        "/usr/share/dict/american-english",
        "/usr/share/dict/british-english",
};


int main(int argc, char *argv[])
{
#if USE_READ
        int loop = 0;
        int fd;
        struct stat st;
        char *p, *dst;
        off_t len;
        ssize_t nr;

        for (loop = 0; loop < 100; loop++) {
                fd = open(files[loop%2], O_RDONLY);
                if (fd == -1) {
                        perror("open");
                        return 1;
                }
                if (fstat(fd, &st) == -1) {
                        perror("fstat");
                        return 1;
                }
                p = (char *)malloc(st.st_size);
                nr = read(fd, p, st.st_size);
                if (nr == -1) {
                        perror("read");
                        return 1;
                }
                dst = (char *)malloc(st.st_size + 1);
                for (len = 0; len < st.st_size; len++) {
                        dst[len] = p[len];
                }
                dst[len+1] = 0;
                free(dst);
        }

        return 0;
#else
        int loop = 0;
        int fd;
        struct stat st;
        char *p, *dst;
        off_t len;

        for (loop = 0; loop < 100; loop++) {
                fd = open(files[loop%2], O_RDONLY);
                if (fd == -1) {
                        perror("open");
                        return 1;
                }
                if (fstat(fd, &st) == -1) {
                        perror("fstat");
                        return 1;
                }
                p = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
                if (p == MAP_FAILED) {
                        perror("mmap");
                        return 1;
                }
                if (close(fd) == -1) {
                        perror("close");
                        return 1;
                }
                dst = (char *)malloc(st.st_size + 1);
                for (len = 0; len < st.st_size; len++) {
                        dst[len] = p[len];
                }
                dst[len+1] = 0;
                if (munmap(p, st.st_size) == -1) {
                        perror("munmap");
                        return 1;
                }
                free(dst);
        }

        return 0;
#endif
}

実行結果は以下。素直に mmap(2) が速い。read(2) はキャッシュに載っていないケース(と思われる)で顕著に遅くなる場合がある。

xubuntu:yagihiro% time ./use_mmap
./use_mmap  0.02s user 0.02s system 7% cpu 0.622 total
xubuntu:yagihiro% time ./use_mmap
./use_mmap  0.03s user 0.02s system 7% cpu 0.637 total
xubuntu:yagihiro% time ./use_mmap
./use_mmap  0.03s user 0.02s system 8% cpu 0.640 total
xubuntu:yagihiro% time ./use_mmap
./use_mmap  0.04s user 0.01s system 7% cpu 0.631 total
xubuntu:yagihiro% time ./use_read
./use_read  0.00s user 0.24s system 7% cpu 3.089 total
xubuntu:yagihiro% time ./use_read
./use_read  0.03s user 0.02s system 7% cpu 0.741 total
xubuntu:yagihiro% time ./use_read
./use_read  0.03s user 0.03s system 7% cpu 0.740 total
xubuntu:yagihiro% time ./use_read
./use_read  0.04s user 0.02s system 8% cpu 0.728 total
xubuntu:yagihiro% time ./use_read
./use_read  0.02s user 0.03s system 7% cpu 0.747 total