Java/C API: Make them Android friendly.
Make the C library and JNI shared library targets Android friendly by linking with the smaller android runtime when building with --config=android Relatedly, strip all but the JNI symbols from libtensorflow_jni.so (regardless of build configuration) to trim its size down (by roughly 50%). Link in the Java libraries in the Android examples. The longer term intention is to encourage use of the TensorFlow Java API in Android and do away with the TensorFlowInferenceInterface class (and related JNI code) currently used in Android. This will provide a single, more thoroughly tested API for use in all Java settings - Android or not. An update to the Android example to switch to this will come in a follow up change. NOTES: - For expediency of this change, the C API call: TF_LoadSessionFromSavedModel is not available when building for Android. I will look into fixing that separately. - Linking in the JNI library required by the TensorFlow Java API results in a small increase (0.7%) in binary size of libtensorflow_demo.so An unrelatedly, rename libtensorflow-jni.so to libtensorflow_jni.so to be consistent with other shared libraries created in tensorflow. Change: 144320074
This commit is contained in:
parent
c4c927cb30
commit
e8f2aad0c0
@ -6,6 +6,7 @@ licenses(["notice"]) # Apache 2.0
|
||||
load(
|
||||
"//tensorflow:tensorflow.bzl",
|
||||
"tf_cc_test",
|
||||
"tf_copts",
|
||||
"tf_cuda_library",
|
||||
"tf_custom_op_library",
|
||||
)
|
||||
@ -23,13 +24,19 @@ tf_cuda_library(
|
||||
name = "c_api",
|
||||
srcs = ["c_api.cc"],
|
||||
hdrs = ["c_api.h"],
|
||||
copts = tf_copts(),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
deps = select({
|
||||
"//tensorflow:android": [
|
||||
"//tensorflow/core:android_tensorflow_lib_lite",
|
||||
],
|
||||
"//conditions:default": [
|
||||
"//tensorflow/cc/saved_model:loader",
|
||||
"//tensorflow/core:core_cpu",
|
||||
"//tensorflow/core:framework",
|
||||
"//tensorflow/core:lib",
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
tf_cuda_library(
|
||||
|
@ -20,7 +20,9 @@ limitations under the License.
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#ifndef __ANDROID__
|
||||
#include "tensorflow/cc/saved_model/loader.h"
|
||||
#endif
|
||||
#include "tensorflow/core/common_runtime/shape_refiner.h"
|
||||
#include "tensorflow/core/framework/log_memory.h"
|
||||
#include "tensorflow/core/framework/node_def_util.h"
|
||||
@ -1709,6 +1711,7 @@ TF_Session* TF_NewSession(TF_Graph* graph, const TF_SessionOptions* opt,
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
TF_Session* TF_LoadSessionFromSavedModel(
|
||||
const TF_SessionOptions* session_options, const TF_Buffer* run_options,
|
||||
const char* export_dir, const char* const* tags, int tags_len,
|
||||
@ -1762,6 +1765,7 @@ TF_Session* TF_LoadSessionFromSavedModel(
|
||||
session->last_num_graph_nodes = graph->graph.num_node_ids();
|
||||
return session;
|
||||
}
|
||||
#endif // __ANDROID__
|
||||
|
||||
void TF_CloseSession(TF_Session* s, TF_Status* status) {
|
||||
status->status = s->session->Close();
|
||||
|
@ -835,6 +835,10 @@ typedef struct TF_Session TF_Session;
|
||||
extern TF_Session* TF_NewSession(TF_Graph* graph, const TF_SessionOptions* opts,
|
||||
TF_Status* status);
|
||||
|
||||
#ifndef __ANDROID__
|
||||
// TODO(ashankar): Remove the __ANDROID__ guard. This will require ensuring that
|
||||
// the tensorflow/cc/saved_model:loader build target is Android friendly.
|
||||
|
||||
// This function creates a new TF_Session (which is created on success) using
|
||||
// `session_options`, and then initializes state (restoring tensors and other
|
||||
// assets) using `run_options`.
|
||||
@ -853,6 +857,7 @@ TF_Session* TF_LoadSessionFromSavedModel(
|
||||
const TF_SessionOptions* session_options, const TF_Buffer* run_options,
|
||||
const char* export_dir, const char* const* tags, int tags_len,
|
||||
TF_Graph* graph, TF_Buffer* meta_graph_def, TF_Status* status);
|
||||
#endif // __ANDROID__
|
||||
|
||||
// Close a session.
|
||||
//
|
||||
|
@ -33,6 +33,7 @@ cc_library(
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//tensorflow/core:android_tensorflow_lib_lite",
|
||||
"//tensorflow/java/src/main/native",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
@ -8,7 +8,7 @@ licenses(["notice"]) # Apache 2.0
|
||||
java_library(
|
||||
name = "tensorflow",
|
||||
srcs = glob(["src/main/java/org/tensorflow/*.java"]),
|
||||
data = [":libtensorflow-jni"],
|
||||
data = [":libtensorflow_jni"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@ -78,18 +78,42 @@ java_test(
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "libtensorflow-jni",
|
||||
name = "libtensorflow_jni",
|
||||
srcs = select({
|
||||
"//tensorflow:darwin": [":libtensorflow-jni.dylib"],
|
||||
"//conditions:default": [":libtensorflow-jni.so"],
|
||||
"//tensorflow:darwin": [":libtensorflow_jni.dylib"],
|
||||
"//conditions:default": [":libtensorflow_jni.so"],
|
||||
}),
|
||||
)
|
||||
|
||||
LINKER_VERSION_SCRIPT = ":config/version_script.lds"
|
||||
|
||||
LINKER_EXPORTED_SYMBOLS = ":config/exported_symbols.lds"
|
||||
|
||||
cc_binary(
|
||||
name = "libtensorflow-jni.so",
|
||||
name = "libtensorflow_jni.so",
|
||||
# Set linker options to strip out anything except the JNI
|
||||
# symbols from the library. This reduces the size of the library
|
||||
# considerably (~50% as of January 2017).
|
||||
linkopts = select({
|
||||
"//tensorflow:darwin": [
|
||||
"-Wl,-exported_symbols_list", # This line must be directly followed by LINKER_EXPORTED_SYMBOLS
|
||||
LINKER_EXPORTED_SYMBOLS,
|
||||
],
|
||||
"//tensorflow:windows": [],
|
||||
"//conditions:default": [
|
||||
"-z defs",
|
||||
"-s",
|
||||
"-Wl,--version-script", # This line must be directly followed by LINKER_VERSION_SCRIPT
|
||||
LINKER_VERSION_SCRIPT,
|
||||
],
|
||||
}),
|
||||
linkshared = 1,
|
||||
linkstatic = 1,
|
||||
deps = ["//tensorflow/java/src/main/native"],
|
||||
deps = [
|
||||
"//tensorflow/java/src/main/native",
|
||||
LINKER_VERSION_SCRIPT,
|
||||
LINKER_EXPORTED_SYMBOLS,
|
||||
],
|
||||
)
|
||||
|
||||
genrule(
|
||||
@ -111,8 +135,8 @@ cc_binary(
|
||||
# is resolved, perhaps this workaround rule can be removed.
|
||||
genrule(
|
||||
name = "darwin-compat",
|
||||
srcs = [":libtensorflow-jni.so"],
|
||||
outs = ["libtensorflow-jni.dylib"],
|
||||
srcs = [":libtensorflow_jni.so"],
|
||||
outs = ["libtensorflow_jni.dylib"],
|
||||
cmd = "cp $< $@",
|
||||
output_to_bindir = 1,
|
||||
)
|
||||
|
@ -37,7 +37,7 @@ Build the Java Archive (JAR) and native library:
|
||||
```sh
|
||||
bazel build -c opt \
|
||||
//tensorflow/java:tensorflow \
|
||||
//tensorflow/java:libtensorflow-jni
|
||||
//tensorflow/java:libtensorflow_jni
|
||||
```
|
||||
|
||||
### Maven
|
||||
@ -86,8 +86,8 @@ bazel run -c opt //tensorflow/java/src/main/java/org/tensorflow/examples:label_i
|
||||
./src/main/java/org/tensorflow/examples/LabelImage.java
|
||||
```
|
||||
|
||||
- Make `libtensorflow.jar` and `libtensorflow-jni.so`
|
||||
(`libtensorflow-jni.dylib` on OS X) available during execution. For example:
|
||||
- Make `libtensorflow.jar` and `libtensorflow_jni.so`
|
||||
(`libtensorflow_jni.dylib` on OS X) available during execution. For example:
|
||||
|
||||
```sh
|
||||
java \
|
||||
|
3
tensorflow/java/config/exported_symbols.lds
Normal file
3
tensorflow/java/config/exported_symbols.lds
Normal file
@ -0,0 +1,3 @@
|
||||
*Java_org_tensorflow_*
|
||||
*JNI_OnLoad
|
||||
*JNI_OnUnload
|
11
tensorflow/java/config/version_script.lds
Normal file
11
tensorflow/java/config/version_script.lds
Normal file
@ -0,0 +1,11 @@
|
||||
VERS_1.0 {
|
||||
# Export JNI symbols.
|
||||
global:
|
||||
Java_*;
|
||||
JNI_OnLoad;
|
||||
JNI_OnUnload;
|
||||
|
||||
# Hide everything else.
|
||||
local:
|
||||
*;
|
||||
};
|
@ -24,7 +24,7 @@ public final class TensorFlow {
|
||||
|
||||
/** Load the TensorFlow runtime C library. */
|
||||
static void init() {
|
||||
System.loadLibrary("tensorflow-jni");
|
||||
System.loadLibrary("tensorflow_jni");
|
||||
}
|
||||
|
||||
static {
|
||||
|
@ -154,7 +154,7 @@ public class LabelImage {
|
||||
}
|
||||
|
||||
// In the fullness of time, equivalents of the methods of this class should be auto-generated from
|
||||
// the OpDefs linked into libtensorflow-jni.so. That would match what is done in other languages
|
||||
// the OpDefs linked into libtensorflow_jni.so. That would match what is done in other languages
|
||||
// like Python, C++ and Go.
|
||||
static class GraphBuilder {
|
||||
GraphBuilder(Graph g) {
|
||||
|
@ -2,26 +2,49 @@
|
||||
# Java Native Interface (JNI) library intended for implementing the
|
||||
# TensorFlow Java API using the TensorFlow C library.
|
||||
|
||||
package(default_visibility = ["//tensorflow/java:__pkg__"])
|
||||
package(default_visibility = [
|
||||
"//tensorflow/java:__pkg__",
|
||||
# TODO(ashankar): Temporary hack for the Java API and
|
||||
# //third_party/tensorflow/contrib/android:android_tensorflow_inference_jni
|
||||
# to co-exist in a single shared library. However, the hope is that
|
||||
# //third_party/tensorflow/contrib/android:android_tensorflow_jni can be
|
||||
# removed once the Java API provides feature parity with it.
|
||||
"//tensorflow/contrib/android:__pkg__",
|
||||
])
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
load("//tensorflow:tensorflow.bzl", "tf_cuda_library")
|
||||
load("//tensorflow:tensorflow.bzl", "tf_cuda_library", "tf_copts")
|
||||
|
||||
tf_cuda_library(
|
||||
name = "native",
|
||||
srcs = glob(["*.cc"]) + [
|
||||
srcs = glob(["*.cc"]) + select({
|
||||
# The Android toolchain makes "jni.h" available in the include path.
|
||||
# For non-Android toolchains, generate jni.h and jni_md.h.
|
||||
"//tensorflow:android": [],
|
||||
"//conditions:default": [
|
||||
":jni.h",
|
||||
":jni_md.h",
|
||||
],
|
||||
}),
|
||||
hdrs = glob(["*.h"]),
|
||||
includes = ["."],
|
||||
copts = tf_copts(),
|
||||
includes = select({
|
||||
"//tensorflow:android": [],
|
||||
"//conditions:default": ["."],
|
||||
}),
|
||||
deps = [
|
||||
"//tensorflow/c:c_api",
|
||||
] + select({
|
||||
"//tensorflow:android": [
|
||||
"//tensorflow/core:android_tensorflow_lib",
|
||||
],
|
||||
"//conditions:default": [
|
||||
"//tensorflow/core:all_kernels",
|
||||
"//tensorflow/core:direct_session",
|
||||
"//tensorflow/core:ops",
|
||||
],
|
||||
}),
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
@ -29,15 +52,11 @@ tf_cuda_library(
|
||||
# #include <jni.h>
|
||||
# in the source headers work
|
||||
# (in combination with the "includes" attribute of the tf_cuda_library rule
|
||||
# above).
|
||||
# above. Not needed when using the Android toolchain).
|
||||
#
|
||||
# Inspired from:
|
||||
# https://github.com/bazelbuild/bazel/blob/f99a0543f8d97339d32075c7176b79f35be84606/src/main/native/BUILD
|
||||
# but hopefully there is a simpler alternative to this.
|
||||
#
|
||||
# TODO(ashankar): This should not be necessary for Android builds as the
|
||||
# toolchain makes <jni.h> available. Perhaps remove ":jni.h" and ":jni_md.h"
|
||||
# from "srcs" and make these genrules a no-op when building for Android?
|
||||
genrule(
|
||||
name = "copy_jni_h",
|
||||
srcs = ["@bazel_tools//tools/jdk:jni_header"],
|
||||
|
@ -14,6 +14,7 @@ limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tensorflow/c/c_api.h"
|
||||
#include "tensorflow/java/src/main/native/exception_jni.h"
|
||||
|
Loading…
Reference in New Issue
Block a user