Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Android NDK give speedup for sending large int[] over sockets?

I need to send an array of 500,000 ints over a socket between two Android devices. Currently, I'm spending a lot of time converting the int[] to a byte[] so that Java's socket will accept it (see my previous question Efficiently send large int[] over sockets in Java, where we determined there's no faster way to do the typecasting in Java).

My question now is, if I take the int[] and pass it through JNI to the Android NDK, can I expect the typecasting to byte[] to go any faster in native code? I know typecasting int* to char* is quite simple in plain-old C, however I'm wondering if the JNI will negate any performance gains.

Furthermore, once I have a byte[] in my native code, can I efficiently pass it back to my Java code or do I need to implement the socket in C as well?

Edit 1: People have been posting a lot of answers without clicking on the link. Using ByteBuffers is not a good option, its actually way slower than mask-and-shift, which is still way slower than my performance critical code needs! That's why I'm asking about the NDK.

Edit 2: I changed the text above to say that C code can cast from int* to char* instead of int[] to byte[]. Hopefully that clarifies the question.

Edit 3: To clarify my use-case, this is a research problem where I distribute a large array of ints across multiple devices and sort the list in parallel. Assume that I have 500,000 ints in Java (doesn't matter where they come from) and I need to get them off the device via a socket as quickly as possible. Answers that say "don't start with an array of ints" aren't helpful. Additionally, my application code needs to be as close to 100% Java as possible. If native typecasting and sockets improve performance, that's ok, but I can't do anything else (i.e. the sort) natively.

like image 537
Jeremy Fowers Avatar asked Sep 12 '12 20:09

Jeremy Fowers


3 Answers

No, using JNI/NDK won't give you a performance boost. First of all when you try to get the array over to the native code you'll have to copy it or use a directly allocated ByteBuffer. Turns out the implementation of Dalvik VM always returns direct pointer from Get*ArrayElements(). I do doubt that you'll get a performance bump because calls through JNI have overhead cost. Finally C++ and Java have the very close performance in this scenario (see C++ performance vs. Java/C#).

Take a look at this question and the first answer for a fast way to convert the int[] to a byte[] from Java How to convert int[] to byte[]

Is there a reason you're using an int[] instead of byte[] to begin with? If it's an image we might be able to recommend ways of avoiding conversion.

like image 152
Samuel Avatar answered Nov 07 '22 20:11

Samuel


Use a SocketChannel and you can use ByteBuffers instead.

buffer.asIntBuffer().put(ints);
do {
  channel.write(buffer);
} while (buffer.hasRemaining());
like image 37
obataku Avatar answered Nov 07 '22 20:11

obataku


If the Java code needs efficient access to int[], then there is a good chance that native send/receive with sockets is worth the effort.

But often it is OK to use IntBuffer instead of int[]. In this case, you can allocate a ByteBuffer and get an IntBuffer from it:

ByteBuffer bb = ByteBuffer.allocate(500000*4);
IntBuffer ib = bb.asIntBuffer();

You should experiment with both allocate() and allocateDirect(), see " ByteBuffer.allocate() vs. ByteBuffer.allocateDirect() " and http://objectissues.blogspot.co.il/2005/10/java-nio-allocate-vs-allocatedirect.html.

Important! In this case, you will get UnsupportedOperationException if you try to use ib.array().

like image 1
Alex Cohn Avatar answered Nov 07 '22 19:11

Alex Cohn