What Makes Jni Calls Slow

Java JNI calls are slower than expected (at least 2 ms/call)

Is this normal speed?

No. If you are really getting 50,000-80,000 ns per JNI call, something weird is going on.

What could be causing my native code to be called so much slower?

No idea. It could be almost anything. But if you showed us the native code and the Java code we'd be in a better position to explain.

My money would be on this NOT being a problem with the JNI calls at all. Rather, I expect it is an artefact of the way that you are benchmarking. There are lots of things that you can do (or fail to do) that will cause a Java benchmark to produce spurious results. We need to see your benchmarking code.


OK so, your update indicates that your earlier reported timings (50,000-80,000 or 2000-4000) are incorrect or irrelevant. Timings of 800-1000ns sound plausible, given the following.

I think there are three flaws in your benchmark.

  • You are trying to measure a time interval in the order of a few nanoseconds. But what your measurement is not taking account of is that a call to System.nanoTime() takes a significant time. What you need to do is measure the time it takes to make a few THOUSAND or MILLION JNI calls between each pair of System.nanoTime() calls, then calculate and print the average.

  • Your code doesn't separate the time taken to make the JNI call from the time taken to execute the call body. (Or maybe it does ... and you haven't shown us that code.). I suspect that the gamma correction will take significantly longer than the JNI call overhead.

  • Your warmup is inadequate. It is doubtful that you are running the code for long enough for JIT compilation to kick in. Furthermore, the fact that your benchmark code is confined to a single method call means that even if the JIT compiler did run, the chances are that you'd never call the JIT-compiled version of the method. Put the benchmark code into a method and call the method repeatedly.

Possible increase of performance using JNI?

Most float operations take around 1 ns in Java, so I am not sure how much faster you would expect them to be in C++.

However JNI calls often take around 30 ns, so unless you are performing alot of floating point operations per call, you will cost more than you save.

As the following micro-benchmark suggests, once the code as warmed up, each operations is sub nano second.

If you want this to go faster, you could use multiple cores and make it 4x or more faster.

public static void main(String[] args) throws Exception {
int length = 200000;
double[] a = fill(new double[length]);
double[] b = fill(new double[length]);
double[] c = fill(new double[length]);
double[] x = new double[length];

for (int i = 0; i < 10; i++)
testTime(length, a, b, c, x);
}

private static void testTime(int length, double[] a, double[] b, double[] c, double[] x) {
long start = System.nanoTime();
for (int i = 0; i < length; i++)
x[i] = a[i] * b[i] + c[i];
long time = System.nanoTime() - start;
System.out.printf("Average time per double operation was %.1f ns%n", time / 2.0 / length);
}

private static double[] fill(double[] doubles) {
for (int i = 0; i < doubles.length; i++)
doubles[i] = Math.random();
return doubles;
}

prints

Average time per double operation was 10.9 ns
Average time per double operation was 17.9 ns
Average time per double operation was 1.7 ns
Average time per double operation was 1.0 ns
Average time per double operation was 0.9 ns
Average time per double operation was 0.8 ns
Average time per double operation was 0.9 ns
Average time per double operation was 0.8 ns
Average time per double operation was 1.0 ns
Average time per double operation was 0.9 ns


Related Topics



Leave a reply



Submit