따라서 기본적으로 코드가 더 빠르게 실행되기를 원합니다. JNI가 답입니다. 당신이 그것이 당신에게 효과가 없다고 말한 것을 알고 있지만 당신이 틀렸다는 것을 보여 드리겠습니다.
여기 있습니다 Dot.java
:
import java.nio.FloatBuffer;
import org.bytedeco.javacpp.*;
import org.bytedeco.javacpp.annotation.*;
@Platform(include = "Dot.h", compiler = "fastfpu")
public class Dot {
static { Loader.load(); }
static float[] a = new float[50], b = new float[50];
static float dot() {
float sum = 0;
for (int i = 0; i < 50; i++) {
sum += a[i]*b[i];
}
return sum;
}
static native @MemberGetter FloatPointer ac();
static native @MemberGetter FloatPointer bc();
static native @NoException float dotc();
public static void main(String[] args) {
FloatBuffer ab = ac().capacity(50).asBuffer();
FloatBuffer bb = bc().capacity(50).asBuffer();
for (int i = 0; i < 10000000; i++) {
a[i%50] = b[i%50] = dot();
float sum = dotc();
ab.put(i%50, sum);
bb.put(i%50, sum);
}
long t1 = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
a[i%50] = b[i%50] = dot();
}
long t2 = System.nanoTime();
for (int i = 0; i < 10000000; i++) {
float sum = dotc();
ab.put(i%50, sum);
bb.put(i%50, sum);
}
long t3 = System.nanoTime();
System.out.println("dot(): " + (t2 - t1)/10000000 + " ns");
System.out.println("dotc(): " + (t3 - t2)/10000000 + " ns");
}
}
및 Dot.h
:
float ac[50], bc[50];
inline float dotc() {
float sum = 0;
for (int i = 0; i < 50; i++) {
sum += ac[i]*bc[i];
}
return sum;
}
다음 명령을 사용하여 JavaCPP로 컴파일하고 실행할 수 있습니다 .
$ java -jar javacpp.jar Dot.java -exec
Intel (R) Core (TM) i7-7700HQ CPU @ 2.80GHz, Fedora 30, GCC 9.1.1 및 OpenJDK 8 또는 11을 사용하면 다음과 같은 출력이 나타납니다.
dot(): 39 ns
dotc(): 16 ns
또는 대략 2.4 배 더 빠릅니다. 어레이 대신 직접 NIO 버퍼를 사용해야하지만 HotSpot은 어레이만큼 빠르게 직접 NIO 버퍼에 액세스 할 수 있습니다 . 반면에 루프를 수동으로 풀면이 경우 성능이 크게 향상되지 않습니다.
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation
. 벡터화 가능 메서드를 "핫"할 수있을만큼 충분히 실행하는 프로그램이 필요합니다.