[SYSTEMDS-2663, 2664] Prepare native instructions for release 2.0
* pulled in a few CMake tricks from gpu codegen dev branch to unify lib naming
* verify MKL and OpenBLAS working
* cleanup native lib loader class (NativeHelper)
* build script for Windows
Closes #1063
diff --git a/src/main/cpp/CMakeLists.txt b/src/main/cpp/CMakeLists.txt
index 2bb8c04..9489f8f 100644
--- a/src/main/cpp/CMakeLists.txt
+++ b/src/main/cpp/CMakeLists.txt
@@ -21,7 +21,7 @@
cmake_minimum_required(VERSION 3.8)
cmake_policy(SET CMP0074 NEW) # make use of <package>_ROOT variable
-project (systemds)
+project (systemds LANGUAGES CXX)
# All custom find modules
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
@@ -41,8 +41,19 @@
set(MATH_LIBRARIES "")
# sets the installation path to src/main/cpp/lib
-set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR})
-install(TARGETS systemds LIBRARY DESTINATION lib)
+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}" CACHE PATH "sets the installation path to src/main/cpp/lib" FORCE)
+endif()
+
+# sets the installation path to src/main/cpp/lib
+# install(TARGETS systemds LIBRARY DESTINATION lib)
+install(TARGETS systemds RUNTIME DESTINATION lib)
+
+# unify library filenames to libsystemds_<...>
+if (WIN32)
+ set(CMAKE_IMPORT_LIBRARY_PREFIX lib CACHE INTERNAL "")
+ set(CMAKE_SHARED_LIBRARY_PREFIX lib CACHE INTERNAL "")
+endif()
set(CMAKE_BUILD_TYPE Release)
diff --git a/src/main/cpp/build.bat b/src/main/cpp/build.bat
new file mode 100644
index 0000000..93c3819
--- /dev/null
+++ b/src/main/cpp/build.bat
@@ -0,0 +1,38 @@
+@ECHO OFF
+::-------------------------------------------------------------
+::
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements. See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership. The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License. You may obtain a copy of the License at
+::
+:: http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied. See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+::
+::-------------------------------------------------------------
+
+:: This shell script compiles the required shared libraries for Windows on x86-64
+:: Make sure to have run "\"%INTEL_ROOT%\"\compilervars.bat intel64 vs2019" and set OpenBLAS_HOME to where
+:: libopenblas.lib is located
+
+:: configure and compile INTEL MKL
+cmake -S . -B INTEL -DUSE_INTEL_MKL=ON -DCMAKE_BUILD_TYPE=Release
+cmake --build INTEL --target install --config Release
+rmdir /Q /S INTEL
+
+:: configure and compile OPENBLAS
+cmake . -B OPENBLAS -DUSE_OPEN_BLAS=ON -DCMAKE_BUILD_TYPE=Release
+cmake --build OPENBLAS --target install --config Release
+rmdir /Q /S OPENBLAS
+
+echo.
+echo "Make sure to re-run mvn package to make use of the newly compiled libraries"
\ No newline at end of file
diff --git a/src/main/cpp/cmake/FindOpenBLAS.cmake b/src/main/cpp/cmake/FindOpenBLAS.cmake
index 8870d15..a67b3bf 100644
--- a/src/main/cpp/cmake/FindOpenBLAS.cmake
+++ b/src/main/cpp/cmake/FindOpenBLAS.cmake
@@ -46,7 +46,7 @@
)
FIND_PATH(OpenBLAS_INCLUDE_DIR NAMES cblas.h PATHS ${Open_BLAS_INCLUDE_SEARCH_PATHS})
-FIND_LIBRARY(OpenBLAS_LIB NAMES openblas PATHS ${Open_BLAS_LIB_SEARCH_PATHS})
+FIND_LIBRARY(OpenBLAS_LIB NAMES openblas libopenblas PATHS ${Open_BLAS_LIB_SEARCH_PATHS})
SET(OpenBLAS_FOUND ON)
diff --git a/src/main/cpp/lib/libsystemds_mkl-Linux-x86_64.so b/src/main/cpp/lib/libsystemds_mkl-Linux-x86_64.so
index c2a3795..800fe13 100644
--- a/src/main/cpp/lib/libsystemds_mkl-Linux-x86_64.so
+++ b/src/main/cpp/lib/libsystemds_mkl-Linux-x86_64.so
Binary files differ
diff --git a/src/main/cpp/lib/libsystemds_mkl-Windows-AMD64.dll b/src/main/cpp/lib/libsystemds_mkl-Windows-AMD64.dll
new file mode 100644
index 0000000..2960551
--- /dev/null
+++ b/src/main/cpp/lib/libsystemds_mkl-Windows-AMD64.dll
Binary files differ
diff --git a/src/main/cpp/lib/libsystemds_openblas-Linux-x86_64.so b/src/main/cpp/lib/libsystemds_openblas-Linux-x86_64.so
index bfef446..6e45343 100644
--- a/src/main/cpp/lib/libsystemds_openblas-Linux-x86_64.so
+++ b/src/main/cpp/lib/libsystemds_openblas-Linux-x86_64.so
Binary files differ
diff --git a/src/main/cpp/lib/libsystemds_openblas-Windows-AMD64.dll b/src/main/cpp/lib/libsystemds_openblas-Windows-AMD64.dll
new file mode 100644
index 0000000..a39d40c
--- /dev/null
+++ b/src/main/cpp/lib/libsystemds_openblas-Windows-AMD64.dll
Binary files differ
diff --git a/src/main/cpp/lib/systemds_mkl-Windows-AMD64.dll b/src/main/cpp/lib/systemds_mkl-Windows-AMD64.dll
deleted file mode 100644
index 4723e26..0000000
--- a/src/main/cpp/lib/systemds_mkl-Windows-AMD64.dll
+++ /dev/null
Binary files differ
diff --git a/src/main/cpp/lib/systemds_openblas-Windows-AMD64.dll b/src/main/cpp/lib/systemds_openblas-Windows-AMD64.dll
deleted file mode 100644
index 5e16569..0000000
--- a/src/main/cpp/lib/systemds_openblas-Windows-AMD64.dll
+++ /dev/null
Binary files differ
diff --git a/src/main/java/org/apache/sysds/utils/NativeHelper.java b/src/main/java/org/apache/sysds/utils/NativeHelper.java
index 59fd243..36ec816 100644
--- a/src/main/java/org/apache/sysds/utils/NativeHelper.java
+++ b/src/main/java/org/apache/sysds/utils/NativeHelper.java
@@ -146,7 +146,20 @@
LOG.info("Unsupported architecture for native BLAS:" + SystemUtils.OS_ARCH);
return false;
}
-
+
+ /**
+ * Note: we only support Windows and Linux at the moment.
+ *
+ * @return true if operating system is supported
+ */
+ private static boolean isSupportedOS() {
+ if(SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_WINDOWS) {
+ return true;
+ }
+ LOG.info("Unsupported architecture for native BLAS:" + SystemUtils.OS_ARCH);
+ return false;
+ }
+
/**
* Check if native BLAS libraries have been successfully loaded
* @return true if CURRENT_NATIVE_BLAS_STATE is SUCCESSFULLY_LOADED_NATIVE_BLAS_AND_IN_USE or
@@ -173,11 +186,12 @@
// Performing loading in a method instead of a static block will throw a detailed stack trace in case of fatal errors
private static void performLoading(String customLibPath, String userSpecifiedBLAS) {
if((customLibPath != null) && customLibPath.equalsIgnoreCase("none"))
- customLibPath = null;
+ customLibPath = null;
// attemptedLoading variable ensures that we don't try to load SystemDS and other dependencies
// again and again especially in the parfor (hence the double-checking with synchronized).
- if(shouldReload(customLibPath) && isSupportedBLAS(userSpecifiedBLAS) && isSupportedArchitecture()) {
+ if(shouldReload(customLibPath) && isSupportedBLAS(userSpecifiedBLAS) && isSupportedArchitecture()
+ && isSupportedOS()) {
long start = System.nanoTime();
synchronized(NativeHelper.class) {
if(shouldReload(customLibPath)) {
@@ -188,23 +202,16 @@
blas = new String[] { "mkl", "openblas" };
}
- if(SystemUtils.IS_OS_WINDOWS) {
- if (checkAndLoadBLAS(customLibPath, blas) &&
- (loadLibraryHelper("systemds_" + blasType + "-Windows-AMD64") ||
- loadBLAS(customLibPath, "systemds_" + blasType + "-Windows-AMD64", null))
- )
+ if(checkAndLoadBLAS(customLibPath, blas)) {
+ String platform_suffix = (SystemUtils.IS_OS_WINDOWS ? "-Windows-AMD64.dll" : "-Linux-x86_64.so");
+ String library_name = "libsystemds_" + blasType + platform_suffix;
+ if(loadLibraryHelperFromResource(library_name) ||
+ loadBLAS(customLibPath, library_name,"Loading native helper with customLibPath."))
{
LOG.info("Using native blas: " + blasType + getNativeBLASPath());
CURRENT_NATIVE_BLAS_STATE = NativeBlasState.SUCCESSFULLY_LOADED_NATIVE_BLAS_AND_IN_USE;
}
}
- else {
- if (checkAndLoadBLAS(customLibPath, blas) &&
- loadLibraryHelper("libsystemds_" + blasType + "-Linux-x86_64.so")) {
- LOG.info("Using native blas: " + blasType + getNativeBLASPath());
- CURRENT_NATIVE_BLAS_STATE = NativeBlasState.SUCCESSFULLY_LOADED_NATIVE_BLAS_AND_IN_USE;
- }
- }
}
}
double timeToLoadInMilliseconds = (System.nanoTime()-start)*1e-6;
@@ -212,8 +219,8 @@
LOG.warn("Time to load native blas: " + timeToLoadInMilliseconds + " milliseconds.");
}
else if(LOG.isDebugEnabled() && !isSupportedBLAS(userSpecifiedBLAS)) {
- LOG.debug("Using internal Java BLAS as native BLAS support the configuration 'sysds.native.blas'=" +
- userSpecifiedBLAS + ".");
+ LOG.debug("Using internal Java BLAS as native BLAS support instead of the configuration " +
+ "'sysds.native.blas'=" + userSpecifiedBLAS + ".");
}
}
@@ -223,15 +230,19 @@
boolean isLoaded = false;
for (String blas : listBLAS) {
- if (blas.equalsIgnoreCase("mkl")) {
- isLoaded = loadBLAS(customLibPath, "mkl_rt", null);
- } else if (blas.equalsIgnoreCase("openblas")) {
- // no need for gomp on windows
- if (SystemUtils.IS_OS_WINDOWS || loadBLAS(customLibPath, "gomp",
- "gomp required for loading OpenBLAS-enabled SystemDS library")) {
- isLoaded = loadBLAS(customLibPath, "openblas", null);
- }
+ if (blas.equalsIgnoreCase("mkl"))
+ isLoaded = loadBLAS(customLibPath, "mkl_rt", "");
+ else if (blas.equalsIgnoreCase("openblas")) {
+ // OpenBLAS 0.3.10 binary distribution [1] for windows comes with a libopenblas.dll, so let's try this
+ // first. Make sure the directory of that dll is on your PATH env var or pointed to by customLibPath.
+ // [1] https://github.com/xianyi/OpenBLAS/releases
+ isLoaded = loadBLAS(customLibPath, "libopenblas", "");
+ if(!isLoaded)
+ isLoaded = loadBLAS(customLibPath, "openblas", "");
}
+ else
+ LOG.warn("Not trying to load unknown blas type " + blas);
+
if (isLoaded) {
blasType = blas;
break;
@@ -288,13 +299,13 @@
String libPath = customLibPath + File.separator + System.mapLibraryName(blas);
try {
System.load(libPath);
- // Print to stdout as this feature is intended for cloud environment
- System.out.println("Loaded the library:" + libPath);
+ LOG.info("Loaded the library:" + libPath);
return true;
}
- catch (UnsatisfiedLinkError e1) {
- // Print to stdout as this feature is intended for cloud environment
- System.out.println("Unable to load " + libPath + ":" + e1.getMessage());
+ catch (UnsatisfiedLinkError e) {
+ LOG.warn("Unable to load " + blas + " from " + libPath +
+ ". Trying once more with System.loadLibrary(" + blas +
+ ") \n Message from exception was: " + e.getMessage());
}
}
@@ -304,22 +315,25 @@
return true;
}
catch (UnsatisfiedLinkError e) {
- System.out.println(System.getProperty("java.library.path"));
- if(optionalMsg != null)
- LOG.debug("Unable to load " + blas + "(" + optionalMsg + "):" + e.getMessage());
- else
- LOG.debug("Unable to load " + blas + ":" + e.getMessage());
+ LOG.debug("java.library.path: " + System.getProperty("java.library.path"));
+ LOG.debug("Unable to load " + blas + (optionalMsg == null ? "" : (" (" + optionalMsg + ")")) +
+ " \n Message from exception was: " + e.getMessage());
return false;
}
}
-
- private static boolean loadLibraryHelper(String path) {
+ /**
+ * Attempts to load the JNI shared library from the sysds jar
+ *
+ * @param libFileName library file name)
+ * @return true if successfully loaded BLAS
+ */
+ private static boolean loadLibraryHelperFromResource(String libFileName) {
OutputStream out = null;
- try(InputStream in = NativeHelper.class.getResourceAsStream("/lib/"+path)) {
+ try(InputStream in = NativeHelper.class.getResourceAsStream("/lib/"+ libFileName)) {
// This logic is added because Java does not allow to load library from a resource file.
if(in != null) {
- File temp = File.createTempFile(path, "");
+ File temp = File.createTempFile(libFileName, "");
temp.deleteOnExit();
out = FileUtils.openOutputStream(temp);
IOUtils.copy(in, out);
@@ -327,10 +341,10 @@
return true;
}
else
- LOG.warn("No lib available in the jar:" + path);
+ LOG.warn("No lib available in the jar:" + libFileName);
}
catch(IOException e) {
- LOG.warn("Unable to load library " + path + " from resource:" + e.getMessage());
+ LOG.warn("Unable to load library " + libFileName + " from resource:" + e.getMessage());
}
finally {
IOUtilFunctions.closeSilently(out);