FAQ
Cover
This is the archive Discourse for the Processing (ALPHA) software.
Please visit the new Processing forum for current information.

   Processing 1.0 _ALPHA_
   Topics & Contributions
   Tools
(Moderator: REAS)
   native code, dlls, jni
« Previous topic | Next topic »

Pages: 1 
   Author  Topic: native code, dlls, jni  (Read 4719 times)
TomC

WWW
native code, dlls, jni
« on: May 20th, 2004, 1:44pm »

Has anyone used JNI with Processing to speed up heavy calculations?  
 
Was there a noticeable benefit?  Do you have any example code?
 
I have tried it today, but with no results yet.  I ported Quasimondo's fast blur code to C++ with JNI, but when I use the dll in conjunction with a native method, it doesn't seem to do anything, and then it crashes.  Anyone care to take a look at it?
 
TomC

WWW
Re: native code, dlls, jni
« Reply #1 on: May 20th, 2004, 4:11pm »

Well, I fixed it.  It's not noticably faster, but it's not any slower either.
 
If you ever need to know how to do this, feel free to ask.
 
mKoser

WWW Email
Re: native code, dlls, jni
« Reply #2 on: May 20th, 2004, 4:47pm »

(if you describe it here, i think we've got a genuine techNote!) ... i'd love to know, but i've got a feeling i'm not going to understand the answer!
 

mikkel crone koser | www.beyondthree.com | http://processing.beyondthree.com
TomC

WWW
Re: native code, dlls, jni
« Reply #3 on: May 20th, 2004, 5:41pm »

OK here goes.  This is not beginner-friendly!  It's geekiness for the sake of it at the moment
 
What's JNI?  ... JNI is the Java Native Interface, a way to call native machine code from Java programs.
 
Why JNI?  ... Because Java code is (mostly) run from bytecode on a virtual machine, and in certain circumstances this will be slower than native code.  You might also want to use a library which is not available for Java.
 
What's the disadvantage? ... It pretty much stops your code being cross platform, and makes deploying as an applet harder.  
 
You will need:
 
* 1 C++ compiler
* 1 copy of processing
* 1 copy of the latest Java SDK
* 1 sketch with a heavy computation to perform
 
If you install the full java SDK, I find it useful to put it in C:\j2sdk\ (without the version number provided by default) because it means you shouldn't need to update your paths when you upgrade to the next version.
 
For C++ compiling in windows, I use MinGW which is a version of GCC.  Download MinGW-3.1.0-1.exe and MSYS-1.0.10.exe from
http://www.mingw.org/download.shtml and install them in that order.  If you're familiar with c++, you might like to use your own environment.
 
If you use the default installs, then running MSYS should bring up a unix-like terminal window.
 
Code:

tomc@MACHINE ~
$  

 
MSYS sets up a home directory with your username.  On the default install this was at C:\msys\1.0\home\tomc\
 
Code:

tomc@MACHINE ~
$ pwd
/home/tomc

 
Make a folder called code, and change to that folder...
Code:

tomc@MACHINE ~
$ mkdir code
code
 
tomc@MACHINE ~
$ cd code
 
tomc@MACHINE ~/code
$  
 

 
Now you need to make 2 files.  One java one for your function to be defined so that processing can see it, and one c++ one which will do the work.  To make them on the MSYS commandline, use the touch command...
 
Code:

 
tomc@MACHINE ~/code
$ touch MyHeavyFunction.java
 
tomc@MACHINE ~/code
$ touch MyHeavyFunction.cpp  
 

 
 
To make life easier, I made my heavy function into a self contained static version.  This way I don't have to exchange data backwards and forwards between the DLL and the VM.  So where in Processing I had:
 
Code:

 
void loop() {
  // draw stuff
  myHeavyFunction(width, height, pixels);
}
 
static void myHeavyFunction(int w, int h, int[] pix) {
  // do complicated stuff to pixels
}
 

 
I now have this in the loop:
 
Code:

void loop() {
  // draw stuff
  MyHeavyFunction.myHeavyFunction(width,height,pix);
}

 
And MyHeavyFunction.java contains just the following:
 
Code:

 
class MyHeavyFunction {
 
  static {  
    System.loadLibrary("MyHeavyFunction");
  }
 
  static native void myHeavyFunction(int w, int h, int[] pix);
 
}
 
 
 
The native keyword means that we won't implement the method right here and now, but the compiler believes us when we say it will be available somewhere, somehow.  The static block gets run the first time the class is loaded, and it will load up MyHeavyFunction.dll (or .so on Linux) for us.
 
Now the hard bit(!).  Most c++ programs use header files which tell the compiler what functions are going to be defined.  The Java SDK provides a tool called javah which will create this for us from a .class file with a native method.  So first you need to compile the Java file:
 
Code:

 
tomc@MACHINE ~/code
$ javac MyHeavyFunction.java  
 

 
Then you run javah on the resulting class:
 
Code:

 
tomc@MACHINE ~/code
$ javah -o MyHeavyFunction.h MyHeavyFunction
 

 
This makes a file called MyHeavyFunction.h.  Open it up.  It should have a lot of messy C code in it, but basically all you need is the function declaration, which should look like this:
 
Code:

 
JNIEXPORT void JNICALL Java_Blur_myHeavyFunction
  (JNIEnv *, jclass, jint, jint, jintArray);
 

 
Copy that into MyHeavyFUnction.cpp.  Then make the following changes:
 
* include the header
* add names to each of the arguments
* make it into an empty function
 
Code:

 
#include "MyHeavyFunction.h"
 
JNIEXPORT void JNICALL Java_Blur_fastblur
  (JNIEnv *env, jclass c, jint w, jint h, jintArray pix) {
 
  // the hard work will be done here...
 
}
 

 
OK, save all that.  Now, assuming the Java SDK is installed at C:\j2sdk, then if you do:
 
Code:

g++ -I/c/j2sdk/include -I/c/j2sdk/include/win32 -Wl,--add-stdcall-alias -shared -o MyHeavyFunction.dll MyHeavyFunction.cpp

 
it should make you a DLL.  Move MyHeavyFunction.class and MyHeavyFunction.dll to the code folder in your sketch folder and you're ready to go.  I'll leave the c++ conversion of your java code to another post - maybe tomorrow!
 
 
 
« Last Edit: May 20th, 2004, 5:47pm by TomC »  
pitaru

WWW Email
Re: native code, dlls, jni
« Reply #4 on: May 20th, 2004, 7:47pm »

Great work Tom, and the explanation is also very clear.
 
*Perhaps* the reason for the disappointing performance is due to the number of calls to the DLL. While the C code runs faster, the JNI pipeline between the two platforms is horribly narrow. To really take advantage of JNI/DLL, you need to think about triggering events in C which will than affect the operating system directly (the JSyn engine used by Sonia is a perfect example). JNI's are also helpful to interface with the operating system in ways that java cannot - such as reading data from Wacom devices etc.
 
amit
« Last Edit: May 20th, 2004, 7:48pm by pitaru »  
fry

WWW
Re: native code, dlls, jni
« Reply #5 on: May 20th, 2004, 8:36pm »

yeah, the overhead from jni calls is wicked.
 
also, general math in java is actually quite fast/near native with the more recent hotspot-based JITs.
 
native code still helps in a lot of areas, for instance if you're dealing with thousands of objects, or doing a lot of i/o and manipulations on them.  
 
there's also the shared memory api in 1.3 (or 1.4?) and i've heard good things about using that to just hold a huge buffer of data in memory that gets "shared" between java and a native app.  
 
msft had a faster, inlined jni (called jdirect) that didn't require you to do quite as much quirky additional stuff to talk native, but it was a naughty extension and sun got pissed and they haven't continued. and of course, it only worked on windows. (mac had its own, confusingly called j/direct, which did roughly the same thing)
 
fry

WWW
Re: native code, dlls, jni
« Reply #6 on: May 20th, 2004, 8:40pm »

and i forgot to mention.. this is a really great/useful tutorial. i wonder if we should get it in a more useful place.  
 
msys is a really great tool (as is cygwin, another alternative). though i've been using msys/mingw to build processing.exe for a while.
 
someday i'd love to use p5 as a frontend to the gcc stuff as well, so that people can move to c++/opengl when they're ready. or even just to compile-in native stuff like this.. but umm.. that's someday far off, if ever..
 
TomC

WWW
Re: native code, dlls, jni
« Reply #7 on: May 21st, 2004, 1:25am »

Amit, Ben, thanks for the feedback.  Feel free to use / rewrite this info as you see fit.  It was a bit of a disappointment that this method didn't allow me to do convolutions etc at higher resolutions... guess it's back to OpenGL for this particular project  I'll take a look at the shared memory stuff though, thanks.
 
With hindsight, I think my post above is a little bit of a let down, because the difficult part is actually converting your code to C++, and using the Java environment methods in the right places (to access arrays etc.). So, to get started with processing pixels, the following might be handy:
 
Code:

 
JNIEXPORT void JNICALL Java_MyHeavyFunction_myHeavyFunction
  (JNIEnv *env, jclass c, jint w, jint h, jintArray pixarray) {
 
  // Java arrays in JNI don't give direct access  
  // to elements, so we have to ask the environment
  // for a pointer to the data...
  jboolean isCopy = JNI_FALSE;
  jint *pix = env->GetIntArrayElements(pixarray, &isCopy);
  // you can ask for the length too, unlike C arrays
 
  // should probably check that pix isn't null here
  // also, if isCopy is JNI_TRUE, then we're  
  // not accessing the data directly
 
  //
  // mess with the pixels in pix here
  //
 
  // now tell the environment to write back
  // the changes (if it's a copy)
  // or release the data (if it's not a copy)
  env->ReleaseIntArrayElements(pixarray, pix, JNI_COMMIT);
  // use JNI_ABORT to discard changes and just  
  // release the data
 
}
 

 
I hope that gets people started.  You'll still need to be reasonably confident with C/C++ in order to not get bogged down with memory problems.  I found the following two sites to be useful today:
 
http://java.sun.com/docs/books/jni/html/jniTOC.html
 
http://www.inonit.com/cygwin/jni/helloWorld/
 
 
About the move to c++/opengl... I have a 15% (ish) complete implementation of the processing API in C++/OpenGL/glut.  As and when it settles down some more, I'd like to take a look at some of the more complex bits (images, video, serial, network, etc) and see if I can't get more things running.  I'm aiming for requiring only minimal changes to compile, and I've got a bit of a Java to C++ transition tutorial lined up.  I'll be sure to post it when it's done.
 
 
justo


Re: native code, dlls, jni
« Reply #8 on: May 21st, 2004, 5:20am »

on May 21st, 2004, 1:25am, TomC wrote:
It was a bit of a disappointment that this method didn't allow me to do convolutions etc at higher resolutions... guess it's back to OpenGL for this particular project

 
its been a while since ive written some convolution code (doing sobel and canny edge detection), but looking over the code it seems like you can get more speed up doing some higher level optimizations by "pre-computing" things...meaning pre-computing what the operations will be, rather than doing it the stricter more mathematical way...analogous to how you can get some speed ups in transformations by only modifying a few entries in a matrix rather than doing the generalized full matrix multiplication for every transform.  
 
the only real speed up youre getting from using JNI is in the array accesses since it doesnt have to do bounds checking, and as youve shown, it doesnt really add up to enough to negate the JNI overhead. very cool tutorial though; it should definitely added to the tech notes section or fully written up as a tutorial.
 
Quote:
About the move to c++/opengl... I have a 15% (ish) complete implementation of the processing API in C++/OpenGL/glut.  As and when it settles down some more, I'd like to take a look at some of the more complex bits (images, video, serial, network, etc) and see if I can't get more things running.  I'm aiming for requiring only minimal changes to compile, and I've got a bit of a Java to C++ transition tutorial lined up.  I'll be sure to post it when it's done.

 
this sounds great. i actually heard about someone at ITP attempting something similar, but using a software renderer in C, though i think his motivation was somewhat about his language biases...dont know how far that got though. obviously youve made your language decision purposefully, but what are your thoughts on using JOGL or LWJGL
« Last Edit: May 21st, 2004, 5:20am by justo »  
TomC

WWW
Re: native code, dlls, jni
« Reply #9 on: May 21st, 2004, 9:41am »

on May 21st, 2004, 5:20am, justo wrote:

 
its been a while since ive written some convolution code (doing sobel and canny edge detection), but looking over the code it seems like you can get more speed up doing some higher level optimizations by "pre-computing" things...meaning pre-computing what the operations will be, rather than doing it the stricter more mathematical way...analogous to how you can get some speed ups in transformations by only modifying a few entries in a matrix rather than doing the generalized full matrix multiplication for every transform.  

 
It's been a while since I've done any convolution stuff too  Maybe we could take this to another thread - if you have any references for optimising blur/edge detection etc I'd be really interested to see them.  Do you have specific ideas about Quasimondo's fastblur code  It seems to beat my naive version of a 3x3 mean filter, which is a good start
 
on May 21st, 2004, 5:20am, justo wrote:

 
this sounds great. i actually heard about someone at ITP attempting something similar, but using a software renderer in C, though i think his motivation was somewhat about his language biases...dont know how far that got though. obviously youve made your language decision purposefully, but what are your thoughts on using JOGL or LWJGL

 
There's already quite a bit of (slightly stale) C/OpenGL/JOGL code sat in the processing source tree, so I didn't want to step on any toes.  The only reason for the choice of language is that I'm working in a C++ team at the moment and I needed some practice after 2 years of Java  I'm not picky about language choice really, but I needed the quickest route to get hardware acceleration and I don't know enough about the Java OpenGL implementations.
 
« Last Edit: May 21st, 2004, 10:04am by TomC »  
fry

WWW
Re: native code, dlls, jni
« Reply #10 on: May 21st, 2004, 4:09pm »

yeah, the opengl in the source tree has gone stale around rev 60 or so while i've been trying to get the api firmed up.
 
it was also based on gl4java, which hasn't been maintained for a while, so i've been holding off on working on it further in the hope of instead moving to jogl once that gets firmed up.
 
for my own c++/opengl work, i've also been making a layer that looks more like processing (since it's not so fun to go back to opengl after using p5 for a while), so maybe i'll be able to release that at some point as well.
 
Pages: 1 

« Previous topic | Next topic »