预读对从外设解压文件的影响

March 30, 2013

我每天都要用个脚本从一个读取很慢的U盘上解压些文件到tmpfs,以前我是这样做的:

cat /path/to/big/compressed-file > /dev/null
tar xf /path/to/big/compressed-file -C /tmp

我先用cat把整个文件读了,然后再解压。那是我的想法是直接tar解压就要边读边解压,CPU要等待IO,那样会很慢的,所以我先把整个文件读一遍,cache里有了这个文件之后,然后再解压,CPU就不用等那么久。也就是先把IO一次做了然后减少CPU等待。

然后今天我Linux有个readahead的系统调用,还有个同名工具,就是把文件放到cache里的,所以想把脚本里cat换掉。换之前我觉得要测试一下。

测试方法

方法就是用各种方法把U盘上的一个文件解压到/tmp。

这是测试用的文件:

lsl java-7-openjdk-u7.tar.xz
-rw-r--r-- 1 root root 52M Oct 21 10:25 java-7-openjdk-u7.tar.xz

只测了xz压缩的文件,其他格式可能不一样。

根据需要,每次测试前要把cache drop掉,避免上一次测试的影响:

sudo sh -c 'echo 1 > /proc/sys/vm/drop_caches '

测试结果

无cache,单独readahead:

time readahead java-7-openjdk-u7.tar.xz

real	0m6.462s
user	0m0.000s
sys	0m0.013s

无cache,单独cat:

time cat java-7-openjdk-u7.tar.xz > /dev/null

real	0m6.619s
user	0m0.003s
sys	0m0.060s

无cache,tar(xz):

time tar xf java-7-openjdk-u7.tar.xz -C /tmp/

real	0m6.994s
user	0m5.300s
sys	0m0.400s

有cache,tar(xz):

time tar xf java-7-openjdk-u7.tar.xz -C /tmp/

real	0m5.335s
user	0m5.260s
sys	0m0.343s

无cache,readahead + tar(xz):

time (readahead java-7-openjdk-u7.tar.xz > /dev/null && tar xf java-7-openjdk-u7.tar.xz -C /tmp/)

real	0m12.314s
user	0m5.203s
sys	0m0.360s

无cache,cat + tar(xz):

time (cat java-7-openjdk-u7.tar.xz > /dev/null && tar xf java-7-openjdk-u7.tar.xz -C /tmp/)

real	0m12.789s
user	0m5.193s
sys	0m0.423s

结论与分析

readahead一直都比cat快,我想这是因为cat使用很多read/write系统调用来复制文件,而readahead主要部分就一个readahead系统调用。

在我意料之外的是,直接解压一直都比预读+解压要快,看来我最初的想法是适得其反。