12

私はJavaで書かれたアプリケーションのいくつかのベンチマークを行っています。結果がページキャッシュの影響を受けないことが実験にとって非常に重要です(私はLinuxを使用しています)

したがって、ページキャッシュを回避する最善の方法は、ファイルが開かれるたびにO_DIRECTを使用することです。そのため、jreのソースコードのそれぞれのコードを変更しました。

私のアプローチは、(たとえば書き込み)を通過するすべてのものに対して完全に機能しますが、 (たとえば読み取り)FileOutputStreamに対しては機能しません。FileInputStream

のopen-callにO_DIRECTを追加するとFileInputStream、JVMはクラスをロードできません。

Error: Could not find or load main class perf.TestDirectIO

「ハッキングされていない」JVMを使用するだけで修正できるため、このエラーはクラスパスの問題ではありません。

したがって、ファイルを開く際に問題があるようです。

問題を解決する方法についてのアドバイスをとてもうれしく思います。

誰かが似たようなことをしたい場合は、ハック全体をブログに記録しました。


参考までに、これらは私が行ったJVMコードの変更です。

jdk/src/share/native/java/io/FileInputStream.c

 @@ -58,7 +60,8 @@
 JNIEXPORT void JNICALL
 Java_java_io_FileInputStream_open(JNIEnv *env, jobject this, jstring path) {
-    fileOpen(env, this, path, fis_fd, O_RDONLY);
+    fileOpen(env, this, path, fis_fd, O_RDONLY | O_DIRECT); // this is the change that causes all the problems
 }

この変更は機能します jdk/src/solaris/native/java/io/FileOutputStream_md.c::

@@ -55,8 +55,10 @@
 JNIEXPORT void JNICALL
 Java_java_io_FileOutputStream_open(JNIEnv *env, jobject this,
                                    jstring path, jboolean append) {
     fileOpen(env, this, path, fos_fd,
-             O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC));
+             O_WRONLY | O_DIRECT | O_CREAT | (append ? O_APPEND : O_TRUNC));
 }

また、ホットスポットjreを変更して、メモリが調整されていることを確認しました(これは、O_DIRECTの要件です) hotspot/src/share/vm/runtime/os.cpp

+# include <mm_malloc.h>
...
-  u_char* ptr = (u_char*)::malloc(size + space_before + space_after);
+  u_char* ptr = (u_char*)::_mm_malloc(size + space_before + space_after,512);
4

3 に答える 3

17

古い投稿ですが、私は最近、この正確な問題を解決することを望んで、Jaydioという小さなライブラリを作成しました。多分あなたはそれが役に立つと思うでしょう。

于 2014-03-13T21:36:18.943 に答える
10
  "The thing that has always disturbed me about O_DIRECT is that the
   whole interface is just stupid, and was probably designed by a deranged
   monkey on some serious mind-controlling substances  [*]."

[*]言い換えれば、それはオラクル主義です。

--TransmetaのLinusTorvalds、2002年5月11日

man 2 open:のNOTESセクションを確認してください。

O_DIRECT

O_DIRECTフラグは 、ユーザースペースバッファーの長さとアドレス、およびI/Oのファイルオフセットに配置制限を課す場合があります。Linuxでは、アライメントの制限はファイルシステムとカーネルのバージョンによって異なります...。

Linux 2.4では、転送サイズ、およびユーザーバッファーとファイルオフセットの配置はすべて、ファイルシステムの論理ブロックサイズの倍数である必要があります。Linux 2.6では、512バイト境界へのアラインメントで十分です。...。

要約すると、O_DIRECTは潜在的に強力なツールであり、注意して使用する必要があります。アプリケーションでは、O_DIRECTの使用を、デフォルトで無効になっているパフォーマンスオプションとして扱うことをお勧めします。

JRE(クラスローダー)には、512バイトにアラインされていないオフセットまたはサイズの読み取りがあるFileInputStreamの使用法がいくつかあると思います。(Advanced Formatの場合、最小の配置は4096バイト、または1つの4Kページでさえ大きくなる可能性があります。)

整列されていないオフセットに対するカーネルの動作はグレーゾーンです。いくつかの情報はここにあります:RFC:Clarifying Direct I / O Semantics、Theodore Ts'o、tytso @ mit、LWN、2009

その他の興味深い議論はここにあります:Linux:O_DIRECTを使用したファイルへのアクセス(kerneltrap、2007)

うーん、DIRECTで何かが失敗した場合、バッファリングされたI/Oへのフォールバックがあるはずのようです。DIRECTを使用したすべてのIO操作は同期しています。DMA効果の可能性はありますか?またはとのO_DIRECT組み合わせmmap

アップデート:

strace出力をありがとう。エラーは次のとおりです(grep O_DIRECT、ファイル記述子の操作を確認してください)。

28290 open("...pact/perf/TestDirectIO.class", O_RDONLY|O_DIRECT) = 11
28290 fstat(11, {st_mode=S_IFREG|0644, st_size=2340, ...}) = 0
28290 fcntl(11, F_GETFD)                = 0
28290 fcntl(11, F_SETFD, FD_CLOEXEC)    = 0
...skip
28290 stat("...pact/perf/TestDirectIO.class", {st_mode=S_IFREG|0644, st_size=2340, ...}) = 0
...skip
28290 read(11, "\312\376\272\276\0\0\0003\0\215\n\0-\0D\t\0E\0F\7\0G\n\0\3\0D\10\0H\n"..., 1024) = 1024
28290 read(11, 0x7f1d76d23a00, 1316)    = -1 EINVAL (Invalid argument)

読み取りサイズがずれていると、EINVALエラーが発生します。クラスファイルの長さは2340バイトで、1024 + 1316バイトであり、整列されていません。

于 2013-03-05T16:17:09.357 に答える
5

Java Native Access(JNA)を利用して、JavaでO_DIRECTを使用できます。ここでは、O_DIRECTが有効になっているInputStreamおよびOutputStreamの実装を提供します

于 2014-04-07T14:15:15.093 に答える