sysutils/freesbie: 四十万倍の高速化 対 二倍の高速化2006年05月07日 11時00分48秒

以前にも紹介したが、FreeSBIE 2は既存のシステムを有効に利用している。Makefile と少しのスクリプトを組み合わせることで、柔軟なシステムをつくっている。

まあ、それでも改良の余地はある。img.sh とclonefs.sh は md-device を作るために、dd を使う。実は、seek を使うことにより、余計なディスクへの書き込みを減らすことが出来る。UFS は sparse file を実装しているので、途中は一気にスッ飛ばして、最後のブロックを書き込めばいい。


diff -urN freesbie2.org/scripts/clonefs.sh freesbie2/scripts/clonefs.sh
--- freesbie2.org/scripts/clonefs.sh    Tue Jan 10 18:30:07 2006
+++ freesbie2/scripts/clonefs.sh        Thu May  4 02:28:41 2006
@@ -35,7 +35,7 @@
     # Find the total dir size and initialize the vnode
     DIRSIZE=$(($(du -kd 0 | cut -f 1)))
     FSSIZE=$(($DIRSIZE + ($DIRSIZE/5)))
-    dd if=/dev/zero of=${UFSFILE} bs=1k count=${FSSIZE} >> ${LOGFILE} 2>&1
+    dd if=/dev/zero of=${UFSFILE} bs=1k count=1 seek=$((${FSSIZE} - 1)) >> ${LOGFILE} 2>&1

     DEVICE=/dev/$(mdconfig -a -t vnode -f ${UFSFILE})
     newfs -o space ${DEVICE} >> ${LOGFILE} 2>&1
diff -urN freesbie2.org/scripts/img.sh freesbie2/scripts/img.sh
--- freesbie2.org/scripts/img.sh        Wed Nov 16 19:21:42 2005
+++ freesbie2/scripts/img.sh    Thu May  4 02:31:41 2006
@@ -33,7 +33,7 @@
 SECTS=$((${CYLINDERS} * ${CYLSIZE}))

 echo "Initializing image..."
-dd if=/dev/zero of=${IMGPATH} count=${SECTS} >> ${LOGFILE} 2>&1
+dd if=/dev/zero of=${IMGPATH} count=1 seek=$((${SECTS} - 1)) >> ${LOGFILE} 2>&1

 # Attach the md device
 DEVICE=`mdconfig -a -t vnode -f ${IMGPATH} -x ${SECTT} -y ${HEADS}`

img.sh の dd は 200MB のファイルを作る。bs は 512 バイトなので、四十万分の一の書き込みでいい。初動時間などを無視するとざっと四十万倍の高速化である。なお clonefs.sh が作るファイルの大きさは、各々によって違うが、同じような大きさのファイルは必要だ。

今回のパッチには入れてないが、dd の前に、rm -rf でファイルを消しておいた方がいい。小さいファイルであったら、大した問題ではないのだが、dd で作る予定よりも大きい時は、問題になる。小さい分には newfs で、どうせ綺麗さっぱり初期化されるので構わないが、大きいと、予定よりも大きいファイルを使って後の処理をすることになるので、これは困る。

さて、次のパッチだが、こちらは余計な dd を消している。


diff -urN freesbie2.org/scripts/img.sh freesbie2/scripts/img.sh
--- freesbie2.org/scripts/img.sh        Wed Nov 16 19:21:42 2005
+++ freesbie2/scripts/img.sh    Thu May  4 02:33:47 2006
@@ -37,7 +37,6 @@

 # Attach the md device
 DEVICE=`mdconfig -a -t vnode -f ${IMGPATH} -x ${SECTT} -y ${HEADS}`
-rm -f ${IMGPATH}

 echo "g c${CYLINDERS} h${HEADS} s${SECTT}" > ${TMPFILE}
 echo "p 1 165 ${SECTT} $((${SECTS} - ${SECTT}))" >> ${TMPFILE}
@@ -58,10 +57,6 @@
 echo "/dev/ufs/${FREESBIE_LABEL} / ufs ro 1 1" > ${TMPDIR}/etc/fstab
 umount ${TMPDIR}
 cd ${LOCALDIR}
-
-echo "Dumping image to ${IMGPATH}..."
-
-dd if=/dev/${DEVICE} of=${IMGPATH} bs=64k >> ${LOGFILE} 2>&1

 mdconfig -d -u ${DEVICE}

${IMGPATH} は既に mdconfig で使われているファイルデバイスである。 なにも、わざわざ消して、/dev/md から dd をやり直す必要はない。

img.sh の中で時間を食うのはマウントされた md-device 上にシステムを移すのと、この /dev/md からファイルへの dd がほとんどだ。経験から適当に言うと、この二つで半々といったところである。この半分を全く無くすのだから、これは md-device を準備する時間としては、二倍の最適化と言ったところか

実は、この二倍速はとても大きいのである。こちらの高速化は主要な処理時間のほとんどを占める。いくら dd の seek が、四十万倍速くなるとは言え、全体の占める割合としては微々たる物だ。それゆえ、dd を削った効果seek の効果よりも著しい。

局所的な部分を大幅に最適化するのも効果はあるが、それよりも大局的な部分を少し速くした方が、全体的な効果がとても大きくなる事も多い。今回のは、その典型的な例であろう。

Patches: dd-seek patch no-dump patch.

前回