Java+JNI 与 Pure C++ 相反

发布于 2024-12-10 10:00:38 字数 1489 浏览 0 评论 0原文

我相应地进行了 DLL-Java 通信这篇文章。我的编译配置你可以在那里看到:

    g++ -IC:\Users\RZ\Downloads\eigen-eigen-3.0.3\eigen-eigen-3.0.3 -IC:\Program Files\Java\jdk1.7.0\include\win32 -IC:\Program Files\Java\jdk1.7.0\include -O3 -msse -msse2 -mmmx -Wall -shared -c -o Vector3DImp.o ..\Vector3DImp.cpp
..\Vector3DImp.cpp:5:0: warning: "JNICALL" redefined
C:\Program Files\Java\jdk1.7.0\include\win32/jni_md.h:31:0: note: this is the location of the previous definition
g++ -Wl,--kill-at -shared -LC:\Program Files\Java\jdk1.7.0\lib -o Eigen.dll Vector3DImp.o

然后我在 Java 上写了同样的配置。并使用向量乘法和向量加法启动一些测试:结果是:

Pure java 39 -38 ms

JNI Java 52 -50ms

然后我使用 DLL 中的相同代码在 C++ 上编写相同的测试。 结果:

22 – 18 毫秒

是的,测试策略看起来很粗糙,但共同的结果是可持续的。 是我的错还是 JNI 的缺点(我不擅长)。

注意:

主要问题是:Java中的DLL使用真的这么难吗(性能降低了2.5倍)。为什么会这样?

更新:

根据要求,有测试源。 抱歉,那里乱七八糟,这是为了我自己的需要而在短时间内制作的。

我的系统配置: Windows 7 x32、酷睿 2 双核。

Java 和 C++ 项目都是在 Eclipse IDE 中使用 MingW C++ 编译器构建的。对于 C++ 向量计算,使用了 Eigen 库。另外,我尝试了JBlas库,在Java测试结束时它很糟糕,我不知道为什么。即使进行 3 次乘法运算(与叉积中的 6 次乘法相反),结果也是令人毛骨悚然。看看你自己。

I make a DLL-Java communication correspondingly this post. My compilation configuration you can see there:

    g++ -IC:\Users\RZ\Downloads\eigen-eigen-3.0.3\eigen-eigen-3.0.3 -IC:\Program Files\Java\jdk1.7.0\include\win32 -IC:\Program Files\Java\jdk1.7.0\include -O3 -msse -msse2 -mmmx -Wall -shared -c -o Vector3DImp.o ..\Vector3DImp.cpp
..\Vector3DImp.cpp:5:0: warning: "JNICALL" redefined
C:\Program Files\Java\jdk1.7.0\include\win32/jni_md.h:31:0: note: this is the location of the previous definition
g++ -Wl,--kill-at -shared -LC:\Program Files\Java\jdk1.7.0\lib -o Eigen.dll Vector3DImp.o

And then I write the same on Java. And launch a few tests with vector multiplication and vector addition: the result is:

Pure java 39 -38 ms

JNI Java 52 -50ms

Then I code the same test on C++ using the same code in DLL.
Result:

22 – 18 ms

Yeah the test strategy make seem rough, but the common result is sustainable.
Is there my fault or it is JNI drawback (I'm not good at it).

Note:

The main question is: Is it real the DLL use in Java is so hard (the performance reduces by 2.5 times). Why it is?

UPDATE:

At the request, there is source of test.
Sorry for mess there, it was made for my own need in short time.

My system configuration:
Windows 7 x32, Core 2 Duo.

Both Java and C++ projects were built in Eclipse IDEs with MingW Compiler for C++. For C++ vector calculation Eigen library was used. Also, I tried JBlas library, in the end of Java test it was awful, I don't know why. Even with 3 multiplication operation (opposite 6 multiplication in cross product) the result was creepy. Look yourself.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

初吻给了烟 2024-12-17 10:00:39

在查看了您发布的代码之后,我认为您可以做很多事情来加快速度。正如其他人所说,根本问题是,遍历 Java <-> 会产生很大的开销。 JNI 边界,以及 JNI 端为向量乘法所做的工作量不足以摊销此成本。

我确实注意到使用原始数组,如下所示:

List<Vector3DJava> vector3dJavas = new ArrayList<Vector3DJava>();
// Populate list with 1,000,000 random elements
Vector3DJava[] v3dj = vector3dJavas.toArray(new Vector3DJava[vector3dJavas.size()]);
long time = System.nanoTime();
for (int i = 0; i < L; i++) {
    v3dj[i].getMultiplication(v3dj[i+1]);
}
System.out.println((System.nanoTime() - time) / 1000000L);

花费大约一半的时间:

List<Vector3DJava> vector3dJavas = new ArrayList<Vector3DJava>();
// Populate list with 1,000,000 random elements
long time = System.nanoTime();
for (int i = 0; i < L; i++) {
    vector3dJavas.get(i).getMultiplication(vector3dJavas.get(i+1));
}
System.out.println((System.nanoTime() - time) / 1000000L);

至少在我的机器上。

After having a look at the code you posted, I don't think there is a huge amount you can do to speed this up. The fundamental problem is, as others have said, there is a significant overhead in traversing the Java <-> JNI boundary, and the amount of work being done on the JNI side for a vector multiplication is not enough to amortise this cost.

I did notice that using raw arrays, like this:

List<Vector3DJava> vector3dJavas = new ArrayList<Vector3DJava>();
// Populate list with 1,000,000 random elements
Vector3DJava[] v3dj = vector3dJavas.toArray(new Vector3DJava[vector3dJavas.size()]);
long time = System.nanoTime();
for (int i = 0; i < L; i++) {
    v3dj[i].getMultiplication(v3dj[i+1]);
}
System.out.println((System.nanoTime() - time) / 1000000L);

takes about half the time of this:

List<Vector3DJava> vector3dJavas = new ArrayList<Vector3DJava>();
// Populate list with 1,000,000 random elements
long time = System.nanoTime();
for (int i = 0; i < L; i++) {
    vector3dJavas.get(i).getMultiplication(vector3dJavas.get(i+1));
}
System.out.println((System.nanoTime() - time) / 1000000L);

At least on my machine.

初懵 2024-12-17 10:00:38

JNI 是软件堆栈中的另一层。除非迫不得已,否则不知道为什么要使用它。通常,JNI 用于访问其他非 Java 代码库(已经存在的 DLL,它们为您做一些复杂的事情 - 比如说,如果您希望您的软件在 Windows 上使用 DirectX - 您可以使用 JNI 包装它)。

我想我想说的是,我对存在一些性能开销并不感到非常惊讶,而且我不认为这真的是你的错。每当您必须进行所谓的“系统”调用(即调用 JVM 外部的系统资源(或 DLL、或某些 I/O 等))时,性能都会受到影响。

JNI is another layer in your software stack. Not sure why you would want to use it unless you had to. Typically JNI is used to access other non-Java code libraries (DLLs that already exist, that do some complicated thing for you - say if you wanted your software to use DirectX on Windows - you could wrap it using JNI).

I guess what I'm saying is, I'm not terribly surprised that there's some performance overhead, and I don't think it's your fault really. There are performance hits anytime you have to make what are referred to as "system" calls, that is, calls to system resources (or DLLs, or some I/O, etc.) outside of the JVM.

场罚期间 2024-12-17 10:00:38

有几个因素会对 JNI

  1. DLL 和 JVM 之间的数据转换速度产生负面影响。您的本机 DLL 是小端字节序,而 JVM 是大端字节序,因此始终会执行转换。抱歉,这里没有任何需要改进的地方。

  2. 传递 JNIEnv 相当耗时

JNA 或 CNI 等 JNI 的替代方案,但不要指望有巨大的改进,因为传递数据的基本问题仍然存在。这里的主要优化是减少对本机库的调用次数或以对两个世界都友好的格式打包参数。

There are several factors that negatively impact the speed with JNI

  1. Data conversion between DLL and JVM. Your native DLL is little endian while JVM is a big endian so conversions are always performed. Sorry bu here is nothing left for improvement.

  2. The passing of JNIEnv is quite time consuming

There are alternatives to JNI as JNA or CNI but do not expect massive improvements as the basic problem of passing data still remains. The major optimization here is to reduce either the number the calls to the native library or to pack parameters in a format that is friendly to both worlds.

倾`听者〃 2024-12-17 10:00:38

如果不知道你实际在做什么,很难说,但如果你在 Java 和 C 之间传递参数,就会产生编组/转换开销。

Without knowing what you're actually doing, tough to say-but if you're passing parameters between Java and C there will be marshalling/conversion overhead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文