![](/img/trans.png)
[英]Why my implementation of binary search in Java slower than sequential search?
[英]Why is the JNI implementation of my method running slower than pure Java?
作為我的CS類之一,我必須用Java編寫一個矩陣類,並通過Java Native Interface用Java以及C ++實現一些方法,並測量執行時間的差異。
編寫和調試這兩個版本非常簡單,經過大約3個小時的時間(主要是在谷歌上搜索了如何選擇接口)后,我得出了以下代碼:
Matrix.java:
public class Matrix {
private double[] data;
private int width, height;
public Matrix(int h, int w) {
width = w;
height = h;
data = new double[w * h];
}
public static void main(String[] args) {
/* takes 3 parametres u, v and w, creates two matrices m1 and m2, dimensions u*v and v*w
* fills them with random doubles, multiplies m1 * m2 with both methods
* reports time elapsed and checks equality of result */
}
public Matrix multiply(Matrix mat) { return multiply(mat, false); }
public Matrix multiplyNative(Matrix mat) { return multiply(mat, true); }
public Matrix multiply(Matrix mat, boolean natively) {
int u, v, w;
u = this.height;
w = mat.width;
Matrix res = new Matrix(u, w);
if(this.width == mat.height) v = this.width;
else return res;
if(natively) multiplyC(this.data, mat.data, res.data, u, v, w);
else {
for(int i=0; i<u; i++) {
for(int j=0; j<w; j++) {
double elem = 0.0;
for(int k=0; k<v; k++) {
elem += this.data[i*v+k] * mat.data[k*w+j];
}
res.data[i*w+j] = elem;
}
}
}
return res;
}
public static native void multiplyC(double[] a, double[] b, double[] r, int i, int j, int k);
// SNIP: equals and random-prefill methods
static {
System.loadLibrary("Matrix");
}
}
Matrix.cpp:
#include "Matrix.h"
JNIEXPORT void JNICALL Java_Matrix_multiplyC(JNIEnv *env, jclass,
jdoubleArray a, jdoubleArray b, jdoubleArray res,
jint u, jint v, jint w) {
jdouble* mat1 = env->GetDoubleArrayElements(a, 0);
jdouble* mat2 = env->GetDoubleArrayElements(b, 0);
jdouble* mat_res = env->GetDoubleArrayElements(res, 0);
for(int i=0; i<u; i++) {
for(int j=0; j<w; j++) {
jdouble elem = 0.0;
for(int k=0; k<v; k++) {
elem += mat1[i*v+k] * mat2[k*w+j];
}
mat_res[i*w+j] = elem;
}
}
env->ReleaseDoubleArrayElements(a, mat1, 0);
env->ReleaseDoubleArrayElements(b, mat2, 0);
env->ReleaseDoubleArrayElements(res, mat_res, 0);
}
但是,由於某些原因,對於大多數輸入大小,Java實現都是一樣快或更快,這絕對不是與某些同學交談后的預期結果。
這是從我的Debian虛擬盒子中獲得的一些不同矩陣大小的示例輸出數據:
axim@hackbox:~/Desktop/prcpp/jni$ java -Djava.library.path=. Matrix 5 12 8
time taken in Java: 11452ns
time taken in C++: 20990ns
results equal: true
axim@hackbox:~/Desktop/prcpp/jni$ java -Djava.library.path=. Matrix 20 48 32
time taken in Java: 5439887ns
time taken in C++: 5492423ns
results equal: true
axim@hackbox:~/Desktop/prcpp/jni$ java -Djava.library.path=. Matrix 80 192 128
time taken in Java: 19726130ns
time taken in C++: 25375681ns
results equal: true
axim@hackbox:~/Desktop/prcpp/jni$ java -Djava.library.path=. Matrix 320 768 512
time taken in Java: 194357345ns
time taken in C++: 384648461ns
results equal: true
axim@hackbox:~/Desktop/prcpp/jni$ java -Djava.library.path=. Matrix 1280 3072 2048
time taken in Java: 58514495266ns
time taken in C++: 116695035710ns
results equal: true
如您所見,本機版本運行所需的時間一直都比較長,但是兩者的比例似乎不穩定,並且似乎沒有遵循趨勢,但是當我將相同大小運行多次時,它相對穩定。
為了使其更加奇怪,在我的Macbook上,它遵循完全不同的曲線:類似地,開始時,小尺寸的速度要慢近2倍,在中等尺寸(大約100-200行/列)的情況下,其完成速度是20-30%時間,然后再變大一點。
axim@ax1m-MBP:~/Desktop/CodeStuff/prcpp/a1/matrix$ java Matrix 5 12 8
time taken in Java: 32454ns
time taken in C++: 43379ns
results equal: true
axim@ax1m-MBP:~/Desktop/CodeStuff/prcpp/a1/matrix$ java Matrix 20 48 32
time taken in Java: 1278592ns
time taken in C++: 103246ns
results equal: true
axim@ax1m-MBP:~/Desktop/CodeStuff/prcpp/a1/matrix$ java Matrix 80 192 128
time taken in Java: 12594845ns
time taken in C++: 2604591ns
results equal: true
axim@ax1m-MBP:~/Desktop/CodeStuff/prcpp/a1/matrix$ java Matrix 320 768 512
time taken in Java: 1272993352ns
time taken in C++: 1217730765ns
results equal: true
axim@ax1m-MBP:~/Desktop/CodeStuff/prcpp/a1/matrix$ java Matrix 1280 3072 2048
time taken in Java: 110882859155ns
time taken in C++: 102803692425ns
results equal: true
這里的第三個調用是關於我與同學交談的期望,但是該程序將需要根據作業處理更大的數據。 如果有人可以解釋這里到底發生了什么,那會很棒嗎?
嘗試在編譯代碼時使用-O3;)
首先,您不必提交對輸入數組的更改。 如果將JNI_ABORT用於不需要傳遞回Java的數組,則可以在C ++中獲得更快的計算速度:
-O3
java -Djava.library.path=. -cp . Matrix 5 12 8
C++: 0
java -Djava.library.path=. -cp . Matrix 20 48 32
C++: 0
java -Djava.library.path=. -cp . Matrix 80 192 128
C++: 2
java -Djava.library.path=. -cp . Matrix 320 768 512
C++: 1254
java -Djava.library.path=. -cp . Matrix 1280 3072 2048
C++: 104179
-O0
java -Djava.library.path=. -cp . Matrix 5 12 8
C++: 0
java -Djava.library.path=. -cp . Matrix 20 48 32
C++: 0
java -Djava.library.path=. -cp . Matrix 80 192 128
C++: 7
java -Djava.library.path=. -cp . Matrix 320 768 512
C++: 2400
java -Djava.library.path=. -cp . Matrix 1280 3072 2048
C++: 183814
-O3 + JNI_ABORT
java -Djava.library.path=. -cp . Matrix 5 12 8
C++: 0
java -Djava.library.path=. -cp . Matrix 20 48 32
C++: 0
java -Djava.library.path=. -cp . Matrix 80 192 128
C++: 3
java -Djava.library.path=. -cp . Matrix 320 768 512
C++: 1121
java -Djava.library.path=. -cp . Matrix 1280 3072 2048
C++: 96696
Java
java -Djava.library.path=. -cp . Matrix 5 12 8
Java: 0
java -Djava.library.path=. -cp . Matrix 20 48 32
Java: 1
java -Djava.library.path=. -cp . Matrix 80 192 128
Java: 13
java -Djava.library.path=. -cp . Matrix 320 768 512
Java: 1242
java -Djava.library.path=. -cp . Matrix 1280 3072 2048
Java: 101324
您可以在這里閱讀有關JNI_ABORT的更多信息: http ://jnicookbook.owsiak.org/recipe-No-013/
如果要編寫此代碼,則可以將u,v,w傳遞給C ++,可以在那里創建數組,可以創建輸出數組並將其傳遞回Java。 減少數據的復制粘貼;)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.