diff options
-rw-r--r-- | CMakeLists.txt | 32 | ||||
-rw-r--r-- | cmake/GlobalConfig.cmake | 3 | ||||
-rw-r--r-- | delegate/CMakeLists.txt | 8 | ||||
-rw-r--r-- | delegate/armnnDelegateJNI/CMakeLists.txt | 62 | ||||
-rw-r--r-- | delegate/armnnDelegateJNI/README.md | 15 | ||||
-rw-r--r-- | delegate/armnnDelegateJNI/README.md.license | 4 | ||||
-rw-r--r-- | delegate/armnnDelegateJNI/src/armnn_delegate_jni.cpp | 98 | ||||
-rw-r--r-- | delegate/armnnDelegateJNI/version_script | 15 |
8 files changed, 224 insertions, 13 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fcadb0475..c112accdf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,13 +60,6 @@ add_subdirectory(src/armnnSerializer) add_subdirectory(src/armnnDeserializer) add_subdirectory(src/armnnTestUtils) - -if (BUILD_ARMNN_TFLITE_DELEGATE) - set(ARMNN_SUB_PROJECT ON) - add_subdirectory(delegate) - add_definitions(-DARMNN_TF_LITE_DELEGATE) -endif() - if (BUILD_TESTS) add_subdirectory(tests) endif() @@ -443,20 +436,35 @@ foreach(lib ${armnnLibraries}) list(APPEND armnn_sources $<TARGET_OBJECTS:${lib}>) endforeach() +# The delegate needs to be placed after armnnLibraries has been fully populated. The armnn_delegate_jni library +# requires a static armnn build. +# Explanation: +# Because backends are added as object libraries they won't be linked to armnn when building armnn statically. +# A target that uses a static armnn library has to link to the object libraries in the variable armnnLibraries +# manually to include all symbols from backends. +if (BUILD_ARMNN_TFLITE_DELEGATE) + set(ARMNN_SUB_PROJECT ON) + set(ARMNN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + add_subdirectory(delegate) + add_definitions(-DARMNN_TF_LITE_DELEGATE) +endif() + if(BUILD_BARE_METAL) add_library_ex(armnn STATIC ${armnn_sources}) else() - add_library_ex(armnn SHARED ${armnn_sources}) + if (BUILD_SHARED_LIBS) + add_library_ex(armnn SHARED ${armnn_sources}) + else() + add_library(armnn ${armnn_sources}) + endif() endif() target_compile_definitions(armnn PRIVATE "ARMNN_COMPILING_DLL") # Generate a map file for debug mode only -if(CMAKE_BUILD_TYPE MATCHES debug) - set_property(TARGET armnn APPEND_STRING PROPERTY +set_property(TARGET armnn APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-Map=libarmnnMapFile.map") - message(STATUS "Linker will generate mapfile " ) -endif() +message(STATUS "Linker will generate mapfile ") target_include_directories(armnn PUBLIC diff --git a/cmake/GlobalConfig.cmake b/cmake/GlobalConfig.cmake index a5c17d5749..d5cdca2b56 100644 --- a/cmake/GlobalConfig.cmake +++ b/cmake/GlobalConfig.cmake @@ -35,6 +35,9 @@ option(BUILD_PIPE_ONLY "Build the PIPE libraries only" OFF) option(BUILD_ARMNN_TFLITE_DELEGATE "Build the Arm NN TfLite delegate" OFF) option(BUILD_MEMORY_STRATEGY_BENCHMARK "Build the MemoryBenchmark" OFF) option(BUILD_BARE_METAL "Disable features requiring operating system support" OFF) +option(BUILD_SHARED_LIBS "Determines if Armnn will be built statically or dynamically. + This is an experimental feature and not fully supported. + Only the ArmNN core and the Delegate can be built statically." ON) include(SelectLibraryConfigurations) diff --git a/delegate/CMakeLists.txt b/delegate/CMakeLists.txt index 523214bb90..01dde4ebce 100644 --- a/delegate/CMakeLists.txt +++ b/delegate/CMakeLists.txt @@ -54,7 +54,7 @@ list(APPEND armnnDelegate_sources src/Unpack.hpp src/Transpose.hpp) -add_library(armnnDelegate SHARED ${armnnDelegate_sources}) +add_library(armnnDelegate ${armnnDelegate_sources}) target_include_directories(armnnDelegate PUBLIC @@ -254,6 +254,12 @@ if(BUILD_UNIT_TESTS) endif() +option(BUILD_DELEGATE_JNI_INTERFACE "Builds a library to allow accessing the Arm NN delegate from Java code. + This is an experimental feature." Off) +if(BUILD_DELEGATE_JNI_INTERFACE) + add_subdirectory(armnnDelegateJNI) +endif() + #################################################### ## Export targets set(armnn_delegate_export_targets) diff --git a/delegate/armnnDelegateJNI/CMakeLists.txt b/delegate/armnnDelegateJNI/CMakeLists.txt new file mode 100644 index 0000000000..06eb3bf8e3 --- /dev/null +++ b/delegate/armnnDelegateJNI/CMakeLists.txt @@ -0,0 +1,62 @@ +# +# Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +# + +cmake_minimum_required(VERSION 3.7.0) + +project("armnn_delegate_jni") + +# JNI is needed for jni calls +find_package(JNI) + +list(APPEND jni_delegate_sources + src/armnn_delegate_jni.cpp) + +# the backends under src/backends extend the list of +# object libs armnn to include in the build +# If armnn is a static library (which it should be to make armnn_delegate_jni a stand alone library) then +# the object libraries of the backends need to be linked manually +include(${ARMNN_SOURCE_DIR}/src/backends/backends.cmake) +foreach(lib ${armnnLibraries}) + message(STATUS "Adding object library dependency to armnn_delegate_jni: ${lib}") + list(APPEND jni_delegate_sources $<TARGET_OBJECTS:${lib}>) +endforeach() + +if (JNI_FOUND) + message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}") + message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}") +else() + message (FATAL_ERROR "JNI library could not be found") +endif() +include_directories(${JNI_INCLUDE_DIRS}) + +add_library(armnn_delegate_jni SHARED ${jni_delegate_sources}) + +target_include_directories( + armnn_delegate_jni + PUBLIC + ${ARMNN_INCLUDE_DIR} + ${ARMNN_DELEGATE_INCLUDE_DIR} + ${ARMCOMPUTE_INCLUDE} + ) + +target_link_libraries( + armnn_delegate_jni + PRIVATE + Armnn::Armnn + ArmnnDelegate::ArmnnDelegate + ) + +# A version script is used to hide all symbols that are not required to use the jni interface +# This is mostly required to avoid symbol conflicts between libc++_shared used to compile armnn +# and an eventual other version used somewhere else: https://developer.android.com/ndk/guides/cpp-support +# This also requires to tell the compiler to link to the static version of libc++_shared. This can be accomplished +# by adding -DCMAKE_ANDROID_STL_TYPE=c++_static to the cmake command when building for android +set(version_script "${CMAKE_CURRENT_SOURCE_DIR}/version_script") + +# Generate a map file for debug mode only +set_property(TARGET armnn_delegate_jni APPEND_STRING PROPERTY + LINK_FLAGS " -Wl,--version-script=${version_script},-Map=mapfile.map") + +set_target_properties(armnn_delegate_jni PROPERTIES LINK_DEPENDS ${version_script}) diff --git a/delegate/armnnDelegateJNI/README.md b/delegate/armnnDelegateJNI/README.md new file mode 100644 index 0000000000..98ddd54a34 --- /dev/null +++ b/delegate/armnnDelegateJNI/README.md @@ -0,0 +1,15 @@ +# The Arm NN TensorFlow Lite delegate JNI (Experimental) + +NOTE: This library is an experimental feature. We cannot guarentee full support for this. + +'armnnDelegateJNI' is a library for accelerating certain TensorFlow Lite operators on Arm hardware specifically through Android +applications. Each release is packaged in an AAR which can be found on Maven Central. +The pre-built library contains the ArmNN Core, ArmNN Utils, Neon backend, CL Backend, and the ArmNN Delegate. +It is essential to only build these. The backends you choose are optional. + +It requires a static build which can be switched on through setting BUILD_SHARED_LIBS=OFF. You will also have to set +CMAKE_ANDROID_STL_TYPE=c++_static when building ArmNN. + +BUILD_DELEGATE_JNI_INTERFACE will also have to be set to true. + +To download the prebuilt ArmNN Delegate JNI AAR from Maven Central, please go to [ArmNN Maven Central Release Page](https://search.maven.org/artifact/io.github.arm-software/armnn.delegate). diff --git a/delegate/armnnDelegateJNI/README.md.license b/delegate/armnnDelegateJNI/README.md.license new file mode 100644 index 0000000000..ac6973d209 --- /dev/null +++ b/delegate/armnnDelegateJNI/README.md.license @@ -0,0 +1,4 @@ +# +# Copyright © 2022 ARM Ltd and Contributors. All rights reserved. +# SPDX-License-Identifier: MIT +#
\ No newline at end of file diff --git a/delegate/armnnDelegateJNI/src/armnn_delegate_jni.cpp b/delegate/armnnDelegateJNI/src/armnn_delegate_jni.cpp new file mode 100644 index 0000000000..55cc066023 --- /dev/null +++ b/delegate/armnnDelegateJNI/src/armnn_delegate_jni.cpp @@ -0,0 +1,98 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include <armnn_delegate.hpp> +#include <DelegateOptions.hpp> + +#if defined(ARMCOMPUTECL_ENABLED) +#include <arm_compute/core/CL/OpenCL.h> +#endif + +#include <jni.h> +#include <string> + +extern "C" { + +/// Creates an Arm NN Delegate object. +/// Options are passed in form of String arrays. For details about what options_keys and option_values +/// are supported please see: +// armnnDelegate::DelegateOptions::DelegateOptions(char const* const*, char const* const*,size_t,void (*)(const char*)) +JNIEXPORT jlong +JNICALL Java_com_arm_armnn_delegate_ArmnnDelegate_createDelegate(JNIEnv* env, + jclass clazz, + jobjectArray optionKeys, + jobjectArray optionValues) +{ + int numOptions = env->GetArrayLength(optionKeys); + const char* nativeOptionKeys[numOptions]; + const char* nativeOptionValues[numOptions]; + + jstring jKeyStrings[numOptions]; + jstring jValueStrings[numOptions]; + + // Convert java array of string into char so we can make use of it in cpp code + for (int i = 0; i < numOptions; i++) + { + jKeyStrings[i] = static_cast<jstring>(env->GetObjectArrayElement(optionKeys, i)); + jValueStrings[i] = static_cast<jstring>(env->GetObjectArrayElement(optionValues, i)); + + nativeOptionKeys[i] = env->GetStringUTFChars(jKeyStrings[i], 0); + nativeOptionValues[i] = env->GetStringUTFChars(jValueStrings[i], 0); + } + + armnnDelegate::DelegateOptions delegateOptions(nativeOptionKeys, + nativeOptionValues, + numOptions, + nullptr); + + // Release jni memory. After the delegate options are created there is no need to hold on to it anymore. + for (int i = 0; i < numOptions; i++) + { + env->ReleaseStringUTFChars(jKeyStrings[i], nativeOptionKeys[i]); + env->ReleaseStringUTFChars(jValueStrings[i], nativeOptionValues[i]); + } + + return reinterpret_cast<jlong>(armnnDelegate::TfLiteArmnnDelegateCreate(delegateOptions)); +} + +/// Destroys a given Arm NN Delegate object +JNIEXPORT void +JNICALL Java_com_arm_armnn_delegate_ArmnnDelegate_deleteDelegate(JNIEnv* env, jclass clazz, jlong delegate) +{ + armnnDelegate::TfLiteArmnnDelegateDelete(reinterpret_cast<TfLiteDelegate*>(delegate)); +} + +/// Returns true if a Arm Mali GPU is detected. +/// Can be used to ensure that GpuAcc is supported on a device. +JNIEXPORT jboolean +JNICALL Java_com_arm_armnn_delegate_ArmnnUtils_IsGpuAccSupported(JNIEnv* env, jclass clazz) +{ +#if defined(ARMCOMPUTECL_ENABLED) + cl::Device device = cl::Device::getDefault(); + char device_name[32]; + cl_int err = clGetDeviceInfo(device.get(), CL_DEVICE_NAME, sizeof(device_name), &device_name, NULL); + if (err != CL_SUCCESS) + { + return false; + } + // search for "Mali" in the devices name + if (strstr(device_name, "Mali")) + { + return true; + } +#endif + return false; +} + +/// Returns true if the current device supports Neon instructions. +/// Can be used to ensure the CpuAcc backend is supported. +JNIEXPORT jboolean +JNICALL Java_com_arm_armnn_delegate_ArmnnUtils_IsNeonDetected(JNIEnv* env, jclass clazz) +{ + return armnn::NeonDetected(); +} + +} + diff --git a/delegate/armnnDelegateJNI/version_script b/delegate/armnnDelegateJNI/version_script new file mode 100644 index 0000000000..8dc044e494 --- /dev/null +++ b/delegate/armnnDelegateJNI/version_script @@ -0,0 +1,15 @@ +/* + Copyright © 2022 Arm Ltd and Contributors. All rights reserved. + SPDX-License-Identifier: MIT +*/ + +LIBARMNN_DELEGATE_JNI { +global: + Java_com_arm_armnn_delegate_ArmnnDelegate_createDelegate; + Java_com_arm_armnn_delegate_ArmnnDelegate_deleteDelegate; + Java_com_arm_armnn_delegate_ArmnnUtils_IsGpuAccSupported; + Java_com_arm_armnn_delegate_ArmnnUtils_IsNeonDetected; +local: + *; + +};
\ No newline at end of file |