ext4のnoauto_da_allocのベンチマーク

# はじめに
[先の記事(ext4のnoauto_da_allocオプションの詳細)](http://qiita.com/rarul/items/40e8bae54efab40d626b)で**noauto_da_alloc**オプションがどう効くかをコードベースで確認したが、これが実際にどれくらいパフォーマンスに響くのかを簡易にテストしてみた。

テスト環境は、Ubuntu 14.04(Linux-3.13くらい)、i7-4790Kくらい、HDDはよくあるSATA接続のもの、RAMはたくさんめです。

# テストスクリプト

```bash:ddtest1.sh
#!/bin/sh

dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
dd if=/dev/zero of=test.dat bs=64k count=1024
```

```bash:ddtest2.sh
#!/bin/sh

dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
dd if=/dev/zero of=test.dat bs=64k count=1024
rm test.dat
```

# テスト結果
## noauto_da_allocなしの時(デフォルト)
```bash
[rarul@tina ~]$ time ./ddtest_pc1.sh 2&>1 > /dev/null
real    0m6.020s
user    0m0.000s
sys     0m0.447s
[rarul@tina ~]$ time ./ddtest_pc1.sh 2&>1 > /dev/null
real    0m5.888s
user    0m0.000s
sys     0m0.376
[rarul@tina ~]$ time ./ddtest_pc2.sh 2&>1 > /dev/null
real    0m0.384s
user    0m0.005s
sys     0m0.379s
[rarul@tina ~]$ time ./ddtest_pc2.sh 2&>1 > /dev/null
real    0m0.319s
user    0m0.007s
sys     0m0.312s
```

## noauto_da_allocありの時(オプション変更)
**noauto_da_alloc**でremountする。

```bash
# mount -o remount,noauto_da_alloc / /
```

でテストを開始、

```bash
# mount -o remount,noauto_da_alloc / /
[rarul@tina ~]$ time ./ddtest_pc1.sh 2&>1 > /dev/null
real    0m0.385s
user    0m0.005s
sys     0m0.379s
[rarul@tina ~]$ time ./ddtest_pc1.sh 2&>1 > /dev/null
real    0m0.305s
user    0m0.004s
sys     0m0.301
```

## ついでにnodelallocもテストする
fstabで**nodelalloc**を足して再起動してテスト、時間置いてからの一発目がなぜか遅いという症状が出るものの、おおむね想定通りの速度。

```bash
[rarul@tina ~]$ time ./ddtest_pc1.sh 2&>1 > /dev/null
real    0m1.199s
user    0m0.000s
sys     0m0.441s
[rarul@tina ~]$ time ./ddtest_pc1.sh 2&>1 > /dev/null
real    0m0.436s
user    0m0.000s
sys     0m0.436s
[rarul@tina ~]$ time ./ddtest_pc2.sh 2&>1 > /dev/null
real    0m0.473s
user    0m0.004s
sys     0m0.442s
[rarul@tina ~]$ time ./ddtest_pc2.sh 2&>1 > /dev/null
real    0m0.443s
user    0m0.003s
sys     0m0.440s
```

ただ、remountではなぜか**nodelalloc**がうまく効いていないようなベンチマーク結果だった。/proc/mounts的には**nodelalloc**になってたんだけどなぁ。ext4のコードを再確認して見るもそれらしきは見あたらずに原因はよくわからない。vopsまで含めてinodeがキャッシュされていたということにしておこう...

```bash
# mount -t ext4 -o remount,nodelalloc / /
```

# テスト結果の解説
ext4はデフォルトでは、
- renameで上書きが発生するタイミング
- truncateでサイズ0にした場合のcloseのタイミング
の2つの場合に、**filemap_flush()**を呼ぶことでIOをスタートさせようとする。通常はバッファキャッシュでIOが遅延され、場合によってはIOがスタートする目に消された結果何もしないのが、**filemap_flush()**が呼ばれることで必ずIOがこのタイミングでスタートしてしまう。**noauto_da_alloc**をつけるとこの挙動を行わなくなるのでこの特定ケースでパフォーマンスが向上する。

前者はともかく、後者はユーザランドレベルではもっと具体的に下記の場合になるかと思う。

- ファイルが存在する場合に[**open(2)**](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/open.2.html)を**O_TRUNC**で呼ぶ
- [**truncate(2)**](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/truncate.2.html)でファイルサイズをゼロにする

「ファイルを消して作り直すくらいなら**O_TRUNC**でファイルサイズをゼロにしてしまう」なんていうのはプログラムによってはやってそうな処理ではある。[**SQLite**を**journal_mode=truncate**で](https://www.sqlite.org/pragma.html)使っているとか。

# 終わりに
先にソースコードを読んだ上での恣意的なテストだったというわけで、なんという出来レース...