提交 e8f2aad0 编写于 作者: A Asim Shankar 提交者: TensorFlower Gardener

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
上级 c4c927cb
......@@ -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 = [
"//tensorflow/cc/saved_model:loader",
"//tensorflow/core:core_cpu",
"//tensorflow/core:framework",
"//tensorflow/core:lib",
],
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 \
......
*Java_org_tensorflow_*
*JNI_OnLoad
*JNI_OnUnload
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"]) + [
":jni.h",
":jni_md.h",
],
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",
"//tensorflow/core:all_kernels",
"//tensorflow/core:direct_session",
"//tensorflow/core:ops",
],
] + 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"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册