Closed phlip9 closed 8 years ago
Thanks for this contribution!
Actually, I created an Android version of JOCL ~4 years ago, but I had a non-disclosure-agreement with some company (which now does no longer seem to give a ... care about this topic - and the NDA was limited to 3 years, so ... the risk of being sued should be rather small). I remember that there had been some other issues. From the tip of my head, there was something related to the inheritance hierarchy of the Buffer
class, but I'll have to revise this - it might be that this is no longer an issue.
I'll have to read through the changes in more detail. I'll try to do this during the weekend, and give it a try early next week (I should even be able to test it on some android device - the above mentioned company provided me one, and they never wanted it back...).
But quickly going over the changes and the points that you mentioned:
"sun.arch.data.model"
string is, according to the name, likely just a "legacy" property and too specific. But according to https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html , System.getProperty("os.arch");
should be a portable approach, and I'd prefer this to a JNI based solution (if it works on Android as well) System.load
. The System.loadLibrary
path is mainly for local tests and as a fallback. However, there are some open questions, also regarding Maven and the deployment of the natives (also see the TODOs below).mk
files to be fed into the NDK - it indeed was painful. And I think android-cmake
did not exist back then - I'll have a closer look at this.Regarding the TODOs:
Generalizations regarding the target platforms (and their build processes):
These are always welcome. However, they may increase the complexity of the makefiles considerably. (You might have noticed that the current issues in the issue tracker are related to "embarassingly basic" problems of building on other platforms - I hope that a robust, portable and maintainable solution can be found there soon...)
The native library deployment (and loading) is indeed an issue. There have been some related discussions in the JOCL forum. The migration of JOCL from "a downloadable ZIP" to "a Maven artifact" was a hassle. (For me, because I'm not a Maven expert, and ... native libraries are always difficult in Maven).
I'll try to summarize some points here (and consider to open one or more dedicated issues in the issue tracker for these) :
System.load
(not System.loadLibrary
). This has the drawback that all native libraries must be available before creating the Maven artifact. The advantage is that one can just download and drop the JAR into the classpath and it should run everywhere. LibUtils
class has evolved over time, and generalized step by step, to allow more flexibility in the library loading. Recently, I added the option to load dependencies before loading the actual JNI library (mainly for JOCLBLAS and JOCLBlast). However, it is still lacking some features that are already on my TODO list. Mainly, a proper versioning scheme. It should more easily be possible to handle different versions of the natives. Some "version number string" (with semantic versioning pattern) should likely be integrated here.OpenCL.DLL
, which contains the ICD (here is a recent related forum thread). In the end, this is the reason for the LibInitializer
contortions, which would not be necessary for "simple" JNI bindings.LibUtils
into a dedicated project. (I also hate the redundancy between JOCL and JCuda, and when more features are integrated (version numbers, dependecy handling...), this becomes an even more pressing issue). But there already are approaches for this - for example, https://github.com/scijava/native-lib-loader . I have to evaluate this and compare its functionality to the LibUtils
, to see whether this library could replace the LibUtils
, or whether the LibUtils
should indeed become a dedicated project.(BTW: I didn't even know BIDMat, thanks for this pointer)
Sizeof.computePointerSize(): The "sun.arch.data.model" string is, according to the name, likely just a "legacy" property and too specific. But according to https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html , System.getProperty("os.arch"); should be a portable approach, and I'd prefer this to a JNI based solution (if it works on Android as well).
I'm not sure this is always valid. While the system might be 64 bit, the library and/or JVM could be compiled as 32 bit. I'm not sure how exactly the "os.arch" responds to say a 32 bit vs 64 bit JVM or the precise interplay between JVM and native pointers; but (from my understanding, please correct me if I'm wrong), I would assume the native code interacting with the OpenCL API is the source of truth in this case.
LibInitializer.java : These hard-coded paths look a bit odd, but from a quick websearch, "trying out different names" seems to be the way to go here. (This might be related to the last TODO, see below)
I agree. It's definitely not pretty, but Google has not standardized OpenCL on Android (they're pushing for their own framework called Renderscript). As a result, every vendor seems to put their library in nonstandard locations...
Android shared library outputs to nativeLibraries/${ANDROID_ABI}/ : I'm not entirely sure (yet) what this is about (and have I'll have to revise how I handled the native library in my first tests). Usually, the intention in JOCL is to pack the native library into the JAR, unpack it at runtime, and load it with System.load. The System.loadLibrary path is mainly for local tests and as a fallback. However, there are some open questions, also regarding Maven and the deployment of the natives (also see the TODOs below)
Unfortunately, I don't think Android supports unpacking the library and then loading it (might have something to do with permissions?) Maybe I'm wrong, but I haven't had any luck with the extract and then load process. Android's loadLibrary method is nonstandard in that a call to loadLibrary("libfoo.so") searches not for lib/libfoo.so but rather lib/armveabi-v7a/libfoo.so and lib/arm/libfoo.so if, for example, the device is running an armv7a compatible processor. I would like a more standard and maintainable library loading method, however.
On a different note, I'm wondering whether we should classify Android as its own OS or put it under Linux in LibUtils
. I'm not sure what the exact differences are, if any, between binaries compiled with the arm-linux-androideabi toolchain and the arm-linux-gnueabi toolchain.
I'm not sure this is always valid. While the system might be 64 bit, the library and/or JVM could be compiled as 32 bit. I'm not sure how exactly the "os.arch" responds to say a 32 bit vs 64 bit JVM or the precise interplay between JVM and native pointers; but (from my understanding, please correct me if I'm wrong), I would assume the native code interacting with the OpenCL API is the source of truth in this case.
On the one hand, you are right. According to a quick websearch, os.arch
returns the JRE architecture, and not the OS architecture. On the other hand, this is kind of a chicken-egg problem: The native library that will be loaded will also depend on the os.arch
. The alternative would thus be to store the bitness directly in the LibUtils.ArchType
enums and obtain them from ther. But frankly, the ArchType
involves some guesswork as well, so I think that obtaining this information natively (and generically) is at least reasonable - maybe I'll review this if the LibUtils
are refactored.
Unfortunately, I don't think Android supports unpacking the library and then loading it ...
This may be true. I had another look at my old JOCL-Android project, and noticed the libs/armeabi
and libs/armeabi-v7a
directories there, containing the JOCL binaries. However, this project was set up years ago. It still used the Eclipse ADT plugin and custom .mk
makefiles - and admittedly, I didn't investigate all the details that are hidden behind the convenient "Install" button that pushes the APK to the device...
Regarding the pull request: I had a closer look at this, and it seems that it is safe and compatible to the existing toolchains. I reviewed the changes, tested it locally, and everything worked fine. So I merged it locally, with minor adjustments, and will push it soon.
One thing: In https://github.com/gpu/JOCLCommon/pull/3 you added the -fPIC
flag for Unix platforms. I think this is strongly related to https://github.com/gpu/JOCL/issues/3 . Might it be that this change also resolves the issue?
Apart from that, I'm currently updating (or rather reviving) my Android infrastructure: I downloaded Android Studio and try to familiarize with it, and see how the NDK interplays with it. I have some trouble with my android device (API version 7 ... ) : It's connected to the USB for 1 hour now, and still says "Charging: 0%" - hope it's not a defect battery... However, I hope that once everything is set up, I can actually try out your changes.
Forgot that one:
I'm wondering whether we should classify Android as its own OS or put it under Linux in LibUtils
Although it does not make a difference in the LibUtils
, the difference in the LibInitializer
is crucial: For Android, it needs the predefined implementation library paths. (This might also be reviewed during a refactoring of the LibUtils
, but at the moment, the ANDROID
type seems to be required)
nativeLibraries/${ANDROID_ABI}/
to comply with canonical Android lib location (also the only place the Android runtime checks when searching for a shared library through System.loadLibrary(...)).TODO: More general cross-compiling support?
TODO: Better, more explicit support for other OS's / ARCH's?
TODO: Library would be more accessible if uploaded to maven repo. But we also have native libraries which makes everything painful.
TODO: Refactor out native library loading to another library? There's lots of redundancy and slight changes between this LibUtils, jcuda's LibUtils, our LibUtils (BIDMat), etc...