diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3dad41a88c8212..db4b1581ae671b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,5 +1,16 @@
# Contributing guidelines
+## Pull Request Checklist
+
+Before sending your pull requests, make sure you followed this list.
+
+- Read [contributing guidelines](CONTRIBUTING.md).
+- Read [Code of Conduct](CODE_OF_CONDUCT.md).
+- Ensure you have signed the [Contributor License Agreement (CLA)](https://cla.developers.google.com/).
+- Check if my changes are consistent with the [guidelines](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md#general-guidelines-and-philosophy-for-contribution).
+- Changes are consistent with the [Coding Style](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md#c-coding-style).
+- Run [Unit Tests](https://github.com/tensorflow/tensorflow/blob/master/CONTRIBUTING.md#running-unit-tests).
+
## How to become a contributor and submit your own code
### Contributor License Agreements
@@ -79,7 +90,7 @@ Bazel BUILD files also need to include a license section, e.g.,
Changes to TensorFlow C++ code should conform to
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html).
-Use `clang-tidy` to check your C/C++ changes. To install clang-tidy on ubuntu:16.04, do:
+Use `clang-tidy` to check your C/C++ changes. To install `clang-tidy` on ubuntu:16.04, do:
```bash
apt-get install -y clang-tidy
diff --git a/README.md b/README.md
index e1a50c87e26d49..6fb4486d0de9ff 100644
--- a/README.md
+++ b/README.md
@@ -5,9 +5,9 @@
-----------------
-| **`Documentation`** | **`Linux CPU`** | **`Linux GPU`** | **`Mac OS CPU`** | **`Windows CPU`** | **`Android`** |
-|-----------------|---------------------|------------------|-------------------|---------------|---------------|
-| [](https://www.tensorflow.org/api_docs/) |  |  |  | [](https://ci.tensorflow.org/job/tensorflow-master-win-cmake-py) | [](https://ci.tensorflow.org/job/tensorflow-master-android) [  ](https://bintray.com/google/tensorflow/tensorflow/_latestVersion)
+| **`Documentation`** |
+|-----------------|
+| [](https://www.tensorflow.org/api_docs/) |
**TensorFlow** is an open source software library for numerical computation using
data flow graphs. The graph nodes represent mathematical operations, while
@@ -40,15 +40,6 @@ environment to install the nightly TensorFlow build. We support CPU and GPU
packages on Linux, Mac, and Windows.
-**Individual whl files**
-* Linux CPU-only: [Python 2](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=cpu-slave/)) / [Python 3.4](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=cpu-slave/)) / [Python 3.5](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=cpu-slave/)) / [Python 3.6](http://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.6,label=cpu-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-cp36-cp36m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.6,label=cpu-slave/))
-* Linux GPU: [Python 2](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/42/artifact/pip_test/whl/tf_nightly_gpu-1.head-cp27-none-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=gpu-linux/)) / [Python 3.4](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly_gpu-1.head-cp34-cp34m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=gpu-linux/)) / [Python 3.5](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly_gpu-1.head-cp35-cp35m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.5,label=gpu-linux/)) / [Python 3.6](http://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.6,label=gpu-linux/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly_gpu-1.head-cp36-cp36m-linux_x86_64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-linux/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3.6,label=gpu-linux/))
-* Mac CPU-only: [Python 2](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-mac/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-py2-none-any.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-mac/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON2,label=mac-slave/)) / [Python 3](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-mac/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac-slave/lastSuccessfulBuild/artifact/pip_test/whl/tf_nightly-1.head-py3-none-any.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-mac/TF_BUILD_IS_OPT=OPT,TF_BUILD_IS_PIP=PIP,TF_BUILD_PYTHON_VERSION=PYTHON3,label=mac-slave/))
-* Windows CPU-only: [Python 3.5 64-bit](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows,PY=35/lastSuccessfulBuild/artifact/cmake_build/tf_python/dist/tf_nightly-1.head-cp35-cp35m-win_amd64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows,PY=35/)) / [Python 3.6 64-bit](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows,PY=36/lastSuccessfulBuild/artifact/cmake_build/tf_python/dist/tf_nightly-1.head-cp36-cp36m-win_amd64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows,PY=36/))
-* Windows GPU: [Python 3.5 64-bit](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows-gpu,PY=35/lastSuccessfulBuild/artifact/cmake_build/tf_python/dist/tf_nightly_gpu-1.head-cp35-cp35m-win_amd64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows-gpu,PY=35/)) / [Python 3.6 64-bit](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows-gpu,PY=36/lastSuccessfulBuild/artifact/cmake_build/tf_python/dist/tf_nightly_gpu-1.head-cp36-cp36m-win_amd64.whl) ([build history](https://ci.tensorflow.org/view/tf-nightly/job/tf-nightly-windows/M=windows-gpu,PY=36/))
-* Android: [demo APK](https://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild/artifact/out/tensorflow_demo.apk), [native libs](https://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild/artifact/out/native/)
-([build history](https://ci.tensorflow.org/view/Nightly/job/nightly-android/))
-
#### *Try your first TensorFlow program*
```shell
$ python
@@ -82,6 +73,30 @@ The TensorFlow project strives to abide by generally accepted best practices in
[](https://bestpractices.coreinfrastructure.org/projects/1486)
+
+## Continuous build status
+
+### Official Builds
+
+| Build Type | Status | Artifacts |
+| --- | --- | --- |
+| **Linux CPU** |  | [pypi](https://pypi.org/project/tf-nightly/) |
+| **Linux GPU** |  | [pypi](https://pypi.org/project/tf-nightly-gpu/) |
+| **Linux XLA** | TBA | TBA |
+| **MacOS** |  | [pypi](https://pypi.org/project/tf-nightly/) |
+| **Windows CPU** | [](https://ci.tensorflow.org/job/tensorflow-master-win-cmake-py) | [pypi](https://pypi.org/project/tf-nightly/) |
+| **Windows GPU** | [](http://ci.tensorflow.org/job/tf-master-win-gpu-cmake/) | [pypi](https://pypi.org/project/tf-nightly-gpu/) |
+| **Android** | [](https://ci.tensorflow.org/job/tensorflow-master-android) | [](https://bintray.com/google/tensorflow/tensorflow/_latestVersion) [demo APK](https://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild/artifact/out/tensorflow_demo.apk), [native libs](https://ci.tensorflow.org/view/Nightly/job/nightly-android/lastSuccessfulBuild/artifact/out/native/) [build history](https://ci.tensorflow.org/view/Nightly/job/nightly-android/) |
+
+
+### Community Supported Builds
+
+| Build Type | Status | Artifacts |
+| --- | --- | --- |
+| **IBM s390x** | [](http://ibmz-ci.osuosl.org/job/TensorFlow_IBMZ_CI/) | TBA |
+| **IBM ppc64le CPU** | [](http://powerci.osuosl.org/job/TensorFlow_Ubuntu_16.04_CPU/) | TBA |
+
+
## For more information
* [TensorFlow Website](https://www.tensorflow.org)
diff --git a/RELEASE.md b/RELEASE.md
index 2717c75740aeea..27f73b7fc6a524 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -6,7 +6,7 @@
* Added Gradient Boosted Trees as pre-made Estimators: BoostedTreesClassifier, BoostedTreesRegressor.
* Add 3rd generation pipeline config for Cloud TPUs which improves performance and usability.
* `tf.contrib.bayesflow` is moving out to it's own repo.
-* Added `tf.contrib.{proto,rpc}` to allow generic proto parsing and RPC communication.
+* Added `tf.contrib.{proto,rpc}` to allow generic proto parsing and RPC communication[1](#rpc-issue).
## Bug Fixes and Other Changes
* `tf.data`:
@@ -49,13 +49,14 @@
* Fix non-uniformity of orthogonal matrices.
* Fix bug where multi-image Estimator eval summaries were not displayed correctly.
+1 The cancellation logic of the RPC op contains a concurrency error. A fix has been submitted to master and will be part of the next release.
+
## Thanks to our Contributors
This release contains contributions from many people at Google, as well as:
4d55397500, Aghasy, Alan Du, Alan Lee, Alan Yee, Alex Wiltschko, Animesh Karnewar, Ankit Gupta, Anton Matosov, Aris L, Ben Barsdell, Brent Yi, Brett Koonce, Carl Thomé, cbockman, Chikanaga Tomoyuki, Chris Tava, CéDric Deltheil, Dahan Gong, Dalmo Cirne, Daniel Erenrich, David Norman, DavidNorman, Edd Wilder-James, Fanjin Zeng, Felix Abecassis, fo40225, George Sterpu, Giovanni Terlingen, Gor Baghdasaryan, Guillaume Klein, Hanchen Li, Ilya Polenov, Jakub Kolodziejczyk, Jason Sadler, Jayaram Bobba, Jerry Liu, jinghuangintel, Jiongyan Zhang (张炯衍), Joel Shor, Jong Wook Kim, Julian Eisenschlos, Karl Lessard, Krish Ravindranath, Loo Rong Jie, Lukas Geiger, Luke Iwanski, Mahmoud Abuzaina, ManHyuk, Marvin Richter, Maximilian Mitchell, Mohammad Ashraf Bhuiyan, msofka, Mustafa Kasap, Nathan Burnham, Nathan Luehr, Naveen Marri, ngc92, nio1814, Oleg Zabluda, Ou Changkun, Panos Ipeirotis, Paul Van Eck, Peter Lee, Piotr Czapla, qjivy, Rholais Lii, Rodrigo Formigone, Russell Klopfer, ryantimjohn, Sang Han, SebastiáN RamíRez, shengfuintel, Siby Jose Plathottam, Silver Chan, Stanislaw Antol, Taehoon Lee, Tarang Chugh, Ted Chang, Thomas Bastiani, Xian Xu, Xiaoming (Jason) Cui, Yan Facai (颜发才), yaox12, Yashal Shakti Kanungo, Yong Tang, Yuan (Terry) Tang, Yuxin Wu, Ziyue(Louis) Lu
-
# Release 1.7.0
## Major Features And Improvements
@@ -235,7 +236,7 @@ Yoni Tsafir, yordun, Yuan (Terry) Tang, Yuxin Wu, zhengdi, Zhengsheng Wei, 田
* Add `complex64` support to XLA compiler.
* `bfloat` support is now added to XLA infrastructure.
* Make `ClusterSpec` propagation work with XLA devices.
- * Use a determinisitic executor to generate XLA graph.
+ * Use a deterministic executor to generate XLA graph.
* `tf.contrib`:
* `tf.contrib.distributions`:
* Add `tf.contrib.distributions.Autoregressive`.
@@ -403,14 +404,6 @@ answered questions, and were part of inspiring discussions.
# Release 1.4.0
-## Major Features And Improvements
-* `tf.keras` is now part of the core TensorFlow API.
-* [`tf.data`](http://tensorflow.org/programmers_guide/datasets) is now part of
- the core TensorFlow API.
- * The API is now subject to backwards compatibility guarantees.
-
-# Release 1.4.0
-
## Major Features And Improvements
* `tf.keras` is now part of the core TensorFlow API.
* [`tf.data`](http://tensorflow.org/programmers_guide/datasets) is now part of
diff --git a/SECURITY.md b/SECURITY.md
index a5ce3a62ee202f..0a4be37cbc2066 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -168,12 +168,12 @@ below).
Please use a descriptive subject line for your report email. After the initial
reply to your report, the security team will endeavor to keep you informed of
-the progress being made towards a fix and announcement.
+the progress being made towards a fix and announcement.
In addition, please include the following information along with your report:
* Your name and affiliation (if any).
-* A description the technical details of the vulnerabilities. It is very
+* A description of the technical details of the vulnerabilities. It is very
important to let us know how we can reproduce your findings.
* An explanation who can exploit this vulnerability, and what they gain when
doing so -- write an attack scenario. This will help us evaluate your report
@@ -246,5 +246,8 @@ v//Fw6ZeY+HmRDFdirjD7wXtIuER4vqCryIqR6Xe9X8oJXz9L/Jhslc=
| Type | Versions affected | Reported by | Additional Information |
|--------------------|:-----------------:|-----------------------|-----------------------------|
+| TensorFlow Lite TOCO FlatBuffer Parsing Vulnerability | <= 1.7 | Blade Team of Tencent | [security advisory](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/docs_src/security/advisory/tfsa-2018-003.md) |
+| GIF File Parsing Null Pointer Dereference Error | <= 1.5 | Blade Team of Tencent | [security advisory](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/docs_src/security/advisory/tfsa-2018-002.md) |
+| BMP File Parser Out-of-bounds Read | <= 1.6 | Blade Team of Tencent | [security advisory](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/docs_src/security/advisory/tfsa-2018-001.md) |
| Out Of Bounds Read | <=1.4 | Blade Team of Tencent | [issue report](https://github.com/tensorflow/tensorflow/issues/14959) |
diff --git a/WORKSPACE b/WORKSPACE
index 4ddfb9a3832ea1..fd7570a80ae2ee 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -22,26 +22,10 @@ check_bazel_version_at_least("0.10.0")
load("//tensorflow:workspace.bzl", "tf_workspace")
-# Uncomment and update the paths in these entries to build the Android demo.
-#android_sdk_repository(
-# name = "androidsdk",
-# api_level = 23,
-# # Ensure that you have the build_tools_version below installed in the
-# # SDK manager as it updates periodically.
-# build_tools_version = "26.0.1",
-# # Replace with path to Android SDK on your system
-# path = "",
-#)
-#
-#android_ndk_repository(
-# name="androidndk",
-# path="",
-# # This needs to be 14 or higher to compile TensorFlow.
-# # Please specify API level to >= 21 to build for 64-bit
-# # archtectures or the Android NDK will automatically select biggest
-# # API level that it supports without notice.
-# # Note that the NDK version is not the API level.
-# api_level=14)
+load("//third_party/android:android_configure.bzl", "android_configure")
+android_configure(name="local_config_android")
+load("@local_config_android//:android.bzl", "android_workspace")
+android_workspace()
# Please add all new TensorFlow dependencies in workspace.bzl.
tf_workspace()
diff --git a/build b/build
index 25744ada64402a..f8c345d169ee3f 100755
--- a/build
+++ b/build
@@ -11,4 +11,4 @@
pip uninstall -y tensorflow || true
bazel build --config=opt --config=rocm //tensorflow/tools/pip_package:build_pip_package --verbose_failures &&
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg &&
-pip install /tmp/tensorflow_pkg/tensorflow-1.8.0rc1-cp27-cp27mu-linux_x86_64.whl
+pip install /tmp/tensorflow_pkg/tensorflow-1.8.0-cp27-cp27mu-linux_x86_64.whl
diff --git a/build_python3 b/build_python3
index a093bdd4873fe6..b0f6f2318a0b9b 100755
--- a/build_python3
+++ b/build_python3
@@ -11,4 +11,4 @@
pip3 uninstall -y tensorflow || true
bazel build --config=opt --config=rocm //tensorflow/tools/pip_package:build_pip_package --verbose_failures &&
bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg &&
-pip3 install /tmp/tensorflow_pkg/tensorflow-1.8.0rc1-cp35-cp35m-linux_x86_64.whl
+pip3 install /tmp/tensorflow_pkg/tensorflow-1.8.0-cp35-cp35m-linux_x86_64.whl
diff --git a/configure.py b/configure.py
index 4f6fc8e70bc29b..46c637843bc2dd 100644
--- a/configure.py
+++ b/configure.py
@@ -498,10 +498,6 @@ def set_cc_opt_flags(environ_cp):
if not is_ppc64le() and not is_windows():
write_to_bazelrc('build:opt --host_copt=-march=haswell')
write_to_bazelrc('build:opt --define with_default_optimizations=true')
- # TODO(mikecase): Remove these default defines once we are able to get
- # TF Lite targets building without them.
- write_to_bazelrc('build --copt=-DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK')
- write_to_bazelrc('build --host_copt=-DGEMMLOWP_ALLOW_SLOW_SCALAR_FALLBACK')
def set_tf_cuda_clang(environ_cp):
"""set TF_CUDA_CLANG action_env.
@@ -674,8 +670,9 @@ def valid_ndk_path(path):
error_msg=('The path %s or its child file "source.properties" '
'does not exist.')
)
-
- write_android_ndk_workspace_rule(android_ndk_home_path)
+ write_action_env_to_bazelrc('ANDROID_NDK_HOME', android_ndk_home_path)
+ write_action_env_to_bazelrc('ANDROID_NDK_API_LEVEL',
+ check_ndk_level(android_ndk_home_path))
def create_android_sdk_rule(environ_cp):
@@ -737,41 +734,12 @@ def valid_build_tools(version):
error_msg=('The selected SDK does not have build-tools version %s '
'available.'))
- write_android_sdk_workspace_rule(android_sdk_home_path,
- android_build_tools_version,
- android_api_level)
-
-
-def write_android_sdk_workspace_rule(android_sdk_home_path,
- android_build_tools_version,
- android_api_level):
- print('Writing android_sdk_workspace rule.\n')
- with open(_TF_WORKSPACE, 'a') as f:
- f.write("""
-android_sdk_repository(
- name="androidsdk",
- api_level=%s,
- path="%s",
- build_tools_version="%s")\n
-""" % (android_api_level, android_sdk_home_path, android_build_tools_version))
-
-
-def write_android_ndk_workspace_rule(android_ndk_home_path):
- print('Writing android_ndk_workspace rule.')
- ndk_api_level = check_ndk_level(android_ndk_home_path)
- if int(ndk_api_level) not in _SUPPORTED_ANDROID_NDK_VERSIONS:
- print('WARNING: The API level of the NDK in %s is %s, which is not '
- 'supported by Bazel (officially supported versions: %s). Please use '
- 'another version. Compiling Android targets may result in confusing '
- 'errors.\n' % (android_ndk_home_path, ndk_api_level,
- _SUPPORTED_ANDROID_NDK_VERSIONS))
- with open(_TF_WORKSPACE, 'a') as f:
- f.write("""
-android_ndk_repository(
- name="androidndk",
- path="%s",
- api_level=%s)\n
-""" % (android_ndk_home_path, ndk_api_level))
+ write_action_env_to_bazelrc('ANDROID_BUILD_TOOLS_VERSION',
+ android_build_tools_version)
+ write_action_env_to_bazelrc('ANDROID_SDK_API_LEVEL',
+ android_api_level)
+ write_action_env_to_bazelrc('ANDROID_SDK_HOME',
+ android_sdk_home_path)
def check_ndk_level(android_ndk_home_path):
@@ -784,18 +752,16 @@ def check_ndk_level(android_ndk_home_path):
revision = re.search(r'Pkg.Revision = (\d+)', filedata)
if revision:
- return revision.group(1)
- return None
-
-
-def workspace_has_any_android_rule():
- """Check the WORKSPACE for existing android_*_repository rules."""
- with open(_TF_WORKSPACE, 'r') as f:
- workspace = f.read()
- has_any_rule = re.search(r'^android_[ns]dk_repository',
- workspace,
- re.MULTILINE)
- return has_any_rule
+ ndk_api_level = revision.group(1)
+ else:
+ raise Exception('Unable to parse NDK revision.')
+ if int(ndk_api_level) not in _SUPPORTED_ANDROID_NDK_VERSIONS:
+ print('WARNING: The API level of the NDK in %s is %s, which is not '
+ 'supported by Bazel (officially supported versions: %s). Please use '
+ 'another version. Compiling Android targets may result in confusing '
+ 'errors.\n' % (android_ndk_home_path, ndk_api_level,
+ _SUPPORTED_ANDROID_NDK_VERSIONS))
+ return ndk_api_level
def set_gcc_host_compiler_path(environ_cp):
@@ -845,8 +811,8 @@ def reformat_version_sequence(version_str, sequence_count):
def set_tf_cuda_version(environ_cp):
"""Set CUDA_TOOLKIT_PATH and TF_CUDA_VERSION."""
ask_cuda_version = (
- 'Please specify the CUDA SDK version you want to use, '
- 'e.g. 7.0. [Leave empty to default to CUDA %s]: ') % _DEFAULT_CUDA_VERSION
+ 'Please specify the CUDA SDK version you want to use. '
+ '[Leave empty to default to CUDA %s]: ') % _DEFAULT_CUDA_VERSION
for _ in range(_DEFAULT_PROMPT_ASK_ATTEMPTS):
# Configure the Cuda SDK version to use.
@@ -1226,6 +1192,9 @@ def set_tf_cuda_compute_capabilities(environ_cp):
ask_cuda_compute_capabilities, default_cuda_compute_capabilities)
# Check whether all capabilities from the input is valid
all_valid = True
+ # Remove all whitespace characters before splitting the string
+ # that users may insert by accident, as this will result in error
+ tf_cuda_compute_capabilities = ''.join(tf_cuda_compute_capabilities.split())
for compute_capability in tf_cuda_compute_capabilities.split(','):
m = re.match('[0-9]+.[0-9]+', compute_capability)
if not m:
@@ -1428,6 +1397,10 @@ def set_grpc_build_flags():
write_to_bazelrc('build --define grpc_no_ares=true')
+def set_build_strip_flag():
+ write_to_bazelrc('build --strip=always')
+
+
def set_windows_build_flags():
if is_windows():
# The non-monolithic build is not supported yet
@@ -1558,23 +1531,18 @@ def main():
set_grpc_build_flags()
set_cc_opt_flags(environ_cp)
+ set_build_strip_flag()
set_windows_build_flags()
- if workspace_has_any_android_rule():
- print('The WORKSPACE file has at least one of ["android_sdk_repository", '
- '"android_ndk_repository"] already set. Will not ask to help '
- 'configure the WORKSPACE. Please delete the existing rules to '
- 'activate the helper.\n')
- else:
- if get_var(
- environ_cp, 'TF_SET_ANDROID_WORKSPACE', 'android workspace',
- False,
- ('Would you like to interactively configure ./WORKSPACE for '
- 'Android builds?'),
- 'Searching for NDK and SDK installations.',
- 'Not configuring the WORKSPACE for Android builds.'):
- create_android_ndk_rule(environ_cp)
- create_android_sdk_rule(environ_cp)
+ if get_var(
+ environ_cp, 'TF_SET_ANDROID_WORKSPACE', 'android workspace',
+ False,
+ ('Would you like to interactively configure ./WORKSPACE for '
+ 'Android builds?'),
+ 'Searching for NDK and SDK installations.',
+ 'Not configuring the WORKSPACE for Android builds.'):
+ create_android_ndk_rule(environ_cp)
+ create_android_sdk_rule(environ_cp)
print('Preconfigured Bazel build configs. You can use any of the below by '
'adding "--config=<>" to your build command. See tools/bazel.rc for '
diff --git a/tensorflow/BUILD b/tensorflow/BUILD
index 79adbe318c4c64..fb5a52e0c9e44c 100644
--- a/tensorflow/BUILD
+++ b/tensorflow/BUILD
@@ -19,6 +19,10 @@ load(
"//tensorflow/core:platform/default/build_config.bzl",
"tf_additional_binary_deps",
)
+load(
+ "//tensorflow/tools/api/generator:api_gen.bzl",
+ "gen_api_init_files", # @unused
+)
# Config setting for determining if we are building for Android.
config_setting(
@@ -478,7 +482,7 @@ tf_cc_shared_object(
# excludes all but a subset of function names.
# On MacOS, the linker does not support version_script, but has an
# an "-exported_symbols_list" command. -z defs disallows undefined
-# symbols in object files and -s strips the output.
+# symbols in object files.
tf_cc_shared_object(
name = "libtensorflow.so",
@@ -492,7 +496,6 @@ tf_cc_shared_object(
"//tensorflow:windows_msvc": [],
"//conditions:default": [
"-z defs",
- "-s",
"-Wl,--version-script", # This line must be directly followed by the version_script.lds file
"$(location //tensorflow/c:version_script.lds)",
],
@@ -518,7 +521,6 @@ tf_cc_shared_object(
"//tensorflow:windows_msvc": [],
"//conditions:default": [
"-z defs",
- "-s",
"-Wl,--version-script", # This line must be directly followed by the version_script.lds file
"$(location //tensorflow:tf_version_script.lds)",
],
@@ -543,13 +545,16 @@ exports_files(
],
)
+gen_api_init_files(
+ name = "python_api_gen",
+ srcs = ["api_template.__init__.py"],
+ root_init_template = "api_template.__init__.py",
+)
+
py_library(
name = "tensorflow_py",
- srcs = ["__init__.py"],
+ srcs = [":python_api_gen"],
srcs_version = "PY2AND3",
visibility = ["//visibility:public"],
- deps = [
- "//tensorflow/python",
- "//tensorflow/tools/api/generator:python_api",
- ],
+ deps = ["//tensorflow/python"],
)
diff --git a/tensorflow/__init__.py b/tensorflow/__init__.py
index c8683e3976c90a..440e9f8dbd2f4b 100644
--- a/tensorflow/__init__.py
+++ b/tensorflow/__init__.py
@@ -22,9 +22,6 @@
# pylint: disable=g-bad-import-order
from tensorflow.python import pywrap_tensorflow # pylint: disable=unused-import
-# pylint: disable=wildcard-import
-from tensorflow.tools.api.generator.api import * # pylint: disable=redefined-builtin
-# pylint: enable=wildcard-import
from tensorflow.python.util.lazy_loader import LazyLoader
contrib = LazyLoader('contrib', globals(), 'tensorflow.contrib')
diff --git a/tensorflow/api_template.__init__.py b/tensorflow/api_template.__init__.py
new file mode 100644
index 00000000000000..9b0d7d48afd058
--- /dev/null
+++ b/tensorflow/api_template.__init__.py
@@ -0,0 +1,43 @@
+# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed 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.
+# ==============================================================================
+"""Bring in all of the public TensorFlow interface into this module."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+# pylint: disable=g-bad-import-order
+from tensorflow.python import pywrap_tensorflow # pylint: disable=unused-import
+# API IMPORTS PLACEHOLDER
+
+from tensorflow.python.util.lazy_loader import LazyLoader
+contrib = LazyLoader('contrib', globals(), 'tensorflow.contrib')
+del LazyLoader
+
+from tensorflow.python.platform import flags # pylint: disable=g-import-not-at-top
+app.flags = flags # pylint: disable=undefined-variable
+
+del absolute_import
+del division
+del print_function
+
+# These symbols appear because we import the python package which
+# in turn imports from tensorflow.core and tensorflow.python. They
+# must come from this module. So python adds these symbols for the
+# resolution to succeed.
+# pylint: disable=undefined-variable
+del python
+del core
+# pylint: enable=undefined-variable
diff --git a/tensorflow/c/c_api.cc b/tensorflow/c/c_api.cc
index 18eeb2816807ec..b86b277ac3200b 100644
--- a/tensorflow/c/c_api.cc
+++ b/tensorflow/c/c_api.cc
@@ -2097,7 +2097,7 @@ static void GraphImportGraphDefLocked(TF_Graph* graph, const GraphDef& def,
for (int i = 0; i < size; ++i) {
TensorId id = results.missing_unused_input_map_keys[i];
- tf_results->missing_unused_key_names_data.push_back(id.first.ToString());
+ tf_results->missing_unused_key_names_data.push_back(std::string(id.first));
tf_results->missing_unused_key_names[i] =
tf_results->missing_unused_key_names_data.back().c_str();
tf_results->missing_unused_key_indexes[i] = id.second;
diff --git a/tensorflow/c/c_api_experimental.cc b/tensorflow/c/c_api_experimental.cc
index d3916bc16778a9..95b04f9058afdf 100644
--- a/tensorflow/c/c_api_experimental.cc
+++ b/tensorflow/c/c_api_experimental.cc
@@ -8368,3 +8368,90 @@ TF_Operation* TF_MakeFileBasedIteratorGetNextWithDatasets(
return getnext_node;
#endif
}
+
+TF_Tensor* TF_DequeueNamedTensor(TF_Session* session, int tensor_id,
+ TF_Status* status) {
+ assert(session);
+ {
+ tensorflow::mutex_lock c(session->graph->mu);
+ VLOG(1) << "Dequeuing named tensor with id " << tensor_id
+ << ", with input graph: "
+ << session->graph->graph.ToGraphDefDebug().DebugString();
+ }
+
+ TF_Operation* dequeue_op = TF_GraphOperationByName(
+ session->graph,
+ tensorflow::strings::StrCat("fifo_queue_dequeue_", tensor_id).c_str());
+ if (dequeue_op == nullptr) {
+ status->status = tensorflow::errors::Internal(
+ "Unable to find the dequeue node in the TF graph.");
+ return nullptr;
+ }
+
+ VLOG(1) << "Running the dequeue op";
+ TF_Output output{dequeue_op, 0};
+ TF_Tensor* ret;
+ TF_SessionRun(session, /*run_options*/ nullptr,
+ // input related parameters
+ /*inputs*/ nullptr, /*input_values*/ nullptr, /*ninputs*/ 0,
+ // output related parameters
+ /*outputs*/ &output, /*output_values*/ &ret,
+ /*noutputs*/ 1,
+ /*targets*/ nullptr, /*ntargets*/ 0,
+ /*run_metadata*/ nullptr, status);
+ if (VLOG_IS_ON(1) && status->status.ok()) {
+ tensorflow::Tensor tensor;
+ if (tensorflow::TF_TensorToTensor(ret, &tensor).ok()) {
+ VLOG(1) << "Dequeued tensor content: " << tensor.DebugString();
+ }
+ }
+ return ret;
+}
+
+void TF_EnqueueNamedTensor(TF_Session* session, int tensor_id,
+ TF_Tensor* tensor, TF_Status* status) {
+ assert(session);
+ {
+ tensorflow::mutex_lock c(session->graph->mu);
+ if (VLOG_IS_ON(1)) {
+ VLOG(1) << "Enqueuing named tensor with id " << tensor_id
+ << ", with input graph: "
+ << session->graph->graph.ToGraphDefDebug().DebugString();
+ tensorflow::Tensor internal_tensor;
+ if (tensorflow::TF_TensorToTensor(tensor, &internal_tensor).ok()) {
+ VLOG(1) << "Enqueu'ing tensor content: "
+ << internal_tensor.DebugString();
+ }
+ }
+ }
+
+ TF_Operation* enqueue_op = TF_GraphOperationByName(
+ session->graph,
+ tensorflow::strings::StrCat("fifo_queue_enqueue_", tensor_id).c_str());
+ if (enqueue_op == nullptr) {
+ status->status = tensorflow::errors::Internal(
+ "Unable to find the enqueue node in the TF graph.");
+ return;
+ }
+
+ TF_Operation* placeholder_op = TF_GraphOperationByName(
+ session->graph,
+ tensorflow::strings::StrCat("arg_tensor_enqueue_", tensor_id).c_str());
+ if (placeholder_op == nullptr) {
+ status->status = tensorflow::errors::Internal(
+ "Unable to find the placeholder node as input to enqueue in the TF "
+ "graph.");
+ return;
+ }
+
+ VLOG(1) << "Running the enqueue op";
+ TF_Output input{placeholder_op, 0};
+ TF_SessionRun(session, /*run_options*/ nullptr,
+ // input related parameters
+ /*inputs*/ &input, /*input_values*/ &tensor, /*ninputs*/ 1,
+ // output related parameters
+ /*outputs*/ nullptr, /*output_values*/ nullptr, /*noutputs*/ 0,
+ /*targets*/ &enqueue_op, /*ntargets*/ 1,
+ /*run_metadata*/ nullptr, status);
+ VLOG(1) << "Enqueuing is done.";
+}
diff --git a/tensorflow/c/c_api_experimental.h b/tensorflow/c/c_api_experimental.h
index 88cb173cd25f42..20bdace40f1272 100644
--- a/tensorflow/c/c_api_experimental.h
+++ b/tensorflow/c/c_api_experimental.h
@@ -86,6 +86,35 @@ TF_CAPI_EXPORT extern TF_Operation* TF_MakeFileBasedIteratorGetNextWithDatasets(
TF_Graph* graph, const char* file_path, int batch_size,
unsigned char is_mnist, TF_Status* status);
+// On success, dequeues a tensor from a TF-managed FifoQueue given by
+// `tensor_id`, associated with `session`. There must be a graph node named
+// "fifo_queue_dequeue_", to be executed by this API call.
+
+// Caller must call TF_DeleteTensor() over the returned tensor. If the queue is
+// empty, this call is blocked.
+//
+// Tensors are enqueued via the corresponding TF enqueue op.
+// TODO(hongm): Add support for `timeout_ms`.
+TF_CAPI_EXPORT extern TF_Tensor* TF_DequeueNamedTensor(TF_Session* session,
+ int tensor_id,
+ TF_Status* status);
+
+// On success, enqueues `tensor` into a TF-managed FifoQueue given by
+// `tensor_id`, associated with `session`. There must be a graph node named
+// "fifo_queue_enqueue_", to be executed by this API call. It reads
+// from a placeholder node "arg_tensor_enqueue_".
+//
+// `tensor` is still owned by the caller. This call will be blocked if the queue
+// has reached its capacity, and will be unblocked when the queued tensors again
+// drop below the capacity due to dequeuing.
+//
+// Tensors are dequeued via the corresponding TF dequeue op.
+// TODO(hongm): Add support for `timeout_ms`.
+TF_CAPI_EXPORT extern void TF_EnqueueNamedTensor(TF_Session* session,
+ int tensor_id,
+ TF_Tensor* tensor,
+ TF_Status* status);
+
#ifdef __cplusplus
} /* end extern "C" */
#endif
diff --git a/tensorflow/c/c_api_test.cc b/tensorflow/c/c_api_test.cc
index 2762f31e0ccebf..581e5bd1998c73 100644
--- a/tensorflow/c/c_api_test.cc
+++ b/tensorflow/c/c_api_test.cc
@@ -1368,7 +1368,7 @@ TEST(CAPI, SavedModel) {
}
const tensorflow::string input_op_name =
- tensorflow::ParseTensorName(input_name).first.ToString();
+ std::string(tensorflow::ParseTensorName(input_name).first);
TF_Operation* input_op =
TF_GraphOperationByName(graph, input_op_name.c_str());
ASSERT_TRUE(input_op != nullptr);
@@ -1376,7 +1376,7 @@ TEST(CAPI, SavedModel) {
ASSERT_EQ(TF_OK, TF_GetCode(s)) << TF_Message(s);
const tensorflow::string output_op_name =
- tensorflow::ParseTensorName(output_name).first.ToString();
+ std::string(tensorflow::ParseTensorName(output_name).first);
TF_Operation* output_op =
TF_GraphOperationByName(graph, output_op_name.c_str());
ASSERT_TRUE(output_op != nullptr);
diff --git a/tensorflow/c/c_test_util.h b/tensorflow/c/c_test_util.h
index cd19cf8d624d9b..c16aba666ee697 100644
--- a/tensorflow/c/c_test_util.h
+++ b/tensorflow/c/c_test_util.h
@@ -20,6 +20,7 @@ limitations under the License.
#include
#include "tensorflow/core/framework/attr_value.pb.h"
+#include "tensorflow/core/framework/function.pb.h"
#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/node_def.pb.h"
#include "tensorflow/core/framework/types.pb.h"
diff --git a/tensorflow/c/checkpoint_reader.cc b/tensorflow/c/checkpoint_reader.cc
index b1f7bdaa5420a5..74bc25a491ac01 100644
--- a/tensorflow/c/checkpoint_reader.cc
+++ b/tensorflow/c/checkpoint_reader.cc
@@ -125,7 +125,7 @@ CheckpointReader::BuildV2VarMaps() {
const auto& slice_proto = entry.slices(i);
CHECK(filtered_keys
.insert(EncodeTensorNameSlice(
- v2_reader_->key().ToString() /* full var's name */,
+ std::string(v2_reader_->key()) /* full var's name */,
TensorSlice(slice_proto)))
.second);
}
@@ -138,11 +138,11 @@ CheckpointReader::BuildV2VarMaps() {
new TensorSliceReader::VarToDataTypeMap);
v2_reader_->Seek(kHeaderEntryKey);
for (v2_reader_->Next(); v2_reader_->Valid(); v2_reader_->Next()) {
- if (filtered_keys.count(v2_reader_->key().ToString()) > 0) continue;
+ if (filtered_keys.count(std::string(v2_reader_->key())) > 0) continue;
CHECK(entry.ParseFromArray(v2_reader_->value().data(),
v2_reader_->value().size()))
<< entry.InitializationErrorString();
- string key = v2_reader_->key().ToString();
+ string key = std::string(v2_reader_->key());
(*var_to_shape_map)[key] = TensorShape(entry.shape());
(*var_to_data_type_map)[key] = DataType(entry.dtype());
}
diff --git a/tensorflow/c/eager/BUILD b/tensorflow/c/eager/BUILD
index d51f0520ac39d5..f2af81f04c5e1f 100644
--- a/tensorflow/c/eager/BUILD
+++ b/tensorflow/c/eager/BUILD
@@ -14,6 +14,7 @@ tf_gpu_library(
name = "c_api",
srcs = [
"c_api.cc",
+ "c_api_debug.cc",
"c_api_internal.h",
],
hdrs = ["c_api.h"],
@@ -24,10 +25,10 @@ tf_gpu_library(
"//tensorflow/core:android_tensorflow_lib_lite",
],
"//conditions:default": [
- ":runtime",
"//tensorflow/c:c_api",
"//tensorflow/c:c_api_internal",
"//tensorflow/core:core_cpu",
+ "//tensorflow/core/common_runtime/eager:attr_builder",
"//tensorflow/core/common_runtime/eager:context",
"//tensorflow/core/common_runtime/eager:eager_executor",
"//tensorflow/core/common_runtime/eager:execute",
@@ -45,10 +46,22 @@ tf_gpu_library(
"//tensorflow:with_xla_support": [
"//tensorflow/compiler/tf2xla:xla_compiler",
"//tensorflow/compiler/jit",
+ "//tensorflow/compiler/jit:xla_device",
],
"//conditions:default": [],
}) + [
"//tensorflow/core/common_runtime/eager:eager_operation",
+ "//tensorflow/core/distributed_runtime/eager:eager_client",
+ "//tensorflow/core/distributed_runtime/rpc/eager:grpc_eager_client",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_channel",
+ "//tensorflow/core/distributed_runtime/rpc/eager:eager_grpc_server_lib",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_server_lib",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_worker_cache",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_worker_service",
+ "//tensorflow/core/distributed_runtime/rpc:rpc_rendezvous_mgr",
+ "//tensorflow/core/distributed_runtime:remote_device",
+ "//tensorflow/core/distributed_runtime:server_lib",
+ "//tensorflow/core/distributed_runtime:worker_env",
"//tensorflow/core:gpu_runtime",
],
)
@@ -59,7 +72,6 @@ tf_gpu_library(
visibility = ["//tensorflow:internal"],
deps = [
":c_api",
- ":runtime",
"//tensorflow/c:c_api",
"//tensorflow/c:c_api_internal",
"//tensorflow/core:core_cpu",
@@ -69,70 +81,65 @@ tf_gpu_library(
"//tensorflow/core:framework_lite",
"//tensorflow/core:lib",
"//tensorflow/core:lib_internal",
+ "//tensorflow/core/common_runtime/eager:attr_builder",
"//tensorflow/core/common_runtime/eager:context",
"//tensorflow/core/common_runtime/eager:eager_executor",
"//tensorflow/core/common_runtime/eager:eager_operation",
"//tensorflow/core/common_runtime/eager:kernel_and_device",
"//tensorflow/core/common_runtime/eager:tensor_handle",
+ "//tensorflow/core/distributed_runtime:remote_device",
+ "//tensorflow/core/distributed_runtime:server_lib",
+ "//tensorflow/core/distributed_runtime:worker_env",
+ "//tensorflow/core/distributed_runtime/eager:eager_client",
+ "//tensorflow/core/distributed_runtime/eager:remote_tensor_handle",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_channel",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_worker_cache",
+ "//tensorflow/core/distributed_runtime/rpc:grpc_worker_service",
+ "//tensorflow/core/distributed_runtime/rpc:rpc_rendezvous_mgr",
+ "//tensorflow/core/distributed_runtime/rpc/eager:eager_grpc_server_lib",
+ "//tensorflow/core/distributed_runtime/rpc/eager:grpc_eager_client",
],
)
-tf_gpu_cc_test(
- name = "c_api_test",
- srcs = ["c_api_test.cc"],
- extra_copts = tfe_xla_copts(),
- tags = [
- "guitar",
- "multi_gpu",
+tf_gpu_library(
+ name = "c_api_test_util",
+ testonly = 1,
+ srcs = ["c_api_test_util.cc"],
+ hdrs = ["c_api_test_util.h"],
+ visibility = [
+ "//learning/brain:__subpackages__",
+ "//tensorflow:__subpackages__",
],
deps = [
":c_api",
"//tensorflow/c:c_test_util",
+ "//tensorflow/core:framework",
"//tensorflow/core:lib",
"//tensorflow/core:protos_all_cc",
"//tensorflow/core:test",
- "//tensorflow/core:test_main",
],
)
-tf_gpu_library(
- name = "runtime",
- srcs = ["runtime.cc"],
- hdrs = ["runtime.h"],
- copts = tf_copts(),
- visibility = ["//tensorflow:internal"],
- deps = select({
- "//tensorflow:android": [
- "//tensorflow/core:android_tensorflow_lib_lite",
- ],
- "//conditions:default": [
- "//tensorflow/c:c_api",
- "//tensorflow/core:core_cpu",
- "//tensorflow/core/common_runtime/eager:kernel_and_device",
- "//tensorflow/core:core_cpu_internal",
- "//tensorflow/core:framework",
- "//tensorflow/core:framework_internal",
- "//tensorflow/core:lib",
- "//tensorflow/core:lib_internal",
- "//tensorflow/core:protos_all_cc",
- ],
- }),
-)
-
-tf_cc_test(
- name = "runtime_test",
- srcs = ["runtime_test.cc"],
+tf_gpu_cc_test(
+ name = "c_api_test",
+ srcs = [
+ "c_api_debug_test.cc",
+ "c_api_test.cc",
+ ],
+ extra_copts = tfe_xla_copts(),
+ tags = [
+ "guitar",
+ "multi_gpu",
+ ],
deps = [
- ":runtime",
- "//tensorflow/cc:cc_ops",
- "//tensorflow/cc:client_session",
- "//tensorflow/cc:ops",
- "//tensorflow/cc:scope",
- "//tensorflow/core:core_cpu_internal",
- "//tensorflow/core:framework",
+ ":c_api",
+ ":c_api_test_util",
+ "//tensorflow/c:c_test_util",
"//tensorflow/core:lib",
+ "//tensorflow/core:protos_all_cc",
"//tensorflow/core:test",
"//tensorflow/core:test_main",
+ "//tensorflow/core/distributed_runtime/rpc/eager:eager_grpc_server_lib",
],
)
diff --git a/tensorflow/c/eager/c_api.cc b/tensorflow/c/eager/c_api.cc
index 3bf071f3abaac7..81221c4078bec9 100644
--- a/tensorflow/c/eager/c_api.cc
+++ b/tensorflow/c/eager/c_api.cc
@@ -24,7 +24,6 @@ limitations under the License.
#include "tensorflow/c/c_api.h"
#include "tensorflow/c/c_api_internal.h"
#include "tensorflow/c/eager/c_api_internal.h"
-#include "tensorflow/c/eager/runtime.h"
#ifdef TENSORFLOW_EAGER_USE_XLA
#include "tensorflow/compiler/tf2xla/xla_op_registry.h"
#endif // TENSORFLOW_EAGER_USE_XLA
@@ -32,15 +31,22 @@ limitations under the License.
#include "tensorflow/core/common_runtime/device_factory.h"
#include "tensorflow/core/common_runtime/device_mgr.h"
#include "tensorflow/core/common_runtime/device_set.h"
+#include "tensorflow/core/common_runtime/eager/attr_builder.h"
#include "tensorflow/core/common_runtime/eager/copy_to_device_node.h"
#include "tensorflow/core/common_runtime/eager/execute.h"
#include "tensorflow/core/common_runtime/function.h"
#include "tensorflow/core/common_runtime/rendezvous_mgr.h"
+#include "tensorflow/core/distributed_runtime/rpc/eager/eager_grpc_server_lib.h"
+#include "tensorflow/core/distributed_runtime/rpc/eager/grpc_eager_client.h"
+#include "tensorflow/core/distributed_runtime/rpc/grpc_channel.h"
+#include "tensorflow/core/distributed_runtime/server_lib.h"
+#include "tensorflow/core/distributed_runtime/worker_env.h"
#include "tensorflow/core/framework/node_def_util.h"
#include "tensorflow/core/framework/rendezvous.h"
#include "tensorflow/core/framework/tensor_shape.pb.h"
#include "tensorflow/core/framework/types.h"
#include "tensorflow/core/lib/core/refcount.h"
+#include "tensorflow/core/lib/gtl/cleanup.h"
#include "tensorflow/core/lib/gtl/flatmap.h"
#include "tensorflow/core/lib/gtl/map_util.h"
#include "tensorflow/core/lib/gtl/stl_util.h"
@@ -67,10 +73,121 @@ string DeviceName(const tensorflow::Device* d) {
return (d == nullptr) ? "cpu:0" : d->name();
}
-#ifdef TENSORFLOW_EAGER_USE_XLA
-std::atomic_int_fast64_t func_id_generator(0);
-#endif // TENSORFLOW_EAGER_USE_XLA
+tensorflow::Status GetAllRemoteDevices(
+ const std::vector& remote_workers,
+ tensorflow::WorkerCacheInterface* worker_cache,
+ std::unique_ptr* device_mgr) {
+ std::vector remote_devices;
+ tensorflow::Status status;
+ // TODO(nareshmodi) do this in parallel instead of serially.
+ for (const string& remote_worker : remote_workers) {
+ tensorflow::Notification n;
+ tensorflow::NewRemoteDevices(
+ tensorflow::Env::Default(), worker_cache, remote_worker,
+ [&status, &n, &remote_devices](
+ const tensorflow::Status& s,
+ std::vector* devices) {
+ status = s;
+ if (s.ok()) {
+ for (tensorflow::Device* d : *devices) {
+ remote_devices.push_back(d);
+ }
+ }
+ n.Notify();
+ });
+ n.WaitForNotification();
+ }
+ std::unique_ptr remote_device_mgr(
+ new tensorflow::DeviceMgr(remote_devices));
+
+ TF_RETURN_IF_ERROR(status);
+
+ *device_mgr = std::move(remote_device_mgr);
+ return tensorflow::Status::OK();
+}
+
+tensorflow::Status CreateRemoteContexts(
+ const std::vector& remote_workers,
+ tensorflow::eager::EagerClientCache* remote_eager_workers, bool async,
+ tensorflow::gtl::FlatMap* remote_contexts) {
+ for (int i = 0; i < remote_workers.size(); i++) {
+ const string& remote_worker = remote_workers[i];
+
+ tensorflow::eager::CreateContextRequest request;
+ tensorflow::eager::CreateContextResponse response;
+ tensorflow::DeviceNameUtils::ParsedName parsed_name;
+ if (!tensorflow::DeviceNameUtils::ParseFullName(remote_worker,
+ &parsed_name)) {
+ return tensorflow::errors::InvalidArgument(
+ "Unable to parse ", remote_worker, " as a device name");
+ }
+ request.mutable_server_def()->set_job_name(parsed_name.job);
+ request.mutable_server_def()->set_task_index(parsed_name.task);
+ request.set_async(async);
+ auto* eager_client = remote_eager_workers->GetClient(remote_worker);
+ if (eager_client == nullptr) {
+ return tensorflow::errors::Internal(
+ "Cannot find a client for the given target:", remote_worker);
+ }
+ tensorflow::Notification n;
+ tensorflow::Status status;
+ // TODO(nareshmodi) do this in parallel instead of serially.
+ eager_client->CreateContextAsync(
+ &request, &response, [&status, &n](const tensorflow::Status& s) {
+ status = s;
+ n.Notify();
+ });
+ n.WaitForNotification();
+ TF_RETURN_IF_ERROR(status);
+
+ remote_contexts->emplace(remote_worker, response.context_id());
+ }
+ return tensorflow::Status::OK();
+}
+
+tensorflow::Status NewRemoteAwareTFE_Context(const TFE_ContextOptions* opts,
+ TFE_Context** ctx) {
+ string worker_name = tensorflow::strings::StrCat(
+ "/job:", opts->server_def.job_name(),
+ "/replica:0/task:", opts->server_def.task_index());
+ std::unique_ptr server;
+ TF_RETURN_IF_ERROR(
+ tensorflow::eager::EagerGrpcServer::Create(opts->server_def, &server));
+
+ TF_RETURN_IF_ERROR(server->Start());
+
+ std::vector remote_workers;
+ server->master_env()->worker_cache->ListWorkers(&remote_workers);
+ remote_workers.erase(
+ std::remove(remote_workers.begin(), remote_workers.end(), worker_name),
+ remote_workers.end());
+
+ std::unique_ptr remote_device_mgr;
+ TF_RETURN_IF_ERROR(GetAllRemoteDevices(
+ remote_workers, server->master_env()->worker_cache, &remote_device_mgr));
+
+ std::shared_ptr channel_cache =
+ server->channel_cache();
+ std::unique_ptr remote_eager_workers(
+ tensorflow::eager::NewGrpcEagerClientCache(channel_cache));
+ // Initialize remote eager workers.
+ tensorflow::gtl::FlatMap remote_contexts;
+ TF_RETURN_IF_ERROR(CreateRemoteContexts(remote_workers,
+ remote_eager_workers.get(),
+ opts->async, &remote_contexts));
+
+ tensorflow::RemoteRendezvous* r =
+ server->worker_env()->rendezvous_mgr->Find(0);
+
+ auto* device_mgr = server->worker_env()->device_mgr;
+ *ctx = new TFE_Context(opts->session_options.options, opts->policy,
+ opts->async, device_mgr, r, std::move(server),
+ std::move(remote_eager_workers),
+ std::move(remote_device_mgr), remote_contexts);
+
+ return tensorflow::Status::OK();
+}
} // namespace
extern "C" {
@@ -91,6 +208,15 @@ void TFE_ContextOptionsSetDevicePlacementPolicy(
options->policy = policy;
}
+TF_CAPI_EXPORT extern void TFE_ContextOptionsSetServerDef(
+ TFE_ContextOptions* options, const void* proto, size_t proto_len,
+ TF_Status* status) {
+ if (!options->server_def.ParseFromArray(proto, proto_len)) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "Invalid tensorflow.ServerDef protocol buffer");
+ }
+}
+
TF_CAPI_EXPORT extern void TFE_ContextSetAsyncForThread(TFE_Context* ctx,
unsigned char async,
TF_Status* status) {
@@ -100,17 +226,23 @@ TF_CAPI_EXPORT extern void TFE_ContextSetAsyncForThread(TFE_Context* ctx,
void TFE_DeleteContextOptions(TFE_ContextOptions* options) { delete options; }
TFE_Context* TFE_NewContext(const TFE_ContextOptions* opts, TF_Status* status) {
+ if (!opts->server_def.job_name().empty()) {
+ TFE_Context* ctx = nullptr;
+ status->status = NewRemoteAwareTFE_Context(opts, &ctx);
+ return ctx;
+ }
+
std::vector devices;
status->status = tensorflow::DeviceFactory::AddDevices(
opts->session_options.options, "/job:localhost/replica:0/task:0",
&devices);
- if (!status->status.ok()) {
- return nullptr;
- }
+ if (!status->status.ok()) return nullptr;
std::unique_ptr device_mgr(
new tensorflow::DeviceMgr(devices));
+
tensorflow::Rendezvous* r =
new tensorflow::IntraProcessRendezvous(device_mgr.get());
+
return new TFE_Context(opts->session_options.options, opts->policy,
opts->async, std::move(device_mgr), r);
}
@@ -119,7 +251,10 @@ void TFE_DeleteContext(TFE_Context* ctx, TF_Status* status) { delete ctx; }
TF_DeviceList* TFE_ContextListDevices(TFE_Context* ctx, TF_Status* status) {
TF_DeviceList* list = new TF_DeviceList;
- ctx->context.device_mgr()->ListDeviceAttributes(&list->response);
+ ctx->context.local_device_mgr()->ListDeviceAttributes(&list->response);
+ if (ctx->context.remote_device_mgr()) {
+ ctx->context.remote_device_mgr()->ListDeviceAttributes(&list->response);
+ }
return list;
}
diff --git a/tensorflow/c/eager/c_api.h b/tensorflow/c/eager/c_api.h
index c06ce84a8c578a..1862af3ce2f505 100644
--- a/tensorflow/c/eager/c_api.h
+++ b/tensorflow/c/eager/c_api.h
@@ -81,6 +81,16 @@ TF_CAPI_EXPORT extern void TFE_ContextOptionsSetAsync(TFE_ContextOptions*,
TF_CAPI_EXPORT extern void TFE_ContextOptionsSetDevicePlacementPolicy(
TFE_ContextOptions*, TFE_ContextDevicePlacementPolicy);
+// A tensorflow.ServerDef specifies remote workers (in addition to the current
+// workers name). Operations created on this context can then be executed on
+// any of these remote workers by setting an appropriate device.
+//
+// If the following is set, all servers identified by the
+// ServerDef must be up when the context is created.
+TF_CAPI_EXPORT extern void TFE_ContextOptionsSetServerDef(
+ TFE_ContextOptions* options, const void* proto, size_t proto_len,
+ TF_Status* status);
+
// Destroy an options object.
TF_CAPI_EXPORT extern void TFE_DeleteContextOptions(TFE_ContextOptions*);
@@ -181,6 +191,45 @@ TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_TensorHandleCopyToDevice(
TFE_TensorHandle* h, TFE_Context* ctx, const char* device_name,
TF_Status* status);
+// Debugging/Profiling information for TFE_TensorHandle
+//
+// TFE_TensorDebugInfo contains information useful for debugging and
+// profiling tensors.
+typedef struct TFE_TensorDebugInfo TFE_TensorDebugInfo;
+
+// Retrieves TFE_TensorDebugInfo for `handle`.
+// If TFE_TensorHandleTensorDebugInfo succeeds, `status` is set to OK and caller
+// is responsible for deleting returned TFE_TensorDebugInfo.
+// If TFE_TensorHandleTensorDebugInfo fails, `status` is set to appropriate
+// error and nullptr is returned. This function can block till the operation
+// that produces `handle` has completed.
+TF_CAPI_EXPORT extern TFE_TensorDebugInfo* TFE_TensorHandleTensorDebugInfo(
+ TFE_TensorHandle* handle, TF_Status* status);
+
+// Deletes `debug_info`.
+TF_CAPI_EXPORT extern void TFE_DeleteTensorDebugInfo(
+ TFE_TensorDebugInfo* debug_info);
+
+// Returns the number of dimensions used to represent the tensor on its device.
+// The number of dimensions used to reprensent the tensor on device can be
+// different from the number returned by TFE_TensorHandleNumDims.
+// The return value was current at the time of TFE_TensorDebugInfo creation.
+TF_CAPI_EXPORT extern int TFE_TensorDebugInfoOnDeviceNumDims(
+ TFE_TensorDebugInfo* debug_info);
+
+// Returns the number of elements in dimension `dim_index`.
+// Tensor representation on device can be transposed from its representation
+// on host. The data contained in dimension `dim_index` on device
+// can correspond to the data contained in another dimension in on-host
+// representation. The dimensions are indexed using the standard TensorFlow
+// major-to-minor order (slowest varying dimension first),
+// not the XLA's minor-to-major order.
+// On-device dimensions can be padded. TFE_TensorDebugInfoOnDeviceDim returns
+// the number of elements in a dimension after padding.
+// The return value was current at the time of TFE_TensorDebugInfo creation.
+TF_CAPI_EXPORT extern int64_t TFE_TensorDebugInfoOnDeviceDim(
+ TFE_TensorDebugInfo* debug_info, int dim_index);
+
// Description of the TensorFlow op to execute.
//
// Assumes that the provided 'ctx' outlives the returned TFE_Op, i.e.,
diff --git a/tensorflow/c/eager/c_api_debug.cc b/tensorflow/c/eager/c_api_debug.cc
new file mode 100644
index 00000000000000..5006b76f1981d0
--- /dev/null
+++ b/tensorflow/c/eager/c_api_debug.cc
@@ -0,0 +1,167 @@
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed 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.
+==============================================================================*/
+
+#include "tensorflow/c/eager/c_api.h"
+
+#include
+
+#include "tensorflow/c/c_api.h"
+#include "tensorflow/c/eager/c_api_internal.h"
+#ifdef TENSORFLOW_EAGER_USE_XLA
+#include "tensorflow/compiler/jit/xla_device.h"
+#endif // TENSORFLOW_EAGER_USE_XLA
+
+using tensorflow::int64;
+using tensorflow::string;
+
+namespace {
+
+std::vector TensorShapeAsVector(TFE_TensorHandle* handle,
+ TF_Status* status) {
+ std::vector shape;
+ int rank = TFE_TensorHandleNumDims(handle, status);
+ if (!status->status.ok()) {
+ return shape;
+ }
+ shape.reserve(rank);
+ for (int i = 0; i < rank; ++i) {
+ shape.push_back(TFE_TensorHandleDim(handle, i, status));
+ if (!status->status.ok()) {
+ return shape;
+ }
+ }
+ return shape;
+}
+
+} // namespace
+
+extern "C" {
+
+TF_CAPI_EXPORT extern TFE_TensorDebugInfo* TFE_TensorHandleTensorDebugInfo(
+ TFE_TensorHandle* handle, TF_Status* status) {
+ const tensorflow::Tensor* tensor;
+ status->status = handle->handle->Tensor(&tensor);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+
+ tensorflow::Device* device;
+ status->status = handle->handle->Device(&device);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+
+#ifdef TENSORFLOW_EAGER_USE_XLA
+ // If tensor resides on an XLA device, use XLA device's PaddedShapeFn.
+ tensorflow::XlaDevice* xla_device =
+ dynamic_cast(device);
+ if (xla_device != nullptr) {
+ tensorflow::XlaDevice::PaddedShapeFn shape_fn =
+ xla_device->metadata().padded_shape_fn();
+ xla::Shape padded_shape;
+ status->status = shape_fn(*tensor, &padded_shape);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+ if (VLOG_IS_ON(3)) {
+ std::vector shape_to_log = TensorShapeAsVector(handle, status);
+ if (!status->status.ok()) {
+ // Ignore the status here as we are simply logging.
+ status->status = tensorflow::Status::OK();
+ } else {
+ VLOG(3) << "Fully padded shape of ["
+ << tensorflow::str_util::Join(shape_to_log, ", ") << "] is "
+ << padded_shape.DebugString();
+ }
+ }
+
+ if (xla::ShapeUtil::IsTuple(padded_shape)) {
+ if (xla::ShapeUtil::TupleElementCount(padded_shape) != 2) {
+ // Currently, the only case of XlaTensor containing a tuple shape is to
+ // represent 64 bit ints, doubles, and complex numbers (we don't support
+ // 64bit complex numbers).
+ status->status = tensorflow::errors::InvalidArgument(
+ "XlaTensors should only contain tuples of size 2. Shape: ",
+ padded_shape.DebugString());
+ return nullptr;
+ }
+
+ // shape0 is not a const& because we will assign it to padded_shape below.
+ // It is illegal to assign a part of a message to itself.
+ xla::Shape shape0 = xla::ShapeUtil::GetTupleElementShape(padded_shape, 0);
+ const xla::Shape& shape1 =
+ xla::ShapeUtil::GetTupleElementShape(padded_shape, 1);
+ if (xla::ShapeUtil::IsTuple(shape0) || xla::ShapeUtil::IsTuple(shape1)) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "XlaTensors should not contain nested tuples. Shape: ",
+ padded_shape.DebugString());
+ return nullptr;
+ }
+ if (!xla::ShapeUtil::Equal(shape0, shape1)) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "Subshapes of XlaTensors should be the same. Shape: ",
+ padded_shape.DebugString());
+ return nullptr;
+ }
+
+ // Since the only case we handle here are two equal subshapes, we
+ // simply return one of them. The caller will interpret it as this
+ // shape directly storing the 64bit types. This approximation is good
+ // enough for this API's debugging use case.
+ padded_shape = shape0;
+ }
+
+ int rank = padded_shape.dimensions_size();
+ std::vector dev_dims;
+ dev_dims.reserve(rank);
+ if (rank == 1) {
+ // Rank 1 tensors might not have padded_shape.layout.minor_to_major set,
+ dev_dims.push_back(padded_shape.dimensions(0));
+ } else {
+ for (int i = rank - 1; i >= 0; --i) {
+ int64 dim_index = padded_shape.layout().minor_to_major(i);
+ dev_dims.push_back(padded_shape.dimensions(dim_index));
+ }
+ }
+ status->status = tensorflow::Status::OK();
+ return new TFE_TensorDebugInfo(dev_dims);
+ }
+#endif // TENSORFLOW_EAGER_USE_XLA
+
+ // If the tensor is not an XLA tensor, the device shape is
+ // the same as regular tensor shape.
+ std::vector dev_dims = TensorShapeAsVector(handle, status);
+ if (!status->status.ok()) {
+ return nullptr;
+ }
+ return new TFE_TensorDebugInfo(dev_dims);
+}
+
+TF_CAPI_EXPORT extern void TFE_DeleteTensorDebugInfo(
+ TFE_TensorDebugInfo* debug_info) {
+ delete debug_info;
+}
+
+TF_CAPI_EXPORT extern int TFE_TensorDebugInfoOnDeviceNumDims(
+ TFE_TensorDebugInfo* debug_info) {
+ return debug_info->dev_dims.size();
+}
+
+TF_CAPI_EXPORT extern int64_t TFE_TensorDebugInfoOnDeviceDim(
+ TFE_TensorDebugInfo* debug_info, int dim_index) {
+ return debug_info->dev_dims[dim_index];
+}
+
+} // extern "C"
diff --git a/tensorflow/c/eager/c_api_debug_test.cc b/tensorflow/c/eager/c_api_debug_test.cc
new file mode 100644
index 00000000000000..cddb9f6e00e9d6
--- /dev/null
+++ b/tensorflow/c/eager/c_api_debug_test.cc
@@ -0,0 +1,50 @@
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed 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.
+==============================================================================*/
+
+#include "tensorflow/c/eager/c_api.h"
+
+#include
+#include "tensorflow/c/eager/c_api_test_util.h"
+#include "tensorflow/core/platform/logging.h"
+#include "tensorflow/core/platform/test.h"
+
+TEST(CApiDebug, ScalarCPU) {
+ TFE_TensorHandle* h = TestScalarTensorHandle();
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorDebugInfo* debug_info = TFE_TensorHandleTensorDebugInfo(h, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ ASSERT_EQ(0, TFE_TensorDebugInfoOnDeviceNumDims(debug_info));
+
+ TFE_DeleteTensorDebugInfo(debug_info);
+ TFE_DeleteTensorHandle(h);
+ TF_DeleteStatus(status);
+}
+
+TEST(CApiDebug, 2DCPU) {
+ TFE_TensorHandle* h = TestMatrixTensorHandle3X2();
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorDebugInfo* debug_info = TFE_TensorHandleTensorDebugInfo(h, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ ASSERT_EQ(2, TFE_TensorDebugInfoOnDeviceNumDims(debug_info));
+ // Shape is the same for CPU tensors.
+ EXPECT_EQ(3, TFE_TensorDebugInfoOnDeviceDim(debug_info, 0));
+ EXPECT_EQ(2, TFE_TensorDebugInfoOnDeviceDim(debug_info, 1));
+
+ TFE_DeleteTensorDebugInfo(debug_info);
+ TFE_DeleteTensorHandle(h);
+ TF_DeleteStatus(status);
+}
diff --git a/tensorflow/c/eager/c_api_internal.h b/tensorflow/c/eager/c_api_internal.h
index 49e1aab1cef957..04a6efc47c5177 100644
--- a/tensorflow/c/eager/c_api_internal.h
+++ b/tensorflow/c/eager/c_api_internal.h
@@ -28,8 +28,8 @@ limitations under the License.
#include "tensorflow/c/c_api.h"
#include "tensorflow/c/c_api_internal.h"
-#include "tensorflow/c/eager/runtime.h"
#include "tensorflow/core/common_runtime/device_factory.h"
+#include "tensorflow/core/common_runtime/eager/attr_builder.h"
#include "tensorflow/core/common_runtime/eager/context.h"
#include "tensorflow/core/common_runtime/eager/eager_executor.h"
#include "tensorflow/core/common_runtime/eager/eager_operation.h"
@@ -37,6 +37,14 @@ limitations under the License.
#include "tensorflow/core/common_runtime/eager/tensor_handle.h"
#include "tensorflow/core/common_runtime/function.h"
#include "tensorflow/core/common_runtime/rendezvous_mgr.h"
+#include "tensorflow/core/distributed_runtime/eager/eager_client.h"
+#include "tensorflow/core/distributed_runtime/remote_device.h"
+#include "tensorflow/core/distributed_runtime/rpc/eager/eager_grpc_server_lib.h"
+#include "tensorflow/core/distributed_runtime/rpc/grpc_worker_cache.h"
+#include "tensorflow/core/distributed_runtime/rpc/grpc_worker_service.h"
+#include "tensorflow/core/distributed_runtime/rpc/rpc_rendezvous_mgr.h"
+#include "tensorflow/core/distributed_runtime/server_lib.h"
+#include "tensorflow/core/distributed_runtime/worker_env.h"
#include "tensorflow/core/framework/rendezvous.h"
#include "tensorflow/core/lib/core/stringpiece.h"
#include "tensorflow/core/lib/gtl/inlined_vector.h"
@@ -51,6 +59,7 @@ struct TFE_ContextOptions {
// true if async execution is enabled.
bool async = false;
TFE_ContextDevicePlacementPolicy policy{TFE_DEVICE_PLACEMENT_SILENT};
+ tensorflow::ServerDef server_def;
};
struct TFE_Context {
@@ -64,6 +73,23 @@ struct TFE_Context {
default_policy),
async, std::move(device_mgr), rendezvous) {}
+ explicit TFE_Context(
+ const tensorflow::SessionOptions& opts,
+ TFE_ContextDevicePlacementPolicy default_policy, bool async,
+ tensorflow::DeviceMgr* local_device_mgr,
+ tensorflow::Rendezvous* rendezvous,
+ std::unique_ptr server,
+ std::unique_ptr remote_eager_workers,
+ std::unique_ptr remote_device_mgr,
+ const tensorflow::gtl::FlatMap&
+ remote_contexts)
+ : context(opts,
+ static_cast(
+ default_policy),
+ async, local_device_mgr, rendezvous, std::move(server),
+ std::move(remote_eager_workers), std::move(remote_device_mgr),
+ remote_contexts) {}
+
tensorflow::EagerContext context;
};
@@ -81,6 +107,14 @@ struct TFE_TensorHandle {
tensorflow::TensorHandle* handle;
};
+struct TFE_TensorDebugInfo {
+ TFE_TensorDebugInfo(const std::vector& dims)
+ : dev_dims(dims) {}
+
+ // Fully-padded, minor-to-major.
+ std::vector dev_dims;
+};
+
struct TFE_Op {
// t is NULL iff the TFE_Op corresponds to a TensorFlow function instead of a
// primitive operation.
diff --git a/tensorflow/c/eager/c_api_test.cc b/tensorflow/c/eager/c_api_test.cc
index 701175e4943d1d..27ff5f7211b059 100644
--- a/tensorflow/c/eager/c_api_test.cc
+++ b/tensorflow/c/eager/c_api_test.cc
@@ -16,6 +16,8 @@ limitations under the License.
#include "tensorflow/c/eager/c_api.h"
#include
+#include "tensorflow/c/eager/c_api_test_util.h"
+#include "tensorflow/core/distributed_runtime/rpc/eager/eager_grpc_server_lib.h"
#include "tensorflow/core/framework/function.pb.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/logging.h"
@@ -23,128 +25,14 @@ limitations under the License.
#include "tensorflow/core/platform/protobuf.h"
#include "tensorflow/core/platform/test.h"
#include "tensorflow/core/platform/test_benchmark.h"
+#include "tensorflow/core/protobuf/cluster.pb.h"
#include "tensorflow/core/protobuf/config.pb.h"
+#include "tensorflow/core/protobuf/tensorflow_server.pb.h"
using tensorflow::string;
namespace {
-TFE_TensorHandle* DoubleTestMatrixTensorHandle() {
- int64_t dims[] = {2, 2};
- double data[] = {1.0, 2.0, 3.0, 4.0};
- TF_Tensor* t = TF_AllocateTensor(
- TF_DOUBLE, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
- memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
- TF_Status* status = TF_NewStatus();
- TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TF_DeleteTensor(t);
- TF_DeleteStatus(status);
- return th;
-}
-
-TFE_TensorHandle* TestMatrixTensorHandle() {
- int64_t dims[] = {2, 2};
- float data[] = {1.0f, 2.0f, 3.0f, 4.0f};
- TF_Tensor* t = TF_AllocateTensor(
- TF_FLOAT, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
- memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
- TF_Status* status = TF_NewStatus();
- TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TF_DeleteTensor(t);
- TF_DeleteStatus(status);
- return th;
-}
-
-TFE_TensorHandle* TestMatrixTensorHandle3X2() {
- int64_t dims[] = {3, 2};
- double data[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
- TF_Tensor* t = TF_AllocateTensor(
- TF_FLOAT, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
- memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
- TF_Status* status = TF_NewStatus();
- TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TF_DeleteTensor(t);
- TF_DeleteStatus(status);
- return th;
-}
-
-TFE_Op* MatMulOp(TFE_Context* ctx, TFE_TensorHandle* a, TFE_TensorHandle* b) {
- TF_Status* status = TF_NewStatus();
-
- TFE_Op* op = TFE_NewOp(ctx, "MatMul", status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TFE_OpAddInput(op, a, status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TFE_OpAddInput(op, b, status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TF_DeleteStatus(status);
- TFE_OpSetAttrBool(op, "transpose_a", 0);
- TFE_OpSetAttrBool(op, "transpose_b", 0);
- TFE_OpSetAttrType(op, "T", TFE_TensorHandleDataType(a));
-
- return op;
-}
-
-TFE_TensorHandle* TestAxisTensorHandle() {
- int64_t dims[] = {1};
- int data[] = {1};
- TF_Tensor* t = TF_AllocateTensor(
- TF_INT32, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
- memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
- TF_Status* status = TF_NewStatus();
- TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TF_DeleteTensor(t);
- TF_DeleteStatus(status);
- return th;
-}
-
-TFE_Op* MinOp(TFE_Context* ctx, TFE_TensorHandle* input,
- TFE_TensorHandle* axis) {
- TF_Status* status = TF_NewStatus();
-
- TFE_Op* op = TFE_NewOp(ctx, "Min", status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TFE_OpAddInput(op, input, status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TFE_OpAddInput(op, axis, status);
- CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
- TFE_OpSetAttrBool(op, "keep_dims", 1);
- TFE_OpSetAttrType(op, "Tidx", TF_INT32);
- TF_DeleteStatus(status);
- TFE_OpSetAttrType(op, "T", TFE_TensorHandleDataType(input));
-
- return op;
-}
-
-// If there is a GPU device, returns true and sets 'gpu_device_name'
-// accordingly.
-bool GetGPUDeviceName(TFE_Context* ctx, string* gpu_device_name) {
- std::unique_ptr status(
- TF_NewStatus(), TF_DeleteStatus);
- TF_DeviceList* devices = TFE_ContextListDevices(ctx, status.get());
- CHECK_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get());
-
- const int num_devices = TF_DeviceListCount(devices);
- for (int i = 0; i < num_devices; ++i) {
- const string device_type(TF_DeviceListType(devices, i, status.get()));
- CHECK_EQ(TF_GetCode(status.get()), TF_OK) << TF_Message(status.get());
- const string device_name(TF_DeviceListName(devices, i, status.get()));
- CHECK_EQ(TF_GetCode(status.get()), TF_OK) << TF_Message(status.get());
- if (device_type == "GPU") {
- *gpu_device_name = device_name;
- LOG(INFO) << "Found GPU device " << device_name;
- TF_DeleteDeviceList(devices);
- return true;
- }
- }
- TF_DeleteDeviceList(devices);
- return false;
-}
-
void BM_InitOp(int iters) {
tensorflow::testing::StopTiming();
TF_Status* status = TF_NewStatus();
@@ -220,6 +108,103 @@ TEST(CAPI, Context) {
TF_DeleteStatus(status);
}
+tensorflow::ServerDef GetServerDef(int num_tasks) {
+ tensorflow::ServerDef server_def;
+ server_def.set_protocol("grpc");
+ server_def.set_job_name("localhost");
+ server_def.set_task_index(0);
+ tensorflow::ClusterDef* cluster_def = server_def.mutable_cluster();
+ tensorflow::JobDef* job_def = cluster_def->add_job();
+ job_def->set_name("localhost");
+ for (int i = 0; i < num_tasks; i++) {
+ int port = tensorflow::testing::PickUnusedPortOrDie();
+ job_def->mutable_tasks()->insert(
+ {i, tensorflow::strings::StrCat("localhost:", port)});
+ }
+ return server_def;
+}
+
+void TestRemoteExecute(bool async) {
+ tensorflow::ServerDef server_def = GetServerDef(2);
+
+ // This server def has the task index set to 0.
+ string serialized = server_def.SerializeAsString();
+
+ server_def.set_task_index(1);
+
+ std::unique_ptr worker_server;
+ ASSERT_TRUE(
+ tensorflow::eager::EagerGrpcServer::Create(server_def, &worker_server)
+ .ok());
+ ASSERT_TRUE(worker_server->Start().ok());
+
+ TF_Status* status = TF_NewStatus();
+ TFE_ContextOptions* opts = TFE_NewContextOptions();
+ TFE_ContextOptionsSetServerDef(opts, serialized.data(), serialized.size(),
+ status);
+ TFE_ContextOptionsSetAsync(opts, static_cast(1));
+ EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_Context* ctx = TFE_NewContext(opts, status);
+ EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_DeleteContextOptions(opts);
+
+ TFE_TensorHandle* h0_task0 = TestMatrixTensorHandle();
+ TFE_TensorHandle* h1_task0 = TestMatrixTensorHandle();
+ const char remote_device_name[] =
+ "/job:localhost/replica:0/task:1/device:CPU:0";
+ auto* h0_task1 =
+ TFE_TensorHandleCopyToDevice(h0_task0, ctx, remote_device_name, status);
+ ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ auto* h1_task1 =
+ TFE_TensorHandleCopyToDevice(h1_task0, ctx, remote_device_name, status);
+ ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ TFE_Op* matmul = MatMulOp(ctx, h0_task1, h1_task1);
+ TFE_OpSetDevice(matmul, remote_device_name, status);
+ EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ TFE_TensorHandle* retvals[1];
+ int num_retvals = 1;
+ TFE_Execute(matmul, &retvals[0], &num_retvals, status);
+ EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ auto* retval_task0 = TFE_TensorHandleCopyToDevice(
+ retvals[0], ctx, "/job:localhost/replica:0/task:0/device:CPU:0", status);
+ ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ TF_Tensor* t = TFE_TensorHandleResolve(retval_task0, status);
+ ASSERT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_DeleteTensorHandle(retval_task0);
+ float product[4] = {0};
+ EXPECT_EQ(sizeof(product), TF_TensorByteSize(t));
+ memcpy(&product[0], TF_TensorData(t), TF_TensorByteSize(t));
+ TF_DeleteTensor(t);
+ EXPECT_EQ(7, product[0]);
+ EXPECT_EQ(10, product[1]);
+ EXPECT_EQ(15, product[2]);
+ EXPECT_EQ(22, product[3]);
+
+ TFE_DeleteTensorHandle(h0_task0);
+ TFE_DeleteTensorHandle(h1_task0);
+ TFE_DeleteTensorHandle(h0_task1);
+ TFE_DeleteTensorHandle(h1_task1);
+ TFE_DeleteTensorHandle(retvals[0]);
+
+ TFE_DeleteOp(matmul);
+
+ TFE_ContextAsyncWait(ctx, status);
+ TFE_DeleteContext(ctx, status);
+ EXPECT_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+
+ TF_DeleteStatus(status);
+
+ // TODO(nareshmodi): Figure out how to correctly shut the server down.
+ worker_server.release();
+}
+
+TEST(CAPI, RemoteExecute) { TestRemoteExecute(false); }
+TEST(CAPI, RemoteExecuteAsync) { TestRemoteExecute(true); }
+
TEST(CAPI, TensorHandle) {
TFE_TensorHandle* h = TestMatrixTensorHandle();
EXPECT_EQ(TF_FLOAT, TFE_TensorHandleDataType(h));
@@ -436,7 +421,7 @@ void TensorHandleSilentCopy(bool async) {
// Disable the test if no GPU is present.
string gpu_device_name;
- if (GetGPUDeviceName(ctx, &gpu_device_name)) {
+ if (GetDeviceName(ctx, &gpu_device_name, "GPU")) {
TFE_TensorHandle* hgpu = TFE_TensorHandleCopyToDevice(
hcpu, ctx, gpu_device_name.c_str(), status.get());
ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get());
@@ -483,7 +468,7 @@ void TensorHandleSilentCopyLocal(bool async) {
// Disable the test if no GPU is present.
string gpu_device_name;
- if (GetGPUDeviceName(ctx, &gpu_device_name)) {
+ if (GetDeviceName(ctx, &gpu_device_name, "GPU")) {
TFE_TensorHandle* hgpu = TFE_TensorHandleCopyToDevice(
hcpu, ctx, gpu_device_name.c_str(), status.get());
ASSERT_TRUE(TF_GetCode(status.get()) == TF_OK) << TF_Message(status.get());
@@ -524,7 +509,7 @@ void SetAndGetOpDevices(bool async) {
// Disable the test if no GPU is present.
string gpu_device_name;
- if (GetGPUDeviceName(ctx, &gpu_device_name)) {
+ if (GetDeviceName(ctx, &gpu_device_name, "GPU")) {
TFE_OpSetDevice(matmul, "GPU:0", status);
ASSERT_TRUE(TF_GetCode(status) == TF_OK) << TF_Message(status);
const char* device_name = TFE_OpGetDevice(matmul, status);
@@ -588,7 +573,7 @@ void Execute_MatMul_CPU_Runtime_Error(bool async) {
TFE_DeleteContextOptions(opts);
TFE_TensorHandle* m1 = TestMatrixTensorHandle();
- TFE_TensorHandle* m2 = TestMatrixTensorHandle3X2();
+ TFE_TensorHandle* m2 = DoubleTestMatrixTensorHandle3X2();
TFE_Op* matmul = MatMulOp(ctx, m1, m2);
TFE_OpSetDevice(matmul, "/job:localhost/replica:0/task:0/device:CPU:0",
status);
diff --git a/tensorflow/c/eager/c_api_test_util.cc b/tensorflow/c/eager/c_api_test_util.cc
new file mode 100644
index 00000000000000..5607c9dcb0bbec
--- /dev/null
+++ b/tensorflow/c/eager/c_api_test_util.cc
@@ -0,0 +1,163 @@
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed 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.
+==============================================================================*/
+
+#include "tensorflow/c/eager/c_api_test_util.h"
+
+#include "tensorflow/c/eager/c_api.h"
+#include "tensorflow/core/platform/logging.h"
+#include "tensorflow/core/platform/test.h"
+
+using tensorflow::string;
+
+TFE_TensorHandle* TestScalarTensorHandle() {
+ float data[] = {1.0f};
+ TF_Tensor* t = TF_AllocateTensor(TF_FLOAT, nullptr, 0, sizeof(float));
+ memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteTensor(t);
+ TF_DeleteStatus(status);
+ return th;
+}
+
+TFE_TensorHandle* DoubleTestMatrixTensorHandle() {
+ int64_t dims[] = {2, 2};
+ double data[] = {1.0, 2.0, 3.0, 4.0};
+ TF_Tensor* t = TF_AllocateTensor(
+ TF_DOUBLE, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
+ memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteTensor(t);
+ TF_DeleteStatus(status);
+ return th;
+}
+
+TFE_TensorHandle* TestMatrixTensorHandle() {
+ int64_t dims[] = {2, 2};
+ float data[] = {1.0f, 2.0f, 3.0f, 4.0f};
+ TF_Tensor* t = TF_AllocateTensor(
+ TF_FLOAT, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
+ memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteTensor(t);
+ TF_DeleteStatus(status);
+ return th;
+}
+
+TFE_TensorHandle* DoubleTestMatrixTensorHandle3X2() {
+ int64_t dims[] = {3, 2};
+ double data[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0};
+ TF_Tensor* t = TF_AllocateTensor(
+ TF_FLOAT, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
+ memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteTensor(t);
+ TF_DeleteStatus(status);
+ return th;
+}
+
+TFE_TensorHandle* TestMatrixTensorHandle3X2() {
+ int64_t dims[] = {3, 2};
+ float data[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
+ TF_Tensor* t = TF_AllocateTensor(
+ TF_FLOAT, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
+ memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteTensor(t);
+ TF_DeleteStatus(status);
+ return th;
+}
+
+TFE_Op* MatMulOp(TFE_Context* ctx, TFE_TensorHandle* a, TFE_TensorHandle* b) {
+ TF_Status* status = TF_NewStatus();
+
+ TFE_Op* op = TFE_NewOp(ctx, "MatMul", status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_OpAddInput(op, a, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_OpAddInput(op, b, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteStatus(status);
+ TFE_OpSetAttrBool(op, "transpose_a", 0);
+ TFE_OpSetAttrBool(op, "transpose_b", 0);
+ TFE_OpSetAttrType(op, "T", TFE_TensorHandleDataType(a));
+
+ return op;
+}
+
+TFE_TensorHandle* TestAxisTensorHandle() {
+ int64_t dims[] = {1};
+ int data[] = {1};
+ TF_Tensor* t = TF_AllocateTensor(
+ TF_INT32, &dims[0], sizeof(dims) / sizeof(int64_t), sizeof(data));
+ memcpy(TF_TensorData(t), &data[0], TF_TensorByteSize(t));
+ TF_Status* status = TF_NewStatus();
+ TFE_TensorHandle* th = TFE_NewTensorHandle(t, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TF_DeleteTensor(t);
+ TF_DeleteStatus(status);
+ return th;
+}
+
+TFE_Op* MinOp(TFE_Context* ctx, TFE_TensorHandle* input,
+ TFE_TensorHandle* axis) {
+ TF_Status* status = TF_NewStatus();
+
+ TFE_Op* op = TFE_NewOp(ctx, "Min", status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_OpAddInput(op, input, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_OpAddInput(op, axis, status);
+ CHECK_EQ(TF_OK, TF_GetCode(status)) << TF_Message(status);
+ TFE_OpSetAttrBool(op, "keep_dims", 1);
+ TFE_OpSetAttrType(op, "Tidx", TF_INT32);
+ TF_DeleteStatus(status);
+ TFE_OpSetAttrType(op, "T", TFE_TensorHandleDataType(input));
+
+ return op;
+}
+
+bool GetDeviceName(TFE_Context* ctx, string* device_name,
+ const char* device_type) {
+ std::unique_ptr status(
+ TF_NewStatus(), TF_DeleteStatus);
+ TF_DeviceList* devices = TFE_ContextListDevices(ctx, status.get());
+ CHECK_EQ(TF_OK, TF_GetCode(status.get())) << TF_Message(status.get());
+
+ const int num_devices = TF_DeviceListCount(devices);
+ for (int i = 0; i < num_devices; ++i) {
+ const string dev_type(TF_DeviceListType(devices, i, status.get()));
+ CHECK_EQ(TF_GetCode(status.get()), TF_OK) << TF_Message(status.get());
+ const string dev_name(TF_DeviceListName(devices, i, status.get()));
+ CHECK_EQ(TF_GetCode(status.get()), TF_OK) << TF_Message(status.get());
+ if (dev_type == device_type) {
+ *device_name = dev_name;
+ LOG(INFO) << "Found " << device_type << " device " << *device_name;
+ TF_DeleteDeviceList(devices);
+ return true;
+ }
+ }
+ TF_DeleteDeviceList(devices);
+ return false;
+}
diff --git a/tensorflow/c/eager/c_api_test_util.h b/tensorflow/c/eager/c_api_test_util.h
new file mode 100644
index 00000000000000..474cae67c89249
--- /dev/null
+++ b/tensorflow/c/eager/c_api_test_util.h
@@ -0,0 +1,53 @@
+/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
+
+Licensed 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.
+==============================================================================*/
+#ifndef TENSORFLOW_C_EAGER_C_API_TEST_UTIL_H_
+#define TENSORFLOW_C_EAGER_C_API_TEST_UTIL_H_
+
+#include "tensorflow/c/eager/c_api.h"
+
+#include "tensorflow/core/platform/types.h"
+
+// Return a tensor handle containing a float scalar
+TFE_TensorHandle* TestScalarTensorHandle();
+
+// Return a tensor handle containing a 2x2 matrix of doubles
+TFE_TensorHandle* DoubleTestMatrixTensorHandle();
+
+// Return a tensor handle containing a 2x2 matrix of floats
+TFE_TensorHandle* TestMatrixTensorHandle();
+
+// Return a tensor handle containing a 3x2 matrix of doubles
+TFE_TensorHandle* DoubleTestMatrixTensorHandle3X2();
+
+// Return a tensor handle containing a 3x2 matrix of floats
+TFE_TensorHandle* TestMatrixTensorHandle3X2();
+
+// Return a matmul op multiplying `a` by `b`.
+TFE_Op* MatMulOp(TFE_Context* ctx, TFE_TensorHandle* a, TFE_TensorHandle* b);
+
+// Return an 1-D INT32 tensor containing a single value 1.
+TFE_TensorHandle* TestAxisTensorHandle();
+
+// Return an op taking minimum of `input` long `axis` dimension.
+TFE_Op* MinOp(TFE_Context* ctx, TFE_TensorHandle* input,
+ TFE_TensorHandle* axis);
+
+// If there is a device of type `device_type`, returns true
+// and sets 'device_name' accordingly.
+// `device_type` must be either "GPU" or "TPU".
+bool GetDeviceName(TFE_Context* ctx, tensorflow::string* device_name,
+ const char* device_type);
+
+#endif // TENSORFLOW_C_EAGER_C_API_TEST_UTIL_H_
diff --git a/tensorflow/c/eager/tape.h b/tensorflow/c/eager/tape.h
index 97c323b8722803..734e712daa39c0 100644
--- a/tensorflow/c/eager/tape.h
+++ b/tensorflow/c/eager/tape.h
@@ -48,7 +48,7 @@ struct OpTapeEntry {
// Should be called before deleting the backward function. TODO(apassos) use
// unique_ptrs to ensure this happens.
- std::function backward_function_deleter;
+ std::function backward_function_deleter;
};
// Map from tensor_id to internally-defined operation-id of the operation which
@@ -104,14 +104,12 @@ class VSpace {
gtl::ArraySlice output_gradients,
std::vector* result) const = 0;
+ // Marks the following gradient as a result so it's not consumed by backward
+ // functions.
+ virtual void MarkAsResult(Gradient* gradient) const = 0;
+
// Deletes the input tensor.
virtual void DeleteGradient(Gradient* gradient) const = 0;
-
- // Lets this VSpace know that it can release resources held by the
- // `backward_function`, It will not be called again.
- // `backward_function` must not be null.
- virtual void ReleaseBackwardFunction(
- BackwardFunction* backward_function) const = 0;
};
// Traces the execution of operations, doing eager garbage collection, and
@@ -126,19 +124,21 @@ class GradientTape {
GradientTape(bool persistent) : persistent_(persistent) {}
~GradientTape() {
for (const auto& pair : op_tape_) {
- pair.second.backward_function_deleter();
+ pair.second.backward_function_deleter(pair.second.backward_function);
}
}
- bool ShouldRecord(gtl::ArraySlice tensor_ids);
+ bool ShouldRecord(gtl::ArraySlice tensor_ids,
+ gtl::ArraySlice dtypes);
void Watch(int64 tensor_id);
- void RecordOperation(const string& op_type,
- gtl::ArraySlice output_tensors,
- gtl::ArraySlice input_tensor_id,
- BackwardFunction* backward_function,
- const std::function& backward_function_deleter);
+ void RecordOperation(
+ const string& op_type, gtl::ArraySlice output_tensors,
+ gtl::ArraySlice input_tensor_id,
+ gtl::ArraySlice input_dtypes,
+ BackwardFunction* backward_function,
+ const std::function& backward_function_deleter);
void DeleteTrace(int64 tensor_id);
@@ -170,12 +170,32 @@ class GradientTape {
// Template instantiations here
+inline bool IsDtypeTrainable(DataType dtype) {
+ switch (dtype) {
+ case DT_HALF:
+ case DT_BFLOAT16:
+ case DT_FLOAT:
+ case DT_DOUBLE:
+ case DT_COMPLEX64:
+ case DT_COMPLEX128:
+ case DT_RESOURCE:
+ case DT_VARIANT:
+ return true;
+ default:
+ return false;
+ }
+}
+
template
bool GradientTape::ShouldRecord(
- gtl::ArraySlice tensor_ids) {
- for (int64 i : tensor_ids) {
- if (tensor_tape_.find(i) != tensor_tape_.end()) {
- return true;
+ gtl::ArraySlice tensor_ids,
+ gtl::ArraySlice dtypes) {
+ CHECK_EQ(tensor_ids.size(), dtypes.size());
+ for (int i = 0; i < tensor_ids.size(); ++i) {
+ if (tensor_tape_.find(tensor_ids[i]) != tensor_tape_.end()) {
+ if (IsDtypeTrainable(dtypes[i])) {
+ return true;
+ }
}
}
return false;
@@ -189,10 +209,12 @@ void GradientTape::Watch(int64 tensor_id) {
template
void GradientTape::RecordOperation(
const string& op_type, gtl::ArraySlice output_tensors,
- gtl::ArraySlice input_tensor_id, BackwardFunction* backward_function,
- const std::function& backward_function_deleter) {
- if (!ShouldRecord(input_tensor_id)) {
- backward_function_deleter();
+ gtl::ArraySlice input_tensor_id,
+ gtl::ArraySlice input_dtypes,
+ BackwardFunction* backward_function,
+ const std::function& backward_function_deleter) {
+ if (!ShouldRecord(input_tensor_id, input_dtypes)) {
+ backward_function_deleter(backward_function);
return;
}
std::vector ids;
@@ -247,7 +269,7 @@ void GradientTape::DeleteTrace(int64 tensor_id) {
for (int64 id : op_it->second.input_tensor_id) {
DeleteTrace(id);
}
- op_it->second.backward_function_deleter();
+ op_it->second.backward_function_deleter(op_it->second.backward_function);
op_tape_.erase(op_it);
}
@@ -332,8 +354,7 @@ BackpropInitialState PrepareBackprop(
count_it->second++;
} else {
result.tensor_usage_counts[it] = 1;
- if (sources_set.find(it) == sources_set.end() &&
- tensor_tape.find(it) != tensor_tape.end()) {
+ if (tensor_tape.find(it) != tensor_tape.end()) {
tensor_stack.push_back(it);
}
}
@@ -354,7 +375,8 @@ BackpropInitialState PrepareBackprop(
// backward functions that will be used for gradient computation
// has been transferred to `result`.
for (const auto& op_pair : *op_tape) {
- op_pair.second.backward_function_deleter();
+ op_pair.second.backward_function_deleter(
+ op_pair.second.backward_function);
}
op_tape->clear();
}
@@ -380,49 +402,39 @@ Status InitialGradients(const VSpace& vspace,
gtl::ArraySlice output_gradients,
const TensorTape& tensor_tape,
const OpTape& op_tape,
- const gtl::FlatMap& tensor_usage_counts,
gtl::FlatMap>* result) {
for (int i = 0; i < target_tensor_ids.size(); ++i) {
const int64 id = target_tensor_ids[i];
- if (tensor_usage_counts.find(id) != tensor_usage_counts.end()) {
- if (!output_gradients.empty() && output_gradients[i] != nullptr) {
- // TODO(apassos) figure out how to print debugging information here.
- return errors::InvalidArgument(
- "A gradient was provided for a tensor which is used as part of the "
- "computation.");
- }
- } else {
- if (output_gradients.empty() || output_gradients[i] == nullptr) {
- auto tensor_it = tensor_tape.find(id);
- if (tensor_it != tensor_tape.end() && tensor_it->second != -1) {
- auto op_it = op_tape.find(tensor_it->second);
- if (op_it == op_tape.end()) {
- return errors::Internal(
- "Internal state of the gradient tape is invalid: "
- "failed to find operation producing a tensor");
- }
- bool found = false;
- for (int j = 0; j < op_it->second.output_tensor_info.size(); ++j) {
- if (op_it->second.output_tensor_info[j].id == id) {
- found = true;
- (*result)[id].push_back(
- vspace.Ones(op_it->second.output_tensor_info[j].shape,
- op_it->second.output_tensor_info[j].dtype));
- break;
- }
- }
- if (!found) {
- return errors::Internal(
- "Internal state of the gradient tape is invalid: "
- "none of operations outputs match expected tensor");
+ if (output_gradients.empty() || output_gradients[i] == nullptr) {
+ auto tensor_it = tensor_tape.find(id);
+ if (tensor_it != tensor_tape.end() && tensor_it->second != -1) {
+ auto op_it = op_tape.find(tensor_it->second);
+ if (op_it == op_tape.end()) {
+ return errors::Internal(
+ "Internal state of the gradient tape is invalid: "
+ "failed to find operation producing a tensor");
+ }
+ bool found = false;
+ for (int j = 0; j < op_it->second.output_tensor_info.size(); ++j) {
+ if (op_it->second.output_tensor_info[j].id == id) {
+ found = true;
+ (*result)[id].push_back(
+ vspace.Ones(op_it->second.output_tensor_info[j].shape,
+ op_it->second.output_tensor_info[j].dtype));
+ break;
}
- } else {
- // No record of the target tensor found on the tape, so no gradient
- // needs to be computed from it. Do nothing.
+ }
+ if (!found) {
+ return errors::Internal(
+ "Internal state of the gradient tape is invalid: "
+ "none of operations outputs match expected tensor");
}
} else {
- (*result)[id].push_back(output_gradients[i]);
+ // No record of the target tensor found on the tape, so no gradient
+ // needs to be computed from it. Do nothing.
}
+ } else {
+ (*result)[id].push_back(output_gradients[i]);
}
}
return Status::OK();
@@ -451,13 +463,12 @@ Status GradientTape::ComputeGradient(
InitialStack(state.op_tape, state.op_missing_tensor);
gtl::FlatMap> gradients;
Status s = InitialGradients(vspace, target_tensor_ids, output_gradients,
- tensor_tape_, state.op_tape,
- state.tensor_usage_counts, &gradients);
+ tensor_tape_, state.op_tape, &gradients);
auto cleanup = [this, &state]() {
if (!persistent_) {
// Release all backprop functions
for (const auto& pair : state.op_tape) {
- pair.second.backward_function_deleter();
+ pair.second.backward_function_deleter(pair.second.backward_function);
}
}
};
@@ -509,10 +520,15 @@ Status GradientTape::ComputeGradient(
}
} else {
any_gradient_nonzero = true;
- out_gradients.push_back(vspace.AggregateGradients(grad_it->second));
+ auto new_gradients = vspace.AggregateGradients(grad_it->second);
if (sources_set.find(grad_it->first) == sources_set.end()) {
gradients.erase(grad_it);
+ } else {
+ grad_it->second.clear();
+ grad_it->second.push_back(new_gradients);
+ vspace.MarkAsResult(new_gradients);
}
+ out_gradients.push_back(new_gradients);
}
}
std::vector in_gradients;
@@ -520,7 +536,7 @@ Status GradientTape::ComputeGradient(
Status s = vspace.CallBackwardFunction(trace.backward_function,
out_gradients, &in_gradients);
if (!persistent_) {
- vspace.ReleaseBackwardFunction(trace.backward_function);
+ trace.backward_function_deleter(trace.backward_function);
}
if (!s.ok()) {
cleanup();
@@ -529,7 +545,7 @@ Status GradientTape::ComputeGradient(
} else {
in_gradients.resize(trace.input_tensor_id.size());
if (!persistent_) {
- vspace.ReleaseBackwardFunction(trace.backward_function);
+ trace.backward_function_deleter(trace.backward_function);
}
for (Gradient* grad : out_gradients) {
if (grad != nullptr) {
diff --git a/tensorflow/c/generate-pc.sh b/tensorflow/c/generate-pc.sh
index 02a6a58b6153bb..7184ad68fb79f2 100755
--- a/tensorflow/c/generate-pc.sh
+++ b/tensorflow/c/generate-pc.sh
@@ -15,10 +15,12 @@
# ==============================================================================
TF_PREFIX='/usr/local'
+LIBDIR='lib'
usage() {
echo "Usage: $0 OPTIONS"
echo -e "-p, --prefix\tset installation prefix (default: /usr/local)"
+ echo -e "-l, --libdir\tset lib directory (default: lib)"
echo -e "-v, --version\tset TensorFlow version"
echo -e "-h, --help\tdisplay this message"
}
@@ -26,7 +28,7 @@ usage() {
[ $# == 0 ] && usage && exit 0
# read the options
-ARGS=$(getopt -o p:v:h --long prefix:,version:,help -n $0 -- "$@")
+ARGS=$(getopt -o p:l:v:h --long prefix:,libdir:,version:,help -n $0 -- "$@")
eval set -- "$ARGS"
# extract options and their arguments into variables.
@@ -38,6 +40,11 @@ while true ; do
"") shift 2 ;;
*) TF_PREFIX=$2 ; shift 2 ;;
esac ;;
+ -l|--libdir)
+ case "$2" in
+ "") shift 2 ;;
+ *) LIBDIR=$2 ; shift 2 ;;
+ esac ;;
-v|--version)
case "$2" in
"") shift 2 ;;
@@ -55,7 +62,7 @@ echo "Generating pkgconfig file for TensorFlow $TF_VERSION in $TF_PREFIX"
cat << EOF > tensorflow.pc
prefix=${TF_PREFIX}
exec_prefix=\${prefix}
-libdir=\${exec_prefix}/lib
+libdir=\${exec_prefix}/${LIBDIR}
includedir=\${prefix}/include
Name: TensorFlow
diff --git a/tensorflow/cc/framework/cc_op_gen.cc b/tensorflow/cc/framework/cc_op_gen.cc
index d73121c7b701ec..d6a4f141b6bb8c 100644
--- a/tensorflow/cc/framework/cc_op_gen.cc
+++ b/tensorflow/cc/framework/cc_op_gen.cc
@@ -440,7 +440,7 @@ string AvoidCPPKeywords(StringPiece name) {
if (IsCPPKeyword(name)) {
return strings::StrCat(name, "_");
}
- return name.ToString();
+ return std::string(name);
}
void InferArgAttributes(const OpDef::ArgDef& arg,
diff --git a/tensorflow/cc/framework/scope.cc b/tensorflow/cc/framework/scope.cc
index c143b978338815..62a889181e787f 100644
--- a/tensorflow/cc/framework/scope.cc
+++ b/tensorflow/cc/framework/scope.cc
@@ -220,7 +220,7 @@ std::unordered_set Scope::Impl::GetColocationConstraints(
for (const string& entry : node_constraints) {
StringPiece s(entry);
if (str_util::ConsumePrefix(&s, kColocationGroupPrefix)) {
- current_constraints.insert(s.ToString());
+ current_constraints.insert(std::string(s));
}
}
} else {
diff --git a/tensorflow/cc/gradients/math_grad.cc b/tensorflow/cc/gradients/math_grad.cc
index 52c177212a8c88..35a01e0341cb08 100644
--- a/tensorflow/cc/gradients/math_grad.cc
+++ b/tensorflow/cc/gradients/math_grad.cc
@@ -38,6 +38,7 @@ REGISTER_NO_GRADIENT_OP("NotEqual");
REGISTER_NO_GRADIENT_OP("LogicalAnd");
REGISTER_NO_GRADIENT_OP("LogicalOr");
REGISTER_NO_GRADIENT_OP("LogicalNot");
+REGISTER_NO_GRADIENT_OP("Floor");
// Conjugate helper function returns the conjugate of an Output if it
// is complex valued.
diff --git a/tensorflow/cc/gradients/math_grad_test.cc b/tensorflow/cc/gradients/math_grad_test.cc
index 1b4c7c2688083e..fd7b6fe6625f27 100644
--- a/tensorflow/cc/gradients/math_grad_test.cc
+++ b/tensorflow/cc/gradients/math_grad_test.cc
@@ -31,7 +31,6 @@ using ops::AddN;
using ops::BatchMatMul;
using ops::Const;
using ops::Div;
-using ops::Greater;
using ops::MatMul;
using ops::Max;
using ops::Maximum;
@@ -46,7 +45,6 @@ using ops::RealDiv;
using ops::SquaredDifference;
using ops::Sub;
using ops::Sum;
-using ops::Where3;
// TODO(andydavis) Test gradient function against numeric gradients output.
// TODO(andydavis) As more gradients are added move common test functions
diff --git a/tensorflow/cc/gradients/nn_grad.cc b/tensorflow/cc/gradients/nn_grad.cc
index 0cb3132e94e381..c73482d5f4d13a 100644
--- a/tensorflow/cc/gradients/nn_grad.cc
+++ b/tensorflow/cc/gradients/nn_grad.cc
@@ -255,6 +255,53 @@ Status LRNGradHelper(const Scope& scope, const Operation& op,
}
REGISTER_GRADIENT_OP("LRN", LRNGradHelper);
+Status SoftplusGradHelper(const Scope& scope, const Operation& op,
+ const std::vector