ファイルの内容を再読み込みすることは期待されておらず、ボックスにメモリのプレッシャーがあるため、読み取ったデータをページキャッシュに保存せずにファイルから順次データを読み取ることができる必要があります(貴重なメモリを便利な目的に使用したい)。ディスクI / Oキャッシュ)。
私の質問は、これらの読み取りを最適化する方法です。読み込んでいるデータがディスクに順次(断片化を除く)配置されることがわかっているので、あらかじめ読み取ることができるようにしたいのですが(/sys/block/sda/queue/read_ahead_kbを増やして)これが可能かどうかはわかりません。読み取るデータがページキャッシュに格納されるのを防ぐには、posix_fadvise(POSIX_FADV_DONTNEEDフラグを含む)を使用する必要があるという利点があります。
先読みデータは、単にページキャッシュからデータを削除するように求められます。
答え1
使用直接IO:
ダイレクトI / Oは、オペレーティングシステムの読み取りおよび書き込みキャッシュをバイパスしてアプリケーションからストレージデバイスに直接ファイルを読み書きするファイルシステムの機能です。直接I / Oは、独自のキャッシュ(データベースなど)を管理するアプリケーションでのみ使用されます。
アプリケーションはこのフラグを持つファイルを開き、直接I / Oを呼び出します
O_DIRECT
。
たとえば、
int fd = open( filename, O_RDONLY | O_DIRECT );
Linuxの直接IOは奇妙で、いくつかの制限があります。アプリケーションの IO バッファーはページ・ソートする必要があり、一部のファイル・システムでは、各 IO 要求はページ・サイズの正確な倍数でなければなりません。この最後の制限により、ファイルの最後の部分を読み書きするのが難しい場合があります。
アプリケーションで先読みを処理するための簡単なコーディング方法は、fdopen
大規模ページソートバッファを使用して設定することによって実行できますposix_memalign
。setvbuf
// should really get page size using sysconf()
// but beware of systems with multiple page sizes
#define ALIGNMENT ( 4UL * 1024UL )
#define BUFSIZE ( 1024UL * 1024UL )
char *buffer;
...
int fd = open( filename, O_RDONLY | O_DIRECT );
FILE *file = fdopen( fd, "rb" );
int rc = posix_memalign( &buffer, ALIGNMENT, BUFSIZE );
rc = setvbuf( file, buffer, _IOFBF, BUFSIZE );
mmap()
これを使用して、バッファに使用する匿名メモリを取得することもできます。これの利点は自然なページソートです。
...
char *buffer = mmap( NULL, BUFSIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0 );
rc = setvbuf( file, buffer, _IOFBF, BUFSIZE );
次に、ストリームから読みたいタイプにfread()
/fgets()
または読み取り機能を使用します。FILE *
file
strace
たとえば、実際のシステムコールがページソートバッファとページサイズバッファで実行されているかどうかを確認するには、ツールを使用する必要があります。ストリーム処理に基づく一部のCライブラリ実装では、IOバッファリングにのみ指定されたバッファをread
使用しないため、ソートバリアントパターンやサイズが発生する可能性があります。 Linux / glibcではこれを実行しないようですが、確認せずにサイズやソートを解除すると、IO呼び出しは失敗します。FILE *
setvbuf
繰り返しますが、LinuxダイレクトIOは奇妙なことがあります。特定のファイルシステムのみが直接IOをサポートし、その一部は他のファイルシステムよりも専門的です。 テスト使用することを決定した場合は、徹底的に使用してください。
公開されたコードは、ストリームのバッファを埋める必要があるたびに1MBの先読みを実行します。スレッドを使用して、より複雑な先読みを実装することもできます。一方のスレッドはバッファを埋め、もう一方のスレッドはバッファ全体から読み込みます。これにより、先読みが完了したときに「太さ」を防ぐことができますが、比較的複雑なマルチスレッドコードがたくさん発生します。
答え2
この質問は非常によく答えられましたこのStackOverflowの質問から。
古いファイルオフセットトレース
read()
その後、データ範囲を
read()
呼び出します[...]fadvise(POSIX_FADV_DONTNEED)
最良の結果を得るには、ページ整列ブロックのデータを読み取る必要があります。 I / Oキャッシュはページベースであり、
fadvise()
指定されたデータ範囲をページリストにマップします。ソートが間違っていると、追加read()
sが発生し、パフォーマンスが低下しますが、それ以外は無害です。
勉強したくない最初メモリを最適化する場合。あなたはただ読みたいです。読み取るとディスクは順番に動作するため、データをストリーミングするように指示する必要はありません。