Added NativeUtils for native lib loading and included libKraskov.so in jar.

This commit is contained in:
Pedro Martinez Mediano 2017-06-01 20:34:23 +10:00
parent 1b69dfa3e7
commit d0b35b3db8
3 changed files with 150 additions and 29 deletions

View File

@ -68,7 +68,7 @@
<!-- Jar the toolkit -->
<target name="jar" depends="compile" description="Create the jar for distribution">
<!-- Put everything in ${bin} into the infodynamics-${version}.jar file -->
<jar jarfile="${jarplainname}" basedir="${bin}" excludes="**/cuda/"/>
<jar jarfile="${jarplainname}" basedir="${bin}" excludes="cuda/*.o,cuda/*.a,cuda/findComputeCapability"/>
</target>
<!-- Compile and run the JUnit tests -->

View File

@ -34,6 +34,7 @@ import infodynamics.utils.MatrixUtils;
import infodynamics.utils.NearestNeighbourSearcher;
import infodynamics.utils.NeighbourNodeData;
import infodynamics.utils.EmpiricalMeasurementDistribution;
import infodynamics.utils.NativeUtils;
/**
* <p>Computes the differential mutual information of two given multivariate sets of
@ -706,37 +707,44 @@ public abstract class MutualInfoCalculatorMultiVariateKraskov
if (!cudaLibraryLoaded) {
String fullPath;
// The code below is used to load native library when it's already
// outside the jar. Now we use the NativeUtils library which can extract
// and load a library from the jar (at the expense of a small latency).
// Code is left here temporarily for future reference.
// =====================================================================
if (gpuLibraryPath.length() < 1) {
// If user didn't provide a path, try the default
Path jarPath = Paths.get(MutualInfoCalculatorMultiVariateKraskov.class.getProtectionDomain().getCodeSource().getLocation().toURI());
String fileSep = System.getProperty("file.separator", "");
if (fileSep.length() == 0) {
throw new Exception("Unable to find default GPU library path. Provide path manually through setProperty().");
}
String jarFolder = jarPath.toString().substring(0, jarPath.toString().lastIndexOf(fileSep));
String relPath = fileSep + "bin" + fileSep +
"cuda" + fileSep + "libKraskov.so";
fullPath = jarFolder + relPath;
} else {
// Otherwise, use the provided path.
fullPath = gpuLibraryPath;
}
// String fullPath;
// if (gpuLibraryPath.length() < 1) {
// // If user didn't provide a path, try the default
// Path jarPath = Paths.get(MutualInfoCalculatorMultiVariateKraskov.class.getProtectionDomain().getCodeSource().getLocation().toURI());
// String fileSep = System.getProperty("file.separator", "");
// if (fileSep.length() == 0) {
// throw new Exception("Unable to find default GPU library path. Provide path manually through setProperty().");
// }
// String jarFolder = jarPath.toString().substring(0, jarPath.toString().lastIndexOf(fileSep));
// String relPath = fileSep + "bin" + fileSep +
// "cuda" + fileSep + "libKraskov.so";
// fullPath = jarFolder + relPath;
// } else {
// // Otherwise, use the provided path.
// fullPath = gpuLibraryPath;
// }
// Check if file exists
File lib = new File(fullPath);
if (!lib.exists()) {
String errmsg = "GPU library not found. To compile GPU code set the enablegpu flag to true in build.xml";
if (gpuLibraryPath.length() > 1) {
errmsg += "\nGPU library was not found in the path provided. Provide full path including library file name.";
errmsg += "\nExample: /home/johndoe/myfolder/libKraskov.so";
}
throw new Exception(errmsg);
}
// // Check if file exists
// File lib = new File(fullPath);
// if (!lib.exists()) {
// String errmsg = "GPU library not found. To compile GPU code set the enablegpu flag to true in build.xml";
// if (gpuLibraryPath.length() > 1) {
// errmsg += "\nGPU library was not found in the path provided. Provide full path including library file name.";
// errmsg += "\nExample: /home/johndoe/myfolder/libKraskov.so";
// }
// throw new Exception(errmsg);
// }
// If it does, then try to load it
System.load(fullPath);
// // If it does, then try to load it
// System.load(fullPath);
NativeUtils.loadLibraryFromJar("/cuda/libKraskov.so");
System.out.println("CUDA native library loaded.");
cudaLibraryLoaded = true;

View File

@ -0,0 +1,113 @@
/*
* Class NativeUtils is published under the The MIT License:
*
* Copyright (c) 2012 Adam Heinrich <adam@adamh.cz>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package infodynamics.utils;
import java.io.*;
/**
* A simple library class which helps with loading dynamic libraries stored in the
* JAR archive. These libraries usualy contain implementation of some methods in
* native code (using JNI - Java Native Interface).
*
* @see http://adamheinrich.com/blog/2012/how-to-load-native-jni-library-from-jar
* @see https://github.com/adamheinrich/native-utils
*
*/
public class NativeUtils {
/**
* Private constructor - this class will never be instanced
*/
private NativeUtils() {
}
/**
* Loads library from current JAR archive
*
* The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after exiting.
* Method uses String as filename because the pathname is "abstract", not system-dependent.
*
* @param path The path of file inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext
* @throws IOException If temporary file creation or read/write operation fails
* @throws IllegalArgumentException If source file (param path) does not exist
* @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of {@see File#createTempFile(java.lang.String, java.lang.String)}).
*/
public static void loadLibraryFromJar(String path) throws IOException {
if (!path.startsWith("/")) {
throw new IllegalArgumentException("The path has to be absolute (start with '/').");
}
// Obtain filename from path
String[] parts = path.split("/");
String filename = (parts.length > 1) ? parts[parts.length - 1] : null;
// Split filename to prexif and suffix (extension)
String prefix = "";
String suffix = null;
if (filename != null) {
parts = filename.split("\\.", 2);
prefix = parts[0];
suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; // Thanks, davs! :-)
}
// Check if the filename is okay
if (filename == null || prefix.length() < 3) {
throw new IllegalArgumentException("The filename has to be at least 3 characters long.");
}
// Prepare temporary file
File temp = File.createTempFile(prefix, suffix);
temp.deleteOnExit();
if (!temp.exists()) {
throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist.");
}
// Prepare buffer for data copying
byte[] buffer = new byte[1024];
int readBytes;
// Open and check input stream
InputStream is = NativeUtils.class.getResourceAsStream(path);
if (is == null) {
throw new FileNotFoundException("File " + path + " was not found inside JAR.");
}
// Open output stream and copy data between source file in JAR and the temporary file
OutputStream os = new FileOutputStream(temp);
try {
while ((readBytes = is.read(buffer)) != -1) {
os.write(buffer, 0, readBytes);
}
} finally {
// If read/write fails, close streams safely before throwing an exception
os.close();
is.close();
}
// Finally, load the library
System.load(temp.getAbsolutePath());
}
}