Open Source Web Development Tutorials - Dev Shed
mmap()を利用する高度なファイルI/O
(2009/03/18公開)
マッピングに関するアドバイス
Linuxにはmadvise()というシステムコールがあります。これは、マッピングの利用方法に関するアドバイスや手掛かりをカーネルに与えるシステムコールです。この結果、マッピングの使用目的に合わせて、カーネルは動作を最適化します。Linuxのカーネルは動作を動的に調整し、通常、明示的なアドバイスがなくても最適性能を提供しますが、上記のようなアドバイスを与えれば、作業負荷に対する望ましいキャッシングや先読み動作が確保されます。
madvise()のコールは、以下のように、addrから開始しlenバイトにかけて継続するメモリ・マッピング内のページに対する動作方法を、カーネルにアドバイスします。
#include <sys/mman.h>
int madvise (void *addr,
size_t len,
int advice);
lenがゼロの場合、カーネルは与えられたアドバイスをaddrから開始するマッピング全体に適用します。adviceパラメータは、以下のアドバイスのいずれかを指示します。
MADV_NORMAL
このメモリ値域に対して、明確に限定するアドバイスはありません。通常の処理を実行します。
MADV_RANDOM
指示された値域内のページに、順不同で(不連続的に)アクセスします。
MADV_SEQUENTIAL
指示された値域内のページに、低位アドレスから高位アドレスへの順で、連続的にアクセスします。
MADV_WILLNEED
指示された値域内のページに、近い将来アクセスします。
MADV_DONTNEED
指示された値域内のページに、近い将来アクセスする予定はありません。
カーネルは、これらのアドバイスに応えて、実装時固有の実動作修正を行います。すなわち、POSIXはアドバイスの意味を指示するだけで、なんらかの潜在的重要性を指示するわけではありません。現行の2.6バージョン・カーネルは、アドバイスの値に応えて、以下のように動作します。
MADV_NORMAL
カーネルは通常どおりに動作して、中程度の先読みを実行します。
MADV_RANDOM
カーネルは先読みを無効にして、おのおのの物理読み取り作業で最小限のデータ読み取りを実行します。
MADV_SEQUENTIAL
カーネルは積極的な先読みを実行します。
MADV_WILLNEED
カーネルは先読みを起動して、指示されたページをメモリ内へ読み込みます。
MADV_DONTNEED
カーネルは指示されたページに関連するすべてのリソースを解放し、ダーティーかつまだ同期化されていないすべてのページを廃棄します。この後、マッピングされたデータへアクセスすると、バッキング・ファイルからデータがページ化されます。
典型的な使い方は、以下のとおりです。
int ret;
ret = madvise (addr, len, MADV_SEQUENTIAL);
if (ret < 0)
perror ("madvise");
上記のコールでは、カーネルに対して、メモリ領域[addr,addr+len)へ連続的にアクセスする意向を指示しています。
________________________________________
先読み
Linuxカーネルは、ディスクからファイルを読み取るとき、先読みと呼ばれる最適化を実行します。つまり、ファイルの特定のチャンクに対する要求が出されたとき、カーネルは後続のチャンクも読み取るのです。例えば、ファイルを連続的に読み出す場合のように、続けて後続のチャンクに対する要求が出されると、カーネルは直ちに要求されたデータを戻すことができます。ディスクにはトラックバッファがあり(基本的に、ハードディスクは自らの先読みを内的に実行します)、通常、ファイルはディスク上に連続的に配置されているので、この最適化は低コストです。
大抵の場合に若干の先読みはメリットをもたらしますが、どの程度の先読みを実行するかによって、至適結果は異なります。連続的にアクセスするファイルの場合はサイズの大きい先読みウインドーのほうが有用かもしれませんが、順不同にアクセスするファイルの場合、先読みは価値のないオーバーヘッドとなる可能性があります。
第2章「カーネルインターナル」で解説しているように、カーネルは、先読みウインドー内のヒット率に応えて、先読みウインドーの大きさを動的に調整します。ヒットが多ければ、大型のウインドーが有利です。ヒットが少なければ、小型のウインドーが適切です。madvise()システムコールを利用すると、最初から、ウインドーの大きさを調整することができます。
________________________________________
madvise()が成功すると、ゼロが戻ります。失敗すると-1が戻り、適切なerrnoが示されます。有効なエラー値は、以下のとおりです。
EAGAIN
インターナルカーネルのリソース(おそらく、メモリ)が利用できませんでした。再試行できます。
EBADF
領域は存在しますが、ファイルのマッピングは実行しません。
EINVAL
lenパラメータが負数です。あるいは、addrがページ境界にあっていません。あるいは、adviceパラメータが無効です。あるいは、MADV_DONTNEEDによってページがロックまたは共有されました。
EIO
MADV_WILLNEEDによって、内部I/Oエラーが発生しました。
ENOMEM
指定された領域は、このプロセスのアドレス空間内の有効なマッピングではありません。あるいは、MADV_WILLNEEDが指定されましたが、メモリ不足のため、指定された領域内にページ化することができません。
解説は第5回に続きます。
Copyright © 2008 Ziff Davis Enterprise, Inc.
Originally appearing in the U.S. Edition of Dev Shed. All Rights Reserved.








