atime関連マウントオプション使用時のディスク性能比較

要約

ITPro 掲載のチューニング記事に書かれていた、

「mount オプションに noatime オプションを付加すると読み込み速度が倍になる」

という情報について検証を行いましたが、検証方法や考察に誤りがありました。

調査の結果 Fedora8, Fedora9, Ubuntu8.04 LTS ではデフォルトで relatime オプションがついていることがわかりました。

検証方法を read() システムコールの実行時間測定という方法に変更し、あらためてデフォルト、noatime, relatime マウントオプション付加時の性能検証を行ったところ、私の環境(Core 2 Duo(2.2GHz),メモリ2GB,Fedora8)では noatime, relatime マウントオプションを付加することで、デフォルト時の実行時間の半分で read() システムコールを実行することができることがわかりました。

よって、最新の FedoraUbuntu を利用している人は、特に何も設定することなく relatime による実行速度向上の恩恵を受けることができます。

背景

先日、ITPro に Linux のチューニングに関する記事が掲載されていました*1
しかしはてなブックマークのコメント*2を読むと、どうやら記事は相当古いらしいので、記事の中に記載されている noatime マウントオプション付加による性能向上について検証を行ってみました。その結果、noatime や relatime をマウントオプションとして加えても性能差を確認することができませんでした*3
しかし、検証方法に問題があること*4 *5、検証環境であるFedora8ではデフォルトで relatime マウントオプションが付加されていることがわかりました*6
そこで、検証方法を見直し、再度 noatime や relatime マウントオプションの有効性について検証を行うことにしました。

検証方法

今回用意した環境は以下の通りです。

ハードウェア Thinkpad X61
CPU Core 2 Duo T7500(2.20GHz)
メモリ 2048MB
OS Fedora 8(x86)
カーネルバージョン 2.6.24.5-85.fc8

検証パターンは以下の通りです。

パターン番号 省略表記 内容
1 デフォルト ブートオプションで defaults_relatime=0 を追加する。
2 noatime ブートオプションで defaults_relatime=0 を追加し、/bootと、その他全てのパーティション(といっても/のみ)を含む論理ボリュームのマウントオプションを defaults,noatime とする
3 relatime 設定変更なし

検証手順は以下の通りです。

  1. 「$ dd if=/dev/urandom of= bs=64 count=1」により64バイトのファイルを一定数作成する。
  2. 「$ strace -c grep -r linux .」により read() システムコールに費やした時間を測定する。

検証方法の妥当性

前回のような失敗を避けるため、今回は検証方法の妥当性についても説明することにしました。

なぜ read() システムコールの実行時間を測定するか

本当はどのシステムコールが atime を更新しているかを示したかったのですが、今回は省略(いずれ調査するかもしれません)。

以下の簡単なテストコードを元に、read() システムコールが atime の更新を行っていることを証明します。

まずブートオプションで default_relatime=0 を指定した上で、以下のコードをコンパイルして実行します。
(コード提供:id:CliffordBrown)

test_open.c

#include
#include
#include
#include

int main(void){
int fdout;

if ( (fdout = open("./test.txt", O_RDONLY)) == -1){
printf("open error.\n");
}

return 0;
}

test_read.c

#include
#include
#include
#include
#include

int main(void){
int fdout;
char ch;

if ( (fdout = open("./test.txt", O_RDONLY)) == -1){
printf("open error.\n");
}

while (read(fdout, &ch, 1));

return 0;
}


これらのコードをコンパイルし実行した後の stat の結果の抜粋を以下に記載します。

初期状態

Access: 2008-06-14 08:21:37.000000000 +0900
Modify: 2008-06-14 08:14:28.000000000 +0900
Change: 2008-06-14 08:14:28.000000000 +0900

test_open 実行後

Access: 2008-06-14 08:21:37.000000000 +0900
Modify: 2008-06-14 08:14:28.000000000 +0900
Change: 2008-06-14 08:14:28.000000000 +0900

test_read 実行後

Access: 2008-06-14 09:10:08.000000000 +0900
Modify: 2008-06-14 08:14:28.000000000 +0900
Change: 2008-06-14 08:14:28.000000000 +0900

以上の通り、open() システムコールでは atime は更新されず、
read() システムコール発行時に atime が更新されていることがわかりました。

grep と find の read() システムコール呼び出し回数比較

次に、grep と find の read() システムコールの呼び出し回数を比較します。

検証方法で示した手順で作成したファイルを、格納ディレクトリの数とともに変えながら、strace -c で read() システムコールの回数をカウントしてみました。

まず、ディレクトリ数が10のときの結果を示します。

1ディレクトリあたりのファイル数 10 100 1000
find ./ -name linux 7 7 7
grep -r linux . 202 2002 20002

次に、1ディレクトリあたりのファイル数が10のときの結果を示します。

ディレクトリ数 10 100 1000
find ./ -name linux 7 7 7
grep -r linux . 202 2002 20002


以上のように、ファイル数やディレクトリ数が増加しただけでは、find の read() システムコール呼び出し回数は増加しませんでした。

一方grep で呼び出される read() システムコールの数には、以下の関係があることがわかりました。

Nread = 2 + Nfile * 2

Nread: コマンド実行時に呼び出される read() システムコールの数
Nfile: ディレクトリを含むファイルの数

最初の定数2は、libpcre.so.0 及び libc.so.6 の読み込みで必ず read() システムコールが呼び出されることによるものです。
ファイル数の2倍の read() システムコールが呼び出される理由についてですが、strace のログを解析すると、

  • 1回目の read(): ファイルの内容を読み込み
  • 2回目の read(): 空行を読み込み(EOF?)

となっています。

以上により、大量のファイルを対象に grep を実行し、それを strace した結果から read() の実行時間を測定することで atime の更新有無による性能変化の検証を行うことは充分に妥当性があることがわかりました。

検証結果

それでは、10000ファイルに対する grep の strace -c の出力より抜粋した read() システムコールの実行時間の測定結果を以下の示します。

なお、read() システムコールの実行回数は前述の計算式の通り、20002回となっています。


まず、atime関連マウントオプションなし(defaults のみ)の場合です。

回数 read()実行時間(second)
1 0.416270
2 0.037194
3 0.043765
4 0.040803
5 0.035256
6 0.037126
7 0.040141
8 0.036697
9 0.042047
10 0.035817
average(下記参照) 0.038761

1回目の結果が2回目移行に比べて時間がかかっているのは、1回目はディスクからデータをカーネルのバッファにファイルキャッシュとして読み込んでいるのに対し、2回目以降はファイルキャッシュを読み込むだけで済ませているためです。*7 *8

上記の点を考慮し、average として2〜10回目の平均値を算出しています。

次に、default_relatimeがオンになっている(つまり relatime マウントオプションが付加されている)ときの結果を示します。

回数 read()実行時間(second)
1 0.370021
2 0.015250
3 0.024272
4 0.020114
5 0.017416
6 0.014885
7 0.016870
8 0.018520
9 0.016413
10 0.018150
average 0.017988

最後に、noatime マウントオプション付加時の結果を示します。

回数 read()実行時間(second)
1 0.385042
2 0.026043
3 0.015115
4 0.013882
5 0.014829
6 0.014383
7 0.022053
8 0.030323
9 0.024475
10 0.026126
average 0.020803


以上の平均実行時間の結果及びデフォルト時を100としたときの相対実行時間を以下に示します。

defaults relatime noatime
平均実行時間(second) 0.038761 0.017988 0.020803
相対実行時間(%) 100 46.41 53.67

考察

relatime, noatime マウントオプションを付加した場合、デフォルトのときに比べ read() システムコールの実行時間は約半分になっていることがわかりました。
atime を更新しないことによるディスクへの書き込み頻度の大幅低下が性能向上に大きな影響を与えていることは間違いないでしょう。
また、relatime の方が noatime の場合よりも平均実行時間が短いですが、これは測定の結果が毎回不安定であるため、偶然 noatime の平均実行時間が relatime のそれを上回っただけと考えられます。
試行回数を増やせば、おそらく有意な差は見られなくなるでしょう。

結論

以上のように、relatime マウントオプションを付加することにより、マウントオプションがないときよりも xx% 性能が向上していることがわかりました。
noatime マウントオプションもデフォルトに比べて性能は向上していますが、relatime とほぼ性能が変わらないばかりか、いくつかのプログラムに悪影響を与える可能性がありますので*9、今後は relatime を使用するのがいいでしょう。
最新の FedoraUbuntu をご利用の方は、この relatime マウントオプションはカーネルのコンパイルオプションによりデフォルトで付加されているようになっていますので、/etc/fstab の設定等を変更する必要はありません。
もし他のディストリビューションで relatime を正しく設定したいのであれば、まず /boot/config-<カーネルバージョン> の中に CONFIG_DEFAULT_RELATIME の項目があるか、あるとすれば y か n かを確認します。
もしこのオプションが存在し、y と書かれていたら、何も設定しなくてもカーネルが勝手に relatime をつけてマウントしてくれます。
n と書いてある、あるいはオプション自体存在しない場合には /etc/fstab のマウントオプションに defaults,relatime と記述することで relatime を使用することができます。

さらなる真実を求めて

この atime 周りでの検証の余地はまだまだあります。

  • 環境を変える(CPU,メモリ,OS,カーネルバージョン, etc...)
  • 測定方法を変える
    • テスト用ファイルではなく実際に使っているファイルに対し、実際に使っているプログラムで検証を行う
      • 多数のファイルが頻繁に更新されるシステムの場合、relatime マウントオプションがあまり効果を発揮しない可能性があります。
      • read() システムコールやその他の atime を更新するシステムコールを多用しないプログラムの場合はマウントオプション付加による性能向上は期待できないでしょう。
  • 測定回数を増やす

また、机上の研究として以下の課題があります。

  • read() システムコールがどのタイミングで atime を更新するのか? (カーネルのソースを追っかけましたがちょっと見ただけでは全然わかりませんでした……)
  • どんなシステムコールがどんなときに atime を更新するのか?
  • カーネルを含め、どんなプログラムのどんな箇所で atime が参照されるのか?

などなど。
atime 一つとっても、色々わからないことだらけですね。

*1:http://itpro.nikkeibp.co.jp/article/COLUMN/20080528/304432/

*2:http://b.hatena.ne.jp/entry/http%3A//itpro.nikkeibp.co.jp/article/COLUMN/20080528/304432/

*3:http://d.hatena.ne.jp/shiumachi/20080605/1212661605

*4:http://blog.livedoor.jp/dankogai/archives/51063263.html

*5:http://mkosaki.blog46.fc2.com/blog-entry-543.html

*6:http://d.hatena.ne.jp/shiumachi/20080609/1213023569

*7:Linuxカーネル2.6解読室』高橋浩和、小田逸郎、山幡為佐久、ソフトバンククリエイティブ、2006 asin:4797338261

*8:http://mkosaki.blog46.fc2.com/blog-entry-539.html

*9:http://mkosaki.blog46.fc2.com/blog-entry-539.html