ページキャッシュにデータを保存せずに先読みで読み出しI / Oを最適化します。

ページキャッシュにデータを保存せずに先読みで読み出しI / Oを最適化します。

ファイルの内容を再読み込みすることは期待されておらず、ボックスにメモリのプレッシャーがあるため、読み取ったデータをページキャッシュに保存せずにファイルから順次データを読み取ることができる必要があります(貴重なメモリを便利な目的に使用したい)。ディスク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_memalignsetvbuf

// 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の先読みを実行します。スレッドを使用して、より複雑な先読みを実装することもできます。一方のスレッドはバッファを埋め、もう一方のスレッドはバッファ全体から読み込みます。これにより、先読みが完了したときに「太さ」を防ぐことができますが、比較的複雑なマルチスレッドコードがたくさん発生します。

おすすめ記事