我每天都要用个脚本从一个读取很慢的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系统调用。
在我意料之外的是,直接解压一直都比预读+解压要快,看来我最初的想法是适得其反。