FreeBSD Daily Topics

2008年10月31日≪注目≫cp(1)やcat(1)のバッファサイズを64KBから1MBへ変更で強制的コンテキストスイッチ回数の削減を実現 - MAXPHYSの増加でシステム全体の効率改善も可能か

heads-up

more buffer makes cp/cat less involuntary context switches

current - Ivan Voras氏がcp(1) and cat(1) in the Age of the Fruitbatにおいて、バッファサイズを増加させることでcp(1)コマンドやcat(1)コマンドの稼働効率を向上させる事例を紹介しています。同氏はFreeBSDがもともとメモリが高価だった時代から存在し、試行錯誤的にその時のハードウェア状況に適切なコードへ変わってきているものの、ここ数年で進んだマルチコア化とメモリの大容量化は急激なもので対応しきれていないことを匂わせてから、単純にバッファサイズを増やすことで稼働効率を改善できるのではないかと説明しています。

ためしに同氏はcp(1)とcat(1)のバッファサイズを主記憶メモリが128Mバイト未満であれば128Kバイトに、それ以上であれば1Mバイトに設定して/usr/bin/timeで動作を比較した例を掲載しています。実行速度に関して注目すべき向上は計測できないものの、強制的に実施されるコンテキストスイッチが11194から272に減るという結果が得られています。

(ちなみにcp(1)コマンドは以前、ファイルサイズが8Mバイト未満である場合にはread/writeシステムコールを使った処理ではなくmmap/writeを使った処理を実施するようにショートカット処理が追加されました。これで8Mバイト未満のコピー処理が高速化されています)

マルチコア化とメモリの大容量化、とくにi386ではなくamd64をメインのアーキテクチャとしていくのにともなって、システム全体にわたるバッファやキャッシュサイズの上昇がシステム性能の向上にストレートに効いてくることになりそうです。

こうしたIvan Voras氏の改善の取り組みはGeorge V. Neville-Neil氏の承認を得てFreeBSD 8-CURRENTへマージされました。今回追加された変更では、主記憶メモリの容量が十分あるかどうかはphysmem pageの値が32Kバイト(これはページが4Kバイトの場合の主記憶メモリ128Mバイトに相当)以下である場合には少なく、それ以上である場合には十分にメモリがあると設定されています。メモリが十分ある場合にはバッファサイズとして最大入出力ブロックサイズMAXPHYSの8倍の値か2Mバイトかどちらか小さいほうが、そうでない場合にはMAXPHYSの値がバッファサイズとして使われます。MAXPHYSは128Kバイトに設定されています。

結果から言えば、従来は64Kバイトをバッファサイズとして使っていたcp(1)コマンドやcat(1)コマンドが、主記憶メモリが128Mバイトを越えている場合には1Mバイトに、128Mバイト以下であれば128Kバイトをバッファサイズとして活用するようになりました。cat(1)コマンドは対象がファイルではない場合には1Kバイトをバッファに割り当てていたため、そのケースでは1Kバイトから1Mバイトへ一気にバッファが増えたことになります。

実際にどの程度の効果があるのか試してみました。次のようにコピー用に1Gバイトのテストファイルを作成し、cp(1) and cat(1) in the Age of the FruitbatでIvan Voras氏が説明しているようにコピーの動作時間とコンテキストスイッチの情報を出力させます。

チェック用に1GBのファイルを作成する - dd(1)コマンドを使用
% dd if=/dev/random of=data-file bs=1024 count=1048576
1048576+0 records in
1048576+0 records out
1073741824 bytes transferred in 30.556598 secs (35139443 bytes/sec)
% ls -lh
total 1049104
-rw-r--r--  1 daichi  wheel   1.0G 10 31 09:57 data-file
%

たとえば改善が加わる前のcat(1)コマンドだと次のような出力が得られます。

1GBのファイルをcat(1)コマンドでコピーしたところ
% /usr/bin/time -lph cat data-file > target
real 50.38
user 0.25
sys 6.34
      1300  maximum resident set size
         7  average shared memory size
      1730  average unshared data size
       126  average unshared stack size
       232  page reclaims
         0  page faults
         0  swaps
      8247  block input operations
      8194  block output operations
         0  messages sent
         0  messages received
         0  signals received
      8414  voluntary context switches
     11071  involuntary context switches
%

出力は冗長なので省きますが、バッファ拡大以前と以後の動作を動作時間とコンテキストスイッチの回数に注目してまとめると次のようになります。

 バッファサイズ拡大による動作の違い cat(1)コマンド
バッファサイズ64KB(変更以前)1MB(変更後)変化率
転送時間[秒]50.3847.156.41%減
コンテキストスイッチ回数(自発)841483730.49%減
コンテキストスイッチ回数(強制)11071414262.59%減
 バッファサイズ拡大による動作の違い cp(1)コマンド
バッファサイズ64KB(変更以前)1MB(変更後)変化率
転送時間[秒]48.5647.751.67%減
コンテキストスイッチ回数(自発)841983630.67%減
コンテキストスイッチ回数(強制)7934485638.79減

コピー時間にはほとんど差はありません。若干早くなる程度ですが、ファイルサイズが小さい場合にはほとんど気にならない差でしょう。たしかに自発的なコンテキストスイッチの回数にはほとんど変更が見られないものの、強制的なコンテキストスイッチがかなり減っていることが確認できます。

ブロックサイズの違いでどの程度違いが現れるか調べてみたかったので、単純にdd(1)コマンドのブロックサイズ指定を変更して同様に計測してみました。⁠/usr/bin/time -lph dd if=data-file of=target bs=1024」のようにしてbs=の値だけ変更しています。まとめると次のようになります。

 バッファサイズ拡大による動作の違い dd(1)コマンド
バッファサイズ1KB64KB1MB2MB100MB
転送時間[秒]51.9650.1051.1845.7345.14
コンテキストスイッチ回数(自発)83668378833380669809
コンテキストスイッチ回数(強制)108827387460643503122

自発的におこるコンテキストスイッチの回数はあまり変わらないものの、強制的におこるコンテキストスイッチの回数が減っていることがわかります。その変化から見ても1Kバイトや64Kバイトから、1Mバイト、2Mバイトへのバッファ拡大というのは妥当な選択のようです。それ以上に上げても今のところあまり効果が見られません。ドライバとカーネルで使っている最大の入出力ブロックサイズが128KBに固定されているためでしょう。

現在128Kバイトに固定されているドライバ/カーネルで使用される最大入出力ブロックサイズMAXPHYSの値を256Kバイトやそれ以上に変更することでシステム全体の稼働効率向上を実現できる可能性があります。cp(1) and cat(1) in the Age of the Fruitbatによれば、すでにこの作業を実施している開発者がいるようで、近いうちに8-CURRENTに導入されるのではないかとみられます。この変更はシステム全体の稼働効率を向上させる可能性を持っており、FreeBSD 8の効率向上に寄与することになると見られます。今後の関連改善に注目です。

ports

xfce4
xfce4関連のport(x11-wm/xfce4他多数)がXFce 4.4.3へアップグレードされました。
graphics/gnash-devel
FlashプレーヤGnash開発版のportが20081030スナップショットへアップグレードされました。
www/linux-opera
Linux Operaのportが9.62へアップグレードされました。

おすすめ記事

記事・ニュース一覧