简体   繁体   English

强制 JVM 在没有页面缓存的情况下执行所有 IO(例如 O_DIRECT)

[英]Force JVM to do all IO without page cache (e.g. O_DIRECT)

I'm doing some benchmarks of an application written in Java.我正在对用 Java 编写的应用程序进行一些基准测试。 It is very important for the experiments that the results are not influenced by the page cache (I'm using linux)实验很重要,结果不受页面缓存的影响(我用的是linux)

So the best way to avoid the page cache is using O_DIRECT whenever a file is opened.因此,避免页面缓存的最佳方法是在打开文件时使用 O_DIRECT。 I therefore changed the respective code in the sourcecode of the jre.因此,我更改了 jre 源代码中的相应代码。

My approach works perfectly for everything that goes through the FileOutputStream (eg writing), but it does not work for FileInputStream (eg reading).我的方法非常适用于通过FileOutputStream的所有内容(例如写入),但不适用于FileInputStream (例如读取)。

When adding O_DIRECT to the open-call of FileInputStream , the JVM is unable to load any classes:将 O_DIRECT 添加到FileInputStream的 open-call 时,JVM 无法加载任何类:

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

This error is not a classpath issue, since I can fix it just by using a "unhacked" JVM.这个错误不是类路径问题,因为我可以通过使用“未破解的”JVM 来修复它。

So there seems to be an issue with opening files.所以打开文件似乎有问题。

I'm very happy about any advice on how to fix the issue.对于有关如何解决此问题的任何建议,我感到非常高兴。

If anyone ever wants to do something similar, I've documented the whole hack in my blog .如果有人想做类似的事情,我已经在我的博客中记录了整个 hack


As a reference, these are the changes on the JVM code I did so:作为参考,这些是我对 JVM 代码所做的更改:

jdk/src/share/native/java/io/FileInputStream.c : 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
 }

This change works: jdk/src/solaris/native/java/io/FileOutputStream_md.c :此更改有效: 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));
 }

I also changed the hotspot jre to ensure that the memory is aligned (thats a requirement for O_DIRECT) hotspot/src/share/vm/runtime/os.cpp :我还更改了热点 jre 以确保 memory 对齐(这是 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);

Old post, but I recently wrote a small library called Jaydio hoping to solve this exact problem. 老帖子,但我最近写了一个名为Jaydio的小型库,希望能解决这个问题。 Maybe you will find it useful. 也许你会发现它很有用。

  "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 [*]." 

[*] In other words, it's an Oracleism. [*]换句话说,它是一个Oracleism。

-- Linus Torvalds from Transmeta, 11 May 2002 - 来自Transmeta的Linus Torvalds,2002年5月11日

Check NOTES section of the man 2 open : 检查man 2 open NOTES部分:

O_DIRECT O_DIRECT

The O_DIRECT flag may impose alignment restrictions on the length and address of userspace buffers and the file offset of I/Os. O_DIRECT标志可能会对用户空间缓冲区的长度和地址以及I / O的文件偏移量施加对齐限制 In Linux alignment restrictions vary by file system and kernel version .... 在Linux中,对齐限制因文件系统和内核版本而异....

Under Linux 2.4, transfer sizes, and the alignment of the user buffer and the file offset must all be multiples of the logical block size of the file system. 在Linux 2.4下,传输大小,用户缓冲区和文件偏移的对齐必须都是文件系统逻辑块大小的倍数。 Under Linux 2.6, alignment to 512-byte boundaries suffices. 在Linux 2.6下,对齐到512字节边界就足够了。 .... ....

In summary, O_DIRECT is a potentially powerful tool that should be used with caution. 总之,O_DIRECT是一个潜在的强大工具,应谨慎使用。 It is recommended that applications treat use of O_DIRECT as a performance option which is disabled by default. 建议应用程序将O_DIRECT用作性能选项,默认情况下禁用该选项。

I think, there are some usages of FileInputStream in the JRE (classloader) which has reads with offsets or sizes not aligned to 512 bytes. 我认为,在JRE(类加载器)中有一些FileInputStream用法,其读取的偏移量或大小未对齐到512字节。 (For Advanced Format the minimal alignment may be bigger, even 4096 bytes, or one 4K page.) (对于高级格式 ,最小对齐可能更大,甚至4096字节,或一个4K页面。)

The behaviour of kernel for unaligned offsets is the grey zone, some info is here: RFC: Clarifying Direct I/O Semantics, Theodore Ts'o, tytso@mit, LWN, 2009 内核对于未对齐偏移的行为是灰色区域,一些信息在这里: RFC:澄清直接I / O语义,Theodore Ts'o,tytso @ mit,LWN,2009

Other interesting discussion is here: Linux: Accessing Files With O_DIRECT (kerneltrap, 2007) 其他有趣的讨论在这里: Linux:使用O_DIRECT访问文件 (kerneltrap,2007)

Hmm, seems like there should be fallback to buffered I/O when something with DIRECT fails. 嗯,当DIRECT出现故障时,似乎应该回退到缓冲的I / O. All IO operations with DIRECT are synchronous. 使用DIRECT的所有IO操作都是同步的。 May be some DMA effects? 可能是一些DMA效应? Or combination of O_DIRECT and mmap ? 或者O_DIRECTmmap组合?

UPDATE: 更新:

Thanks for strace output. 感谢strace输出。 Here is the error ( grep O_DIRECT , then check file descriptor operations): 这是错误( 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)

Unaligned read size results in EINVAL error. 未对齐的读取大小会导致EINVAL错误。 Your classfile is 2340 bytes long, it is 1024+1316 bytes, which is not aligned. 您的类文件长度为2340字节,它是1024 + 1316字节,未对齐。

You can use O_DIRECT under Java, leveraging the Java Native Access (JNA) . 您可以在Java下使用O_DIRECT,利用Java Native Access(JNA) Implementations for InputStream and OutputStream, with O_DIRECT enabled, are provided here . 此处提供启用O_DIRECT的InputStream和OutputStream的实现。

Just to update, since this post is the first one that shows up if you google O_DIRECT JVM :只是为了更新,因为如果你谷歌O_DIRECT JVM ,这篇文章是第一个出现的:

The ability to do Direct I/O with O_DIRECT was merged into JDK into 2017:使用O_DIRECT进行 Direct I/O 的能力在 2017 年被合并到 JDK 中:

When creating a FileChannel, you can pass ExtendedOpenOption.DIRECT :创建 FileChannel 时,您可以传递ExtendedOpenOption.DIRECT

import com.sun.nio.file.ExtendedOpenOption;

import java.nio.channels.FileChannel;
import java.nio.file.StandardOpenOption;

FileChannel fc = FileChannel.open(f.toPath(), StandardOpenOption.WRITE, 
                                  ExtendedOpenOption.DIRECT);

In 2022, consider also using alongside the new Foreign Memory API with MemorySegment for the backing buffer.在 2022 年,还可以考虑将新的 Foreign Memory API 与MemorySegment用于后备缓冲区。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 没有括号的泛型静态方法,例如在JavaFX 8中 - Generic static methods without brackets, e.g. in JavaFX 8 没有 npm 的 video.js 插件(例如 eme) - video.js plugins (e.g., eme) without npm 在单例 bean 中将共享数据结构(例如缓存)实现为 concurrentHashMap - Implementing shared data structure (e.g. cache) as a concurrentHashMap in a singleton bean Linux中的本机内存使用似乎比通过JVM本身(例如,通过JConsole)观察到的要高得多 - Native memory usage in Linux seems to be much higher than observed through JVM itself (e.g. through JConsole) 如何以Java方式直接从设备读取/写入文件(如O_DIRECT标志的效果)? - How to directly read/write file from and to device (like effect of O_DIRECT flag) in Java way? 如何在没有任何动画(例如淡入淡出)的情况​​下显示/隐藏软键盘? - How to show/hide the soft keyboard without any animation (e.g. fade) in Java? Java优化的读/写共享资源/内存位置,无需Atomic API,例如AtomicInteger - Java optimized read/write a shared resource/memory location without Atomic API e.g. AtomicInteger 是什么的J字头和没有如-J-XMS和-Xmx通过java选项之间的区别? - What is the difference between java option passed with J prefix and without e.g. -J-Xms and -Xmx? Intellij IDEA:如何查看 class(例如 Color.html)的 javadoc 的 *整个页面*? - Intellij IDEA: How to view *entire page* of javadoc for a class (e.g. Color.html)? 在FreeMarker中,如何自动将自定义对象(例如java.awt.Color)转换为特定的String值(例如HTML十六进制颜色)? - In FreeMarker, how do I automatically convert a custom object (e.g. java.awt.Color) to a particular String value (e.g. HTML hex color)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM