diff --git a/tools/bazel.rc b/.bazelrc
similarity index 93%
rename from tools/bazel.rc
rename to .bazelrc
index 1fdf51f53e29c7111cf89c016400b710051cf9c6..ceba7bfdbac74d1e44aadc3010e5e84bd36ce3ee 100644
--- a/tools/bazel.rc
+++ b/.bazelrc
@@ -76,7 +76,6 @@ build:nonccl --define=no_nccl_support=true
build --define=use_fast_cpp_protos=true
build --define=allow_oversize_protos=true
-build --define=grpc_no_ares=true
build --spawn_strategy=standalone
build --genrule_strategy=standalone
@@ -93,3 +92,14 @@ build:dynamic_kernels --copt=-DAUTOLOAD_DYNAMIC_KERNELS
build --define=PREFIX=/usr
build --define=LIBDIR=$(PREFIX)/lib
build --define=INCLUDEDIR=$(PREFIX)/include
+
+# Disable MKL-DNN contraction kernels by default.
+build --define=tensorflow_mkldnn_contraction_kernel=0
+
+# Default options should come above this line
+
+# Options from ./configure
+try-import %workspace%/.tf_configure.bazelrc
+
+# Put user-specific options in .bazelrc.user
+try-import %workspace%/.bazelrc.user
diff --git a/.gitignore b/.gitignore
index 90324058600bee46af56e49028977971848a80de..e1d352c238a1b2d4febe0f5d4a30cfa0c942f7e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
.DS_Store
.ipynb_checkpoints
node_modules
-/.bazelrc
+/.bazelrc.user
/.tf_configure.bazelrc
/bazel-*
/bazel_pip
diff --git a/CODEOWNERS b/CODEOWNERS
index bfcdc2a23f4753336e357a45afd6259b531f36ec..cb3fa2312405ce44d5dfc30ea4164740f436e07e 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,7 +1,7 @@
# Where component owners are known, add them here.
/tenosrflow/core/debug @caisq
-/tensorflow/core/nccl/ @azaks @csigg
+/tensorflow/core/nccl/ @azaks2 @chsigg
/tensorflow/core/platform/windows/ @mrry
/tensorflow/core/platform/s3 @yongtang
/tensorflow/go @asimshankar
diff --git a/README.md b/README.md
index 044174947a094d43a51f7140dd40ec0f17801d40..519815d006cc33be10132909baf414a4bd843435 100644
--- a/README.md
+++ b/README.md
@@ -113,11 +113,12 @@ The TensorFlow project strives to abide by generally accepted best practices in
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_PPC64LE_CPU_Build/) | TBA
-**IBM ppc64le GPU** Nightly | [](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Nightly_Artifact/) | [Nightly](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Nightly_Artifact/)
-**IBM ppc64le GPU** Stable Release | [](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/) | [Release](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/)
+**Linux ppc64le CPU** Nightly | [](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_CPU_Build/) | [Nightly](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_CPU_Nightly_Artifact/)
+**Linux ppc64le CPU** Stable Release | [](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_CPU_Release_Build/) | [Release](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_CPU_Release_Build/)
+**Linux ppc64le GPU** Nightly | [](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Build/) | [Nightly](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Nightly_Artifact/)
+**Linux ppc64le GPU** Stable Release | [](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/) | [Release](https://powerci.osuosl.org/job/TensorFlow_PPC64LE_GPU_Release_Build/)
**Linux CPU with Intel® MKL-DNN** Nightly | [](https://tensorflow-ci.intel.com/job/tensorflow-mkl-linux-cpu/) | [Nightly](https://tensorflow-ci.intel.com/job/tensorflow-mkl-build-whl-nightly/)
-**Linux CPU with Intel® MKL-DNN** Python 2.7 **Linux CPU with Intel® MKL-DNN** Python 3.4 **Linux CPU with Intel® MKL-DNN** Python 3.5 **Linux CPU with Intel® MKL-DNN** Python 3.6 | [](https://tensorflow-ci.intel.com/job/tensorflow-mkl-build-release-whl/lastStableBuild) | [1.11.0 py2.7](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.11.0-cp27-cp27mu-linux_x86_64.whl) [1.11.0 py3.4](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.11.0-cp34-cp34m-linux_x86_64.whl) [1.11.0 py3.5](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.11.0-cp35-cp35m-linux_x86_64.whl) [1.11.0 py3.6](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.11.0-cp36-cp36m-linux_x86_64.whl)
+**Linux CPU with Intel® MKL-DNN** Python 2.7 **Linux CPU with Intel® MKL-DNN** Python 3.4 **Linux CPU with Intel® MKL-DNN** Python 3.5 **Linux CPU with Intel® MKL-DNN** Python 3.6 | [](https://tensorflow-ci.intel.com/job/tensorflow-mkl-build-release-whl/lastStableBuild) | [1.12.0 py2.7](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.12.0-cp27-cp27mu-linux_x86_64.whl) [1.12.0 py3.4](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.12.0-cp34-cp34m-linux_x86_64.whl) [1.12.0 py3.5](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.12.0-cp35-cp35m-linux_x86_64.whl) [1.12.0 py3.6](https://storage.googleapis.com/intel-optimized-tensorflow/tensorflow-1.12.0-cp36-cp36m-linux_x86_64.whl)
## For more information
diff --git a/RELEASE.md b/RELEASE.md
index b13b071bd6cf4d3a260c8e248a67d23e1a688498..282430d12303bde980e19e3c3602eb91b1a54d63 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -7,6 +7,8 @@
Serving.
* Keras models now support evaluating with a `tf.data.Dataset`.
* TensorFlow binaries are built with XLA support linked in by default.
+* Ignite Dataset added to contrib/ignite that allows to work with Apache
+ Ignite.
## Bug Fixes and Other Changes
@@ -280,50 +282,76 @@ Ag Ramesh, Alex Wiltschko, Alexander Pantyukhin, Amogh Mannekote, An Jiaoyang, A
## Bug Fixes and Other Changes
-* `tfe.Network` is deprecated. Please inherit from `tf.keras.Model`.
-* Layered variable names have changed in the following conditions:
- * Using `tf.keras.layers` with custom variable scopes.
- * Using `tf.layers` in a subclassed `tf.keras.Model` class. See
- [here](https://www.tensorflow.org/versions/r1.9/api_docs/python/tf/layers) for more details
-* `tf.data`:
- * `Dataset.from_generator()` now accepts an `args` list, in order to create nested generators.
- * `Dataset.list_files()` now produces determinstic results when `shuffle=False` or a `seed` is passed.
- * `tf.contrib.data.sample_from_datasets()` and `tf.contrib.data.choose_from_datasets()` make it easier to sample or deterministically choose elements from multiple datasets.
- * `tf.contrib.data.make_csv_dataset()` now supports line breaks in quoted strings, and two infrequently used arguments removed.
- * (C++) `DatasetBase::DebugString()` is now `const`.
- * (C++) `DatasetBase::MakeIterator()` has been renamed to `DatasetBase::MakeIteratorInternal()`.
- * (C++) `IteratorBase::Initialize()` method was added to support raising errors during iterator construction.
-* Eager Execution:
- * Added the ability to pause recording operations for gradient computation via `tf.GradientTape.stop_recording`.
- * Updated documentation, introductory notebooks.
-* `tf.keras`:
- * Move Keras code out of _impl folder and remove API files.
- * `tf.keras.Model.save_weights` now saves in TensorFlow format by default.
- * Enable dataset iterators to be passed to `tf.keras.Model` training/eval methods.
-* TensorFlow Debugger (tfdbg) CLI: fix an issue in which the TensorBoard Debugger Plugin could not handle total source file size exceeding gRPC message size limit (4 MB).
-* `tf.contrib`:
- * `tf.contrib.framework.zero_initializer` supports ResourceVariable.
- * Adding "constrained_optimization" to tensorflow/contrib.
-* Other:
- * Add GCS Configuration Ops.
- * Changing signature of `MakeIterator` to enable propagating error status.
- * KL divergence for two Dirichlet distributions.
- * More consistent GcsFileSystem behavior for certain reads past EOF.
- * Update benchmark for tf.scan to match ranges across eager and graph modes.
- * Fixed bug in `tf.reduce_prod gradient` for complex dtypes.
- * Allow the use of '.' in variables (e.g. "hparams.parse('a.b=1.0')"), which would previously raise an error. This will correspond to an attribute name with an embedded '.' symbol (e.g. 'a.b'), which can only be accessed indirectly (e.g. through getattr and setattr). To set this up the user will first need to explicitly add the variable to the hparam object (e.g. "hparams.add_hparam(name='a.b', value=0.0)").
- * Benchmark for tf.scan in graph and eager modes.
- * Added complex128 support to FFT, FFT2D, FFT3D, IFFT, IFFT2D, and IFFT3D.
- * Making ids unique in `nn.embedding_lookup_sparse`. This helps to reduce RPC calls for looking up the embeddings when there are repeated ids in the batch.
- * Support indicator column in boosted trees.
- * Prevent `tf.gradients()` from backpropagating through integer tensors.
- * LinearOperator[1D,2D,3D]Circulant added to `tensorflow.linalg`.
- * Conv3D, Conv3DBackpropInput, Conv3DBackpropFilter now supports arbitrary.
- * Added `tf.train.Checkpoint` for reading/writing object-based checkpoints.
- * Added LinearOperatorKronecker, a dense-free implementation of the Kronecker Product.
- * Allow LinearOperator to broadcast.
- * SavedModelBuilder will now deduplicate asset names that point to files with the same basename and the same contents. Note that this may result in new asset files included in SavedModels in cases where assets with the same name but different contents were previously overwriting each other.
-
+* `tfe.Network` is deprecated. Please inherit from `tf.keras.Model`.
+* Layered variable names have changed in the following conditions:
+ * Using `tf.keras.layers` with custom variable scopes.
+ * Using `tf.layers` in a subclassed `tf.keras.Model` class. See
+ [here](https://www.tensorflow.org/versions/r1.9/api_docs/python/tf/layers)
+ for more details
+* `tf.data`:
+ * `Dataset.from_generator()` now accepts an `args` list, in order to
+ create nested generators.
+ * `Dataset.list_files()` now produces deterministic results when
+ `shuffle=False` or a `seed` is passed.
+ * `tf.contrib.data.sample_from_datasets()` and
+ `tf.contrib.data.choose_from_datasets()` make it easier to sample or
+ deterministically choose elements from multiple datasets.
+ * `tf.contrib.data.make_csv_dataset()` now supports line breaks in quoted
+ strings, and two infrequently used arguments removed.
+ * (C++) `DatasetBase::DebugString()` is now `const`.
+ * (C++) `DatasetBase::MakeIterator()` has been renamed to
+ `DatasetBase::MakeIteratorInternal()`.
+ * (C++) `IteratorBase::Initialize()` method was added to support raising
+ errors during iterator construction.
+* Eager Execution:
+ * Added the ability to pause recording operations for gradient computation
+ via `tf.GradientTape.stop_recording`.
+ * Updated documentation, introductory notebooks.
+* `tf.keras`:
+ * Move Keras code out of _impl folder and remove API files.
+ * `tf.keras.Model.save_weights` now saves in TensorFlow format by default.
+ * Enable dataset iterators to be passed to `tf.keras.Model` training/eval
+ methods.
+* TensorFlow Debugger (tfdbg) CLI: fix an issue in which the TensorBoard
+ Debugger Plugin could not handle total source file size exceeding gRPC
+ message size limit (4 MB).
+* `tf.contrib`:
+ * `tf.contrib.framework.zero_initializer` supports ResourceVariable.
+ * Adding "constrained_optimization" to tensorflow/contrib.
+* Other:
+ * Add GCS Configuration Ops.
+ * Changing signature of `MakeIterator` to enable propagating error status.
+ * KL divergence for two Dirichlet distributions.
+ * More consistent GcsFileSystem behavior for certain reads past EOF.
+ * Update benchmark for tf.scan to match ranges across eager and graph
+ modes.
+ * Fixed bug in `tf.reduce_prod gradient` for complex dtypes.
+ * Allow the use of '.' in variables (e.g. "hparams.parse('a.b=1.0')"),
+ which would previously raise an error. This will correspond to an
+ attribute name with an embedded '.' symbol (e.g. 'a.b'), which can only
+ be accessed indirectly (e.g. through getattr and setattr). To set this
+ up the user will first need to explicitly add the variable to the hparam
+ object (e.g. "hparams.add_hparam(name='a.b', value=0.0)").
+ * Benchmark for tf.scan in graph and eager modes.
+ * Added complex128 support to FFT, FFT2D, FFT3D, IFFT, IFFT2D, and IFFT3D.
+ * Making ids unique in `nn.embedding_lookup_sparse`. This helps to reduce
+ RPC calls for looking up the embeddings when there are repeated ids in
+ the batch.
+ * Support indicator column in boosted trees.
+ * Prevent `tf.gradients()` from backpropagating through integer tensors.
+ * LinearOperator[1D,2D,3D]Circulant added to `tensorflow.linalg`.
+ * Conv3D, Conv3DBackpropInput, Conv3DBackpropFilter now supports
+ arbitrary.
+ * Added `tf.train.Checkpoint` for reading/writing object-based
+ checkpoints.
+ * Added LinearOperatorKronecker, a dense-free implementation of the
+ Kronecker Product.
+ * Allow LinearOperator to broadcast.
+ * SavedModelBuilder will now deduplicate asset names that point to files
+ with the same basename and the same contents. Note that this may result
+ in new asset files included in SavedModels in cases where assets with
+ the same name but different contents were previously overwriting each
+ other.
## Thanks to our Contributors
diff --git a/WORKSPACE b/WORKSPACE
index 7cc08e0164a202581ad7ebbe107a9e19410e70e4..2277e83a3f67b62cf4ee1311767ee06c0549c697 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,6 +1,6 @@
workspace(name = "org_tensorflow")
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
http_archive(
name = "io_bazel_rules_closure",
@@ -16,38 +16,64 @@ load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")
closure_repositories()
-http_archive(
- name = "base_images_docker",
- sha256 = "e2b1b7254270bb7605e814a9dbf6d1e4ae04a11136ff1714fbfdabe3f87f7cf9",
- strip_prefix = "base-images-docker-12801524f867e657fbb5d1a74f31618aff181ac6",
- urls = ["https://github.com/GoogleCloudPlatform/base-images-docker/archive/12801524f867e657fbb5d1a74f31618aff181ac6.tar.gz"],
-)
+load("//third_party/toolchains/preconfig/generate:archives.bzl",
+ "bazel_toolchains_archive")
-http_archive(
- name = "bazel_toolchains",
- sha256 = "15b5858b1b5541ec44df31b94c3b8672815b31d71215a98398761ea9f4c4eedb",
- strip_prefix = "bazel-toolchains-6200b238c9c2d137c0d9a7262c80cc71d98e692b",
- urls = [
- "https://github.com/bazelbuild/bazel-toolchains/archive/6200b238c9c2d137c0d9a7262c80cc71d98e692b.tar.gz",
- ],
+bazel_toolchains_archive()
+
+load(
+ "@bazel_toolchains//repositories:repositories.bzl",
+ bazel_toolchains_repositories = "repositories",
)
-http_archive(
- name = "io_bazel_rules_docker",
- sha256 = "29d109605e0d6f9c892584f07275b8c9260803bf0c6fcb7de2623b2bedc910bd",
- strip_prefix = "rules_docker-0.5.1",
- urls = ["https://github.com/bazelbuild/rules_docker/archive/v0.5.1.tar.gz"],
+bazel_toolchains_repositories()
+
+load(
+ "@io_bazel_rules_docker//container:container.bzl",
+ container_repositories = "repositories",
)
-load("//third_party/toolchains/preconfig/generate:workspace.bzl", "remote_config_workspace")
+container_repositories()
+
+load("//third_party/toolchains/preconfig/generate:workspace.bzl",
+ "remote_config_workspace")
remote_config_workspace()
+# Apple and Swift rules.
+http_archive(
+ name = "build_bazel_rules_apple",
+ sha256 = "4fe4ee824200b48821730f89ff260984332dc3551db587c24691235d1d96a8a7",
+ strip_prefix = "rules_apple-0.10.0",
+ urls = ["https://github.com/bazelbuild/rules_apple/archive/0.10.0.tar.gz"],
+)
+http_archive(
+ name = "build_bazel_rules_swift",
+ sha256 = "6544ff5615febec0342de1127144d2f3e43ea80fb7f9b1ade65e6a184e39e618",
+ strip_prefix = "rules_swift-0.5.0",
+ urls = ["https://github.com/bazelbuild/rules_swift/archive/0.5.0.tar.gz"],
+)
+http_archive(
+ name = "bazel_skylib",
+ sha256 = "eb5c57e4c12e68c0c20bc774bfbc60a568e800d025557bc4ea022c6479acc867",
+ strip_prefix = "bazel-skylib-0.6.0",
+ urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.6.0.tar.gz"],
+)
+http_file(
+ name = "xctestrunner",
+ executable = 1,
+ urls = ["https://github.com/google/xctestrunner/releases/download/0.2.5/ios_test_runner.par"],
+)
+load("@build_bazel_rules_apple//apple:repositories.bzl", "apple_rules_dependencies")
+apple_rules_dependencies(ignore_version_differences = True)
+load("@build_bazel_rules_swift//swift:repositories.bzl", "swift_rules_dependencies")
+swift_rules_dependencies()
+
# We must check the bazel version before trying to parse any other BUILD
# files, in case the parsing of those build files depends on the bazel
# version we require here.
load("//tensorflow:version_check.bzl", "check_bazel_version_at_least")
-check_bazel_version_at_least("0.15.0")
+check_bazel_version_at_least("0.18.0")
load("//tensorflow:workspace.bzl", "tf_workspace")
diff --git a/tensorflow/opensource_only/arm_compiler.BUILD b/arm_compiler.BUILD
similarity index 100%
rename from tensorflow/opensource_only/arm_compiler.BUILD
rename to arm_compiler.BUILD
diff --git a/configure.py b/configure.py
index 6c905a0be3d685b5921dfbc5bddfbe6471a82625..1e732db26404906901a9eeab97a5e75137ee8388 100644
--- a/configure.py
+++ b/configure.py
@@ -255,18 +255,6 @@ def setup_python(environ_cp):
def reset_tf_configure_bazelrc():
"""Reset file that contains customized config settings."""
open(_TF_BAZELRC, 'w').close()
- bazelrc_path = os.path.join(_TF_WORKSPACE_ROOT, '.bazelrc')
-
- data = []
- if os.path.exists(bazelrc_path):
- with open(bazelrc_path, 'r') as f:
- data = f.read().splitlines()
- with open(bazelrc_path, 'w') as f:
- for l in data:
- if _TF_BAZELRC_FILENAME in l:
- continue
- f.write('%s\n' % l)
- f.write('import %%workspace%%/%s\n' % _TF_BAZELRC_FILENAME)
def cleanup_makefile():
"""Delete any leftover BUILD files from the Makefile build.
@@ -488,11 +476,12 @@ def check_bazel_version(min_version, max_version):
if curr_version_int < min_version_int:
print('Please upgrade your bazel installation to version %s or higher to '
'build TensorFlow!' % min_version)
- sys.exit(0)
- if curr_version_int > max_version_int:
+ sys.exit(1)
+ if (curr_version_int > max_version_int and
+ 'TF_IGNORE_MAX_BAZEL_VERSION' not in os.environ):
print('Please downgrade your bazel installation to version %s or lower to '
'build TensorFlow!' % max_version)
- sys.exit(0)
+ sys.exit(1)
return curr_version
@@ -1565,11 +1554,9 @@ def main():
# environment variables.
environ_cp = dict(os.environ)
- check_bazel_version('0.15.0', '0.20.0')
+ check_bazel_version('0.19.0', '0.20.0')
reset_tf_configure_bazelrc()
- # Explicitly import tools/bazel.rc, this is needed for Bazel 0.19.0 or later
- write_to_bazelrc('import %workspace%/tools/bazel.rc')
cleanup_makefile()
setup_python(environ_cp)
diff --git a/tensorflow/BUILD b/tensorflow/BUILD
index fd4b94202aad24a82abef8abd16431f61a8326f0..f07e7365d3482cde5b7bb76ebf22890150e98651 100644
--- a/tensorflow/BUILD
+++ b/tensorflow/BUILD
@@ -202,6 +202,12 @@ config_setting(
visibility = ["//visibility:public"],
)
+config_setting(
+ name = "arm",
+ values = {"cpu": "arm"},
+ visibility = ["//visibility:public"],
+)
+
config_setting(
name = "freebsd",
values = {"cpu": "freebsd"},
@@ -267,6 +273,15 @@ config_setting(
visibility = ["//visibility:public"],
)
+# By default, XLA GPU is compiled into tensorflow when building with
+# --config=cuda even when `with_xla_support` is false. The config setting
+# here allows us to override the behavior if needed.
+config_setting(
+ name = "no_xla_deps_in_cuda",
+ define_values = {"no_xla_deps_in_cuda": "true"},
+ visibility = ["//visibility:public"],
+)
+
config_setting(
name = "with_gdr_support",
define_values = {"with_gdr_support": "true"},
@@ -359,7 +374,9 @@ package_group(
name = "internal",
packages = [
"-//third_party/tensorflow/python/estimator",
+ "//learning/deepmind/...",
"//learning/meta_rank/...",
+ "//learning/pathways/...", # While dataset C++ api requires internals
"//tensorflow/...",
"//tensorflow_estimator/contrib/...",
"//tensorflow_fold/llgtm/...",
@@ -606,9 +623,11 @@ py_library(
name = "tensorflow_py",
srcs_version = "PY2AND3",
visibility = ["//visibility:public"],
- deps = [
+ deps = select({
+ "api_version_2": [],
+ "//conditions:default": ["//tensorflow/contrib:contrib_py"],
+ }) + [
":tensorflow_py_no_contrib",
- "//tensorflow/contrib:contrib_py",
"//tensorflow/python/estimator:estimator_py",
],
)
@@ -618,7 +637,11 @@ py_library(
srcs = select({
"api_version_2": [":tf_python_api_gen_v2"],
"//conditions:default": [":tf_python_api_gen_v1"],
- }) + [":root_init_gen"],
+ }) + [":root_init_gen"] + [
+ "//tensorflow/python/keras/api:keras_python_api_gen",
+ "//tensorflow/python/keras/api:keras_python_api_gen_compat_v1",
+ "//tensorflow/python/keras/api:keras_python_api_gen_compat_v2",
+ ],
srcs_version = "PY2AND3",
visibility = ["//visibility:public"],
deps = ["//tensorflow/python:no_contrib"],
diff --git a/tensorflow/api_template.__init__.py b/tensorflow/api_template.__init__.py
index d81cf067eb07e88e2b8a86cf5643674235eb3f3b..2c0a7452692e5cdb184f7f0a77eb1b646a1772d4 100644
--- a/tensorflow/api_template.__init__.py
+++ b/tensorflow/api_template.__init__.py
@@ -18,27 +18,78 @@ from __future__ import absolute_import as _absolute_import
from __future__ import division as _division
from __future__ import print_function as _print_function
+import distutils as _distutils
+import inspect as _inspect
import os as _os
+import site as _site
+import sys as _sys
+
+# API IMPORTS PLACEHOLDER
# pylint: disable=g-bad-import-order
from tensorflow.python.tools import component_api_helper as _component_api_helper
_component_api_helper.package_hook(
parent_package_str=__name__,
- child_package_str=('tensorflow_estimator.python.estimator.api.estimator'))
-
-# API IMPORTS PLACEHOLDER
+ child_package_str=(
+ 'tensorflow_estimator.python.estimator.api._v2.estimator'))
+_current_module = _sys.modules[__name__]
+if not hasattr(_current_module, 'estimator'):
+ _component_api_helper.package_hook(
+ parent_package_str=__name__,
+ child_package_str=(
+ 'tensorflow_estimator.python.estimator.api.estimator'))
+_component_api_helper.package_hook(
+ parent_package_str=__name__,
+ child_package_str=('tensorflow.python.keras.api._v2.keras'))
# Make sure directory containing top level submodules is in
# the __path__ so that "from tensorflow.foo import bar" works.
# We're using bitwise, but there's nothing special about that.
_tf_api_dir = _os.path.dirname(_os.path.dirname(bitwise.__file__)) # pylint: disable=undefined-variable
-if _tf_api_dir not in __path__:
+if not hasattr(_current_module, '__path__'):
+ __path__ = [_tf_api_dir]
+elif _tf_api_dir not in __path__:
__path__.append(_tf_api_dir)
# Enable TF2 behaviors
from tensorflow.python.compat import compat as _compat # pylint: disable=g-import-not-at-top
_compat.enable_v2_behavior()
+
+# Load all plugin libraries from site-packages/tensorflow-plugins if we are
+# running under pip.
+# TODO(gunan): Enable setting an environment variable to define arbitrary plugin
+# directories.
+# TODO(gunan): Find a better location for this code snippet.
+from tensorflow.python.framework import load_library as _ll
+from tensorflow.python.lib.io import file_io as _fi
+
+# Get sitepackages directories for the python installation.
+_site_packages_dirs = []
+_site_packages_dirs += [_site.USER_SITE]
+_site_packages_dirs += [_p for _p in _sys.path if 'site-packages' in _p]
+if 'getsitepackages' in dir(_site):
+ _site_packages_dirs += _site.getsitepackages()
+
+if 'sysconfig' in dir(_distutils):
+ _site_packages_dirs += [_distutils.sysconfig.get_python_lib()]
+
+_site_packages_dirs = list(set(_site_packages_dirs))
+
+# Find the location of this exact file.
+_current_file_location = _inspect.getfile(_inspect.currentframe())
+
+def _running_from_pip_package():
+ return any(
+ _current_file_location.startswith(dir_) for dir_ in _site_packages_dirs)
+
+if _running_from_pip_package():
+ for s in _site_packages_dirs:
+ # TODO(gunan): Add sanity checks to loaded modules here.
+ plugin_dir = _os.path.join(s, 'tensorflow-plugins')
+ if _fi.file_exists(plugin_dir):
+ _ll.load_library(plugin_dir)
+
# 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
@@ -59,4 +110,6 @@ try:
del compiler
except NameError:
pass
+
+
# pylint: enable=undefined-variable
diff --git a/tensorflow/api_template_v1.__init__.py b/tensorflow/api_template_v1.__init__.py
index 65bdb6cb1b5e6fb0656a12b932d767aeacfccd29..514aba1b59631f882523396aab0f4d3d5e88a893 100644
--- a/tensorflow/api_template_v1.__init__.py
+++ b/tensorflow/api_template_v1.__init__.py
@@ -18,20 +18,42 @@ from __future__ import absolute_import as _absolute_import
from __future__ import division as _division
from __future__ import print_function as _print_function
+import distutils as _distutils
+import inspect as _inspect
import os as _os
+import site as _site
+import sys as _sys
# pylint: disable=g-bad-import-order
from tensorflow.python import pywrap_tensorflow # pylint: disable=unused-import
+# API IMPORTS PLACEHOLDER
+
from tensorflow.python.tools import component_api_helper as _component_api_helper
_component_api_helper.package_hook(
parent_package_str=__name__,
- child_package_str=('tensorflow_estimator.python.estimator.api.estimator'))
-
-# API IMPORTS PLACEHOLDER
+ child_package_str=(
+ 'tensorflow_estimator.python.estimator.api._v1.estimator'))
+_current_module = _sys.modules[__name__]
+if not hasattr(_current_module, 'estimator'):
+ _component_api_helper.package_hook(
+ parent_package_str=__name__,
+ child_package_str=(
+ 'tensorflow_estimator.python.estimator.api.estimator'))
+_component_api_helper.package_hook(
+ parent_package_str=__name__,
+ child_package_str=('tensorflow.python.keras.api._v1.keras'))
from tensorflow.python.util.lazy_loader import LazyLoader # pylint: disable=g-import-not-at-top
-contrib = LazyLoader('contrib', globals(), 'tensorflow.contrib')
+_CONTRIB_WARNING = """
+WARNING: The TensorFlow contrib module will not be included in TensorFlow 2.0.
+For more information, please see:
+ * https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md
+ * https://github.com/tensorflow/addons
+If you depend on functionality not listed there, please file an issue.
+"""
+contrib = LazyLoader('contrib', globals(), 'tensorflow.contrib',
+ _CONTRIB_WARNING)
del LazyLoader
# The templated code that replaces the placeholder above sometimes
# sets the __all__ variable. If it does, we have to be sure to add
@@ -45,9 +67,44 @@ app.flags = flags # pylint: disable=undefined-variable
# Make sure directory containing top level submodules is in
# the __path__ so that "from tensorflow.foo import bar" works.
_tf_api_dir = _os.path.dirname(_os.path.dirname(app.__file__)) # pylint: disable=undefined-variable
-if _tf_api_dir not in __path__:
+if not hasattr(_current_module, '__path__'):
+ __path__ = [_tf_api_dir]
+elif _tf_api_dir not in __path__:
__path__.append(_tf_api_dir)
+# Load all plugin libraries from site-packages/tensorflow-plugins if we are
+# running under pip.
+# TODO(gunan): Enable setting an environment variable to define arbitrary plugin
+# directories.
+# TODO(gunan): Find a better location for this code snippet.
+from tensorflow.python.framework import load_library as _ll
+from tensorflow.python.lib.io import file_io as _fi
+
+# Get sitepackages directories for the python installation.
+_site_packages_dirs = []
+_site_packages_dirs += [_site.USER_SITE]
+_site_packages_dirs += [_p for _p in _sys.path if 'site-packages' in _p]
+if 'getsitepackages' in dir(_site):
+ _site_packages_dirs += _site.getsitepackages()
+
+if 'sysconfig' in dir(_distutils):
+ _site_packages_dirs += [_distutils.sysconfig.get_python_lib()]
+
+_site_packages_dirs = list(set(_site_packages_dirs))
+
+# Find the location of this exact file.
+_current_file_location = _inspect.getfile(_inspect.currentframe())
+
+def _running_from_pip_package():
+ return any(
+ _current_file_location.startswith(dir_) for dir_ in _site_packages_dirs)
+
+if _running_from_pip_package():
+ for s in _site_packages_dirs:
+ # TODO(gunan): Add sanity checks to loaded modules here.
+ plugin_dir = _os.path.join(s, 'tensorflow-plugins')
+ if _fi.file_exists(plugin_dir):
+ _ll.load_library(plugin_dir)
# These symbols appear because we import the python package which
# in turn imports from tensorflow.core and tensorflow.python. They
diff --git a/tensorflow/c/BUILD b/tensorflow/c/BUILD
index ad2ae08a37b628b7343e58088a5340d6525675d1..3e1f220db233001ba652120657631f8c1a296b35 100644
--- a/tensorflow/c/BUILD
+++ b/tensorflow/c/BUILD
@@ -123,7 +123,6 @@ tf_cuda_library(
"//tensorflow/c/eager:c_api",
"//tensorflow/c/eager:c_api_internal",
"//tensorflow/compiler/jit:flags",
- "//tensorflow/contrib/tpu:all_ops",
"//tensorflow/core:core_cpu",
"//tensorflow/core:framework",
"//tensorflow/core:lib",
@@ -175,6 +174,32 @@ tf_cuda_library(
],
)
+tf_cuda_library(
+ name = "env",
+ srcs = [
+ "env.cc",
+ ],
+ hdrs = [
+ "env.h",
+ ],
+ copts = tf_copts(),
+ visibility = ["//visibility:public"],
+ deps = select({
+ "//tensorflow:android": [
+ ":c_api",
+ ":tf_status_helper",
+ "//tensorflow/core:android_tensorflow_lib_lite",
+ "//tensorflow/core:lib",
+ ],
+ "//conditions:default": [
+ ":c_api",
+ ":tf_status_helper",
+ "//tensorflow/core:framework",
+ "//tensorflow/core:lib",
+ ],
+ }) + [":c_api_internal"],
+)
+
tf_cuda_library(
name = "kernels",
srcs = [
@@ -223,6 +248,24 @@ tf_cuda_library(
],
)
+tf_cc_test(
+ name = "c_test",
+ srcs = ["c_test.c"],
+ extra_copts = ["-std=c11"],
+ tags = [
+ # TODO(b/121223209): Re-enable after fixing asan memory leaks and MacOS
+ # build errors.
+ "noasan",
+ "no_mac",
+ ],
+ deps = [
+ ":c_api",
+ ":c_api_experimental",
+ ":env",
+ ":kernels",
+ ],
+)
+
tf_cuda_cc_test(
name = "c_api_test",
size = "small",
@@ -334,6 +377,27 @@ tf_kernel_library(
alwayslink = 1,
)
+tf_cuda_cc_test(
+ name = "env_test",
+ size = "small",
+ srcs = ["env_test.cc"],
+ linkopts = select({
+ "//tensorflow:darwin": ["-headerpad_max_install_names"],
+ "//conditions:default": [],
+ }),
+ tags = ["noasan"],
+ # We must ensure that the dependencies can be dynamically linked since
+ # the shared library must be able to use core:framework.
+ # linkstatic = tf_kernel_tests_linkstatic(),
+ deps = [
+ ":c_api",
+ ":env",
+ "//tensorflow/core:lib",
+ "//tensorflow/core:test",
+ "//tensorflow/core:test_main",
+ ],
+)
+
tf_cuda_cc_test(
name = "kernels_test",
size = "small",
diff --git a/tensorflow/c/c_api.cc b/tensorflow/c/c_api.cc
index 94d18eb8b04e3534be547aca5cfbb32da40ffbf6..9580215a317b1a6b1cdacbd430a1764af61be990 100644
--- a/tensorflow/c/c_api.cc
+++ b/tensorflow/c/c_api.cc
@@ -488,6 +488,7 @@ static TF_Tensor* EmptyTensor(TF_DataType dtype, const TensorShape& shape) {
// Non-static for testing.
TF_Tensor* TF_TensorFromTensor(const tensorflow::Tensor& src,
TF_Status* status) {
+ TF_SetStatus(status, TF_OK, "");
if (!src.IsInitialized()) {
status->status = FailedPrecondition(
"attempt to use a tensor with an uninitialized value");
diff --git a/tensorflow/c/c_api.h b/tensorflow/c/c_api.h
index 3d56268110edbe96616201d15a69cc8c84d3115a..c7abba85521fccec07983cd5ab4f94a8368d6181 100644
--- a/tensorflow/c/c_api.h
+++ b/tensorflow/c/c_api.h
@@ -91,7 +91,7 @@ extern "C" {
// --------------------------------------------------------------------------
// TF_Version returns a string describing version information of the
// TensorFlow library. TensorFlow using semantic versioning.
-TF_CAPI_EXPORT extern const char* TF_Version();
+TF_CAPI_EXPORT extern const char* TF_Version(void);
// --------------------------------------------------------------------------
// TF_DataType holds the type for a scalar value. E.g., one slot in a tensor.
@@ -157,7 +157,7 @@ typedef enum TF_Code {
typedef struct TF_Status TF_Status;
// Return a new status object.
-TF_CAPI_EXPORT extern TF_Status* TF_NewStatus();
+TF_CAPI_EXPORT extern TF_Status* TF_NewStatus(void);
// Delete a previously created status object.
TF_CAPI_EXPORT extern void TF_DeleteStatus(TF_Status*);
@@ -196,7 +196,7 @@ TF_CAPI_EXPORT extern TF_Buffer* TF_NewBufferFromString(const void* proto,
size_t proto_len);
// Useful for passing *out* a protobuf.
-TF_CAPI_EXPORT extern TF_Buffer* TF_NewBuffer();
+TF_CAPI_EXPORT extern TF_Buffer* TF_NewBuffer(void);
TF_CAPI_EXPORT extern void TF_DeleteBuffer(TF_Buffer*);
@@ -305,7 +305,7 @@ TF_CAPI_EXPORT extern size_t TF_StringEncodedSize(size_t len);
typedef struct TF_SessionOptions TF_SessionOptions;
// Return a new options object.
-TF_CAPI_EXPORT extern TF_SessionOptions* TF_NewSessionOptions();
+TF_CAPI_EXPORT extern TF_SessionOptions* TF_NewSessionOptions(void);
// Set the target in TF_SessionOptions.options.
// target can be empty, a single entry, or a comma separated list of entries.
@@ -338,7 +338,7 @@ TF_CAPI_EXPORT extern void TF_DeleteSessionOptions(TF_SessionOptions*);
typedef struct TF_Graph TF_Graph;
// Return a new graph object.
-TF_CAPI_EXPORT extern TF_Graph* TF_NewGraph();
+TF_CAPI_EXPORT extern TF_Graph* TF_NewGraph(void);
// Destroy an options object. Graph will be deleted once no more
// TFSession's are referencing it.
@@ -890,7 +890,8 @@ TF_CAPI_EXPORT extern void TF_GraphVersions(TF_Graph* graph,
// TF_GraphImportGraphDef.
typedef struct TF_ImportGraphDefOptions TF_ImportGraphDefOptions;
-TF_CAPI_EXPORT extern TF_ImportGraphDefOptions* TF_NewImportGraphDefOptions();
+TF_CAPI_EXPORT extern TF_ImportGraphDefOptions* TF_NewImportGraphDefOptions(
+ void);
TF_CAPI_EXPORT extern void TF_DeleteImportGraphDefOptions(
TF_ImportGraphDefOptions* opts);
@@ -1611,7 +1612,7 @@ TF_CAPI_EXPORT extern void TF_DeleteLibraryHandle(TF_Library* lib_handle);
//
// The data in the buffer will be the serialized OpList proto for ops registered
// in this address space.
-TF_CAPI_EXPORT extern TF_Buffer* TF_GetAllOpList();
+TF_CAPI_EXPORT extern TF_Buffer* TF_GetAllOpList(void);
// TF_ApiDefMap encapsulates a collection of API definitions for an operation.
//
diff --git a/tensorflow/c/c_api_experimental.cc b/tensorflow/c/c_api_experimental.cc
index 38e29aa74a90f4e85d1369b6928a5a58c531b2da..f04b285037dff403428ed74fe90eac60339fe36b 100644
--- a/tensorflow/c/c_api_experimental.cc
+++ b/tensorflow/c/c_api_experimental.cc
@@ -66,7 +66,8 @@ void TF_EnableXLACompilation(TF_SessionOptions* options, unsigned char enable) {
}
TF_Buffer* TF_CreateConfig(unsigned char enable_xla_compilation,
- unsigned char gpu_memory_allow_growth) {
+ unsigned char gpu_memory_allow_growth,
+ unsigned int num_cpu_devices) {
tensorflow::ConfigProto config;
auto* optimizer_options =
config.mutable_graph_options()->mutable_optimizer_options();
@@ -87,6 +88,8 @@ TF_Buffer* TF_CreateConfig(unsigned char enable_xla_compilation,
auto* gpu_options = config.mutable_gpu_options();
gpu_options->set_allow_growth(gpu_memory_allow_growth);
+ (*config.mutable_device_count())["CPU"] = num_cpu_devices;
+
// TODO(b/113217601): This is needed for EagerContext::runner_ to use a
// threadpool, so that we avoid the possibility of running the runner_ in the
// threadpool of GPU event mgr, as that can trigger more callbacks to be
@@ -8535,8 +8538,9 @@ TFE_Context* TFE_CreateContextFromSession(TF_Session* session,
// Reduce GPU memory allocation, and set appropriate config options for TFE
// context.
- auto* config =
- TF_CreateConfig(/*xla*/ false, /* gpu_memory_allow_growth */ true);
+ auto* config = TF_CreateConfig(
+ /*xla*/ false, /* gpu_memory_allow_growth */ true, /* num_cpu_devices */
+ 10);
TFE_ContextOptionsSetConfig(opts, config->data, config->length, status);
if (!status->status.ok()) {
CHECK(!config);
@@ -8886,3 +8890,54 @@ TFE_TensorHandle* TFE_NewTensorHandleFromScalar(TF_DataType dtype_arg,
std::memcpy(tensorflow::TensorCApi::Buffer(tensor)->data(), data, len);
return new TFE_TensorHandle(tensor, nullptr, nullptr);
}
+
+namespace {
+tensorflow::Status EnableCollectiveOps(const tensorflow::ServerDef& server_def,
+ TFE_Context* ctx) {
+ // We don't use the TF_RETURN_IF_ERROR macro directly since that destroys the
+ // server object (which currently CHECK-fails) and we miss the error, instead,
+ // we log the error, and then return to allow the user to see the error
+ // message.
+#define LOG_AND_RETURN_IF_ERROR(...) \
+ do { \
+ const ::tensorflow::Status _status = (__VA_ARGS__); \
+ if (TF_PREDICT_FALSE(!_status.ok())) { \
+ LOG(ERROR) << _status.error_message(); \
+ return _status; \
+ } \
+ } while (0);
+
+ std::unique_ptr server;
+ LOG_AND_RETURN_IF_ERROR(tensorflow::NewServer(server_def, &server));
+
+ tensorflow::GrpcServer* grpc_server =
+ dynamic_cast(server.get());
+ if (grpc_server == nullptr) {
+ LOG_AND_RETURN_IF_ERROR(tensorflow::errors::Internal(
+ "Currently, TFE_NewContext only supports tensorflow::GrpcServer."));
+ }
+
+ LOG_AND_RETURN_IF_ERROR(grpc_server->Start());
+
+ LOG_AND_RETURN_IF_ERROR(ctx->context.StoreCollectiveOpsServer(
+ std::move(server), grpc_server->worker_env()->device_mgr,
+ grpc_server->worker_env()->collective_executor_mgr));
+
+ return tensorflow::Status::OK();
+#undef LOG_AND_RETURN_IF_ERROR
+}
+} // namespace
+
+// Set server_def on the context, possibly updating it.
+TF_CAPI_EXPORT extern void TFE_EnableCollectiveOps(TFE_Context* ctx,
+ const void* proto,
+ size_t proto_len,
+ TF_Status* status) {
+ tensorflow::ServerDef server_def;
+ if (!server_def.ParseFromArray(proto, proto_len)) {
+ status->status = tensorflow::errors::InvalidArgument(
+ "Invalid tensorflow.ServerDef protocol buffer");
+ return;
+ }
+ status->status = EnableCollectiveOps(server_def, ctx);
+}
diff --git a/tensorflow/c/c_api_experimental.h b/tensorflow/c/c_api_experimental.h
index 80c8bfe594c4c89606efd01bec7f50e7a86b5bda..e6d04d0c2b25a3f7b1ebf50c58268f003595a520 100644
--- a/tensorflow/c/c_api_experimental.h
+++ b/tensorflow/c/c_api_experimental.h
@@ -67,9 +67,10 @@ TF_CAPI_EXPORT extern void TF_EnableXLACompilation(TF_SessionOptions* options,
// a) ConfigProto.optimizer_options.global_jit_level is set to to ON_1 if
// `enable_xla_compilation` is non-zero, and OFF otherwise.
// b) ConfigProto.gpu_options.allow_growth is set to `gpu_memory_allow_growth`.
+// c) ConfigProto.device_count is set to `num_cpu_devices`.
TF_CAPI_EXPORT extern TF_Buffer* TF_CreateConfig(
- unsigned char enable_xla_compilation,
- unsigned char gpu_memory_allow_growth);
+ unsigned char enable_xla_compilation, unsigned char gpu_memory_allow_growth,
+ unsigned int num_cpu_devices);
// Create a serialized tensorflow.RunOptions proto, where RunOptions.trace_level
// is set to FULL_TRACE if `enable_full_trace` is non-zero, and NO_TRACE
@@ -239,13 +240,21 @@ TF_CAPI_EXPORT void TF_InitMain(const char* usage, int* argc, char*** argv);
// Platform-specific implementation to return an unused port. (This should used
// in tests only.)
-TF_CAPI_EXPORT int TF_PickUnusedPortOrDie();
+TF_CAPI_EXPORT int TF_PickUnusedPortOrDie(void);
// Fast path method that makes constructing a single scalar tensor require less
// overhead and copies.
TF_CAPI_EXPORT extern TFE_TensorHandle* TFE_NewTensorHandleFromScalar(
TF_DataType dtype, void* scalar, size_t len);
+// Specify the server_def that enables collective ops.
+// This is different to the above function in that it doesn't create remote
+// contexts, and remotely executing ops is not possible. It just enables
+// communication for collective ops.
+TF_CAPI_EXPORT extern void TFE_EnableCollectiveOps(TFE_Context* ctx,
+ const void* proto,
+ size_t proto_len,
+ TF_Status* status);
#ifdef __cplusplus
} /* end extern "C" */
#endif
diff --git a/tensorflow/c/c_test.c b/tensorflow/c/c_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0ed5ccd15d9524e2c14630d8ef92f6b3ef9b059
--- /dev/null
+++ b/tensorflow/c/c_test.c
@@ -0,0 +1,79 @@
+/* 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
+#include
+#include
+#include
+#include
+#include
+
+#include "tensorflow/c/c_api.h"
+#include "tensorflow/c/c_api_experimental.h"
+#include "tensorflow/c/env.h"
+#include "tensorflow/c/kernels.h"
+
+// A compute function. This will never actually get called in this test, it's
+// just nice to know that it compiles.
+void compute(void* kernel, TF_OpKernelContext* ctx) {
+ TF_Tensor* input;
+ TF_Status* s = TF_NewStatus();
+ TF_GetInput(ctx, 0, &input, s);
+ TF_DeleteTensor(input);
+ TF_DeleteStatus(s);
+}
+
+// Exercises tensorflow's C API.
+int main(int argc, char** argv) {
+ TF_InitMain(argv[0], &argc, &argv);
+
+ struct TF_StringStream* s = TF_GetLocalTempDirectories();
+ const char* path;
+
+ if (!TF_StringStreamNext(s, &path)) {
+ fprintf(stderr, "TF_GetLocalTempDirectories returned no results\n");
+ return 1;
+ }
+
+ char file_name[100];
+ struct timeval t;
+ if (gettimeofday(&t, NULL)) {
+ perror("gettimeofday failed");
+ return 1;
+ }
+ snprintf(file_name, sizeof(file_name), "test-%d-%ld.txt", getpid(), t.tv_sec);
+
+ size_t length = 2 + strlen(path) + strlen(file_name);
+ char* full_path = malloc(length);
+ snprintf(full_path, length, "%s/%s", path, file_name);
+
+ TF_WritableFileHandle* h;
+ TF_Status* status = TF_NewStatus();
+ TF_NewWritableFile(full_path, &h, status);
+ if (TF_GetCode(status) != TF_OK) {
+ fprintf(stderr, "TF_NewWritableFile failed: %s\n", TF_Message(status));
+ return 1;
+ }
+ fprintf(stderr, "wrote %s\n", full_path);
+ free(full_path);
+ TF_StringStreamDone(s);
+
+ TF_KernelBuilder* b =
+ TF_NewKernelBuilder("SomeOp", "SomeDevice", NULL, &compute, NULL);
+ TF_RegisterKernelBuilder("someKernel", b, status);
+
+ TF_DeleteStatus(status);
+ return 0;
+}
diff --git a/tensorflow/c/eager/c_api.h b/tensorflow/c/eager/c_api.h
index 8d6c8d958d5961fce817156a14eb2b2940c1f2f0..120748ab763a3358b6e38e64bb3b6fd2ea32f7c3 100755
--- a/tensorflow/c/eager/c_api.h
+++ b/tensorflow/c/eager/c_api.h
@@ -48,7 +48,7 @@ extern "C" {
typedef struct TFE_ContextOptions TFE_ContextOptions;
// Return a new options object.
-TF_CAPI_EXPORT extern TFE_ContextOptions* TFE_NewContextOptions();
+TF_CAPI_EXPORT extern TFE_ContextOptions* TFE_NewContextOptions(void);
// Set the config in TF_ContextOptions.options.
// config should be a serialized tensorflow.ConfigProto proto.
@@ -170,23 +170,11 @@ TF_CAPI_EXPORT extern int64_t TFE_TensorHandleDim(TFE_TensorHandle* h,
int dim_index,
TF_Status* status);
-// Returns the device of the operation that produced `h`.
-// If `h` was produced by a copy, returns the destination device of
-// the copy. Note that returned device name is not always the device
-// holding the tensor handle's memory. If you want the latter, use
-// TFE_TensorHandleBackingDeviceName.
-// This function will block till the operation that produces `h` has completed.
-//
-// Device on which the kernel of the operation that produced `h` ran.
-//
-// If `h` was produced by a copy, returns the destination device of
-// the copy.
-//
-// Note that returned device name is not always the device that owns the memory
-// that backs the tensor handle. For the latter see
-// TFE_TensorHandleBackingDeviceName.
-//
-// This function will block till the operation that produces `h` has completed.
+// Returns the device of the operation that produced `h`. If `h` was produced by
+// a copy, returns the destination device of the copy. Note that the returned
+// device name is not always the device holding the tensor handle's memory. If
+// you want the latter, use TFE_TensorHandleBackingDeviceName. This function
+// will block till the operation that produces `h` has completed.
TF_CAPI_EXPORT extern const char* TFE_TensorHandleDeviceName(
TFE_TensorHandle* h, TF_Status* status);
diff --git a/tensorflow/c/env.cc b/tensorflow/c/env.cc
new file mode 100644
index 0000000000000000000000000000000000000000..1c35ff9001d0ee1ab0fbae9e1bcc07116fab1065
--- /dev/null
+++ b/tensorflow/c/env.cc
@@ -0,0 +1,183 @@
+/* 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/env.h"
+
+#include "tensorflow/c/c_api_internal.h"
+#include "tensorflow/c/tf_status_helper.h"
+#include "tensorflow/core/platform/env.h"
+#include "tensorflow/core/platform/types.h"
+
+struct TF_StringStream {
+ std::vector<::tensorflow::string>* list;
+ size_t position;
+};
+
+void TF_CreateDir(const char* dirname, TF_Status* status) {
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(
+ status, ::tensorflow::Env::Default()->CreateDir(dirname));
+}
+
+void TF_DeleteDir(const char* dirname, TF_Status* status) {
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(
+ status, ::tensorflow::Env::Default()->DeleteDir(dirname));
+}
+
+void TF_DeleteRecursively(const char* dirname, int64_t* undeleted_file_count,
+ int64_t* undeleted_dir_count, TF_Status* status) {
+ ::tensorflow::int64 f, d;
+
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(
+ status, ::tensorflow::Env::Default()->DeleteRecursively(dirname, &f, &d));
+ *undeleted_file_count = f;
+ *undeleted_dir_count = d;
+}
+
+void TF_FileStat(const char* filename, TF_FileStatistics* stats,
+ TF_Status* status) {
+ ::tensorflow::FileStatistics cc_stats;
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Status s =
+ ::tensorflow::Env::Default()->Stat(filename, &cc_stats);
+ ::tensorflow::Set_TF_Status_from_Status(status, s);
+ if (s.ok()) {
+ stats->length = cc_stats.length;
+ stats->mtime_nsec = cc_stats.mtime_nsec;
+ stats->is_directory = cc_stats.is_directory;
+ }
+}
+
+void TF_NewWritableFile(const char* filename, TF_WritableFileHandle** handle,
+ TF_Status* status) {
+ std::unique_ptr<::tensorflow::WritableFile> f;
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Status s =
+ ::tensorflow::Env::Default()->NewWritableFile(filename, &f);
+ ::tensorflow::Set_TF_Status_from_Status(status, s);
+
+ if (s.ok()) {
+ *handle = reinterpret_cast(f.release());
+ }
+}
+
+void TF_CloseWritableFile(TF_WritableFileHandle* handle, TF_Status* status) {
+ auto* cc_file = reinterpret_cast<::tensorflow::WritableFile*>(handle);
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(status, cc_file->Close());
+ delete cc_file;
+}
+
+void TF_SyncWritableFile(TF_WritableFileHandle* handle, TF_Status* status) {
+ auto* cc_file = reinterpret_cast<::tensorflow::WritableFile*>(handle);
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(status, cc_file->Sync());
+}
+
+void TF_FlushWritableFile(TF_WritableFileHandle* handle, TF_Status* status) {
+ auto* cc_file = reinterpret_cast<::tensorflow::WritableFile*>(handle);
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(status, cc_file->Flush());
+}
+
+void TF_AppendWritableFile(TF_WritableFileHandle* handle, const char* data,
+ size_t length, TF_Status* status) {
+ auto* cc_file = reinterpret_cast<::tensorflow::WritableFile*>(handle);
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(
+ status, cc_file->Append(::tensorflow::StringPiece{data, length}));
+}
+
+void TF_DeleteFile(const char* filename, TF_Status* status) {
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(
+ status, ::tensorflow::Env::Default()->DeleteFile(filename));
+}
+
+bool TF_StringStreamNext(TF_StringStream* list, const char** result) {
+ if (list->position >= list->list->size()) {
+ *result = nullptr;
+ return false;
+ }
+
+ *result = list->list->at(list->position++).c_str();
+ return true;
+}
+
+void TF_StringStreamDone(TF_StringStream* list) {
+ delete list->list;
+ delete list;
+}
+TF_StringStream* TF_GetChildren(const char* dirname, TF_Status* status) {
+ auto* children = new std::vector<::tensorflow::string>;
+
+ TF_SetStatus(status, TF_OK, "");
+ ::tensorflow::Set_TF_Status_from_Status(
+ status, ::tensorflow::Env::Default()->GetChildren(dirname, children));
+
+ auto* list = new TF_StringStream;
+ list->list = children;
+ list->position = 0;
+ return list;
+}
+
+TF_StringStream* TF_GetLocalTempDirectories() {
+ auto* tmpdirs = new std::vector<::tensorflow::string>;
+
+ ::tensorflow::Env::Default()->GetLocalTempDirectories(tmpdirs);
+
+ auto* list = new TF_StringStream;
+ list->list = tmpdirs;
+ list->position = 0;
+ return list;
+}
+
+TF_CAPI_EXPORT extern uint64_t TF_NowNanos(void) {
+ return ::tensorflow::Env::Default()->NowNanos();
+}
+
+// Returns the number of microseconds since the Unix epoch.
+TF_CAPI_EXPORT extern uint64_t TF_NowMicros(void) {
+ return ::tensorflow::Env::Default()->NowMicros();
+}
+
+// Returns the number of seconds since the Unix epoch.
+TF_CAPI_EXPORT extern uint64_t TF_NowSeconds(void) {
+ return ::tensorflow::Env::Default()->NowSeconds();
+}
+
+void TF_DefaultThreadOptions(TF_ThreadOptions* options) {
+ options->stack_size = 0;
+ options->guard_size = 0;
+ options->numa_node = -1;
+}
+
+TF_Thread* TF_StartThread(const TF_ThreadOptions* options,
+ const char* thread_name, void (*work_func)(void*),
+ void* param) {
+ ::tensorflow::ThreadOptions cc_options;
+ cc_options.stack_size = options->stack_size;
+ cc_options.guard_size = options->guard_size;
+ cc_options.numa_node = options->numa_node;
+ return reinterpret_cast(::tensorflow::Env::Default()->StartThread(
+ cc_options, thread_name, [=]() { (*work_func)(param); }));
+}
+
+void TF_JoinThread(TF_Thread* thread) {
+ // ::tensorflow::Thread joins on destruction
+ delete reinterpret_cast<::tensorflow::Thread*>(thread);
+}
diff --git a/tensorflow/c/env.h b/tensorflow/c/env.h
new file mode 100644
index 0000000000000000000000000000000000000000..73078fcbbc5ae4c042f4a992655072a838e42915
--- /dev/null
+++ b/tensorflow/c/env.h
@@ -0,0 +1,195 @@
+/* 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
+#include
+#include
+
+#ifndef TENSORFLOW_C_ENV_H_
+#define TENSORFLOW_C_ENV_H_
+
+#include "tensorflow/c/c_api.h"
+
+// --------------------------------------------------------------------------
+// C API for tensorflow::Env.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct TF_WritableFileHandle TF_WritableFileHandle;
+typedef struct TF_StringStream TF_StringStream;
+typedef struct TF_Thread TF_Thread;
+
+typedef struct TF_FileStatistics {
+ // The length of the file in bytes.
+ int64_t length;
+ // The last modified time in nanoseconds.
+ int64_t mtime_nsec;
+ // Whether the name refers to a directory.
+ bool is_directory;
+} TF_FileStatistics;
+
+typedef struct TF_ThreadOptions {
+ // Thread stack size to use (in bytes), zero implies that the system default
+ // will be used.
+ size_t stack_size;
+
+ // Guard area size to use near thread stacks to use (in bytes), zero implies
+ // that the system default will be used.
+ size_t guard_size;
+
+ // The NUMA node to use, -1 implies that there should be no NUMA affinity for
+ // this thread.
+ int numa_node;
+} TF_ThreadOptions;
+
+// Creates the specified directory. Typical status code are:
+// * TF_OK - successfully created the directory
+// * TF_ALREADY_EXISTS - directory already exists
+// * TF_PERMISSION_DENIED - dirname is not writable
+TF_CAPI_EXPORT extern void TF_CreateDir(const char* dirname, TF_Status* status);
+
+// Deletes the specified directory. Typical status codes are:
+// * TF_OK - successfully deleted the directory
+// * TF_FAILED_PRECONDITION - the directory is not empty
+TF_CAPI_EXPORT extern void TF_DeleteDir(const char* dirname, TF_Status* status);
+
+// Deletes the specified directory and all subdirectories and files underneath
+// it. This is accomplished by traversing the directory tree rooted at dirname
+// and deleting entries as they are encountered.
+//
+// If dirname itself is not readable or does not exist, *undeleted_dir_count is
+// set to 1, *undeleted_file_count is set to 0 and an appropriate status (e.g.
+// TF_NOT_FOUND) is returned.
+//
+// If dirname and all its descendants were successfully deleted, TF_OK is
+// returned and both error counters are set to zero.
+//
+// Otherwise, while traversing the tree, undeleted_file_count and
+// undeleted_dir_count are updated if an entry of the corresponding type could
+// not be deleted. The returned error status represents the reason that any one
+// of these entries could not be deleted.
+//
+// Typical status codes:
+// * TF_OK - dirname exists and we were able to delete everything underneath
+// * TF_NOT_FOUND - dirname doesn't exist
+// * TF_PERMISSION_DENIED - dirname or some descendant is not writable
+// * TF_UNIMPLEMENTED - some underlying functions (like Delete) are not
+// implemented
+TF_CAPI_EXPORT extern void TF_DeleteRecursively(const char* dirname,
+ int64_t* undeleted_file_count,
+ int64_t* undeleted_dir_count,
+ TF_Status* status);
+
+// Obtains statistics for the given path. If status is TF_OK, *stats is
+// updated, otherwise it is not touched.
+TF_CAPI_EXPORT extern void TF_FileStat(const char* filename,
+ TF_FileStatistics* stats,
+ TF_Status* status);
+
+// Creates or truncates the given filename and returns a handle to be used for
+// appending data to the file. If status is TF_OK, *handle is updated and the
+// caller is responsible for freeing it (see TF_CloseWritableFile).
+TF_CAPI_EXPORT extern void TF_NewWritableFile(const char* filename,
+ TF_WritableFileHandle** handle,
+ TF_Status* status);
+
+// Closes the given handle and frees its memory. If there was a problem closing
+// the file, it is indicated by status. Memory is freed in any case.
+TF_CAPI_EXPORT extern void TF_CloseWritableFile(TF_WritableFileHandle* handle,
+ TF_Status* status);
+
+// Syncs content of the handle to the filesystem. Blocks waiting for the
+// filesystem to indicate that the content has been persisted.
+TF_CAPI_EXPORT extern void TF_SyncWritableFile(TF_WritableFileHandle* handle,
+ TF_Status* status);
+
+// Flush local buffers to the filesystem. If the process terminates after a
+// successful flush, the contents may still be persisted, since the underlying
+// filesystem may eventually flush the contents. If the OS or machine crashes
+// after a successful flush, the contents may or may not be persisted, depending
+// on the implementation.
+TF_CAPI_EXPORT extern void TF_FlushWritableFile(TF_WritableFileHandle* handle,
+ TF_Status* status);
+
+// Appends the given bytes to the file. Any failure to do so is indicated in
+// status.
+TF_CAPI_EXPORT extern void TF_AppendWritableFile(TF_WritableFileHandle* handle,
+ const char* data,
+ size_t length,
+ TF_Status* status);
+
+// Deletes the named file and indicates whether successful in *status.
+TF_CAPI_EXPORT extern void TF_DeleteFile(const char* filename,
+ TF_Status* status);
+
+// Retrieves the next item from the given TF_StringStream and places a pointer
+// to it in *result. If no more items are in the list, *result is set to NULL
+// and false is returned.
+//
+// Ownership of the items retrieved with this function remains with the library.
+// Item points are invalidated after a call to TF_StringStreamDone.
+TF_CAPI_EXPORT extern bool TF_StringStreamNext(TF_StringStream* list,
+ const char** result);
+
+// Frees the resources associated with given string list. All pointers returned
+// by TF_StringStreamNext are invalid after this call.
+TF_CAPI_EXPORT extern void TF_StringStreamDone(TF_StringStream* list);
+
+// Retrieves the list of children of the given directory. You can iterate
+// through the list with TF_StringStreamNext. The caller is responsible for
+// freeing the list (see TF_StringStreamDone).
+TF_CAPI_EXPORT extern TF_StringStream* TF_GetChildren(const char* filename,
+ TF_Status* status);
+
+// Retrieves a list of directory names on the local machine that may be used for
+// temporary storage. You can iterate through the list with TF_StringStreamNext.
+// The caller is responsible for freeing the list (see TF_StringStreamDone).
+TF_CAPI_EXPORT extern TF_StringStream* TF_GetLocalTempDirectories(void);
+
+// Returns the number of nanoseconds since the Unix epoch.
+TF_CAPI_EXPORT extern uint64_t TF_NowNanos(void);
+
+// Returns the number of microseconds since the Unix epoch.
+TF_CAPI_EXPORT extern uint64_t TF_NowMicros(void);
+
+// Returns the number of seconds since the Unix epoch.
+TF_CAPI_EXPORT extern uint64_t TF_NowSeconds(void);
+
+// Populates a TF_ThreadOptions struct with system-default values.
+TF_CAPI_EXPORT extern void TF_DefaultThreadOptions(TF_ThreadOptions* options);
+
+// Returns a new thread that is running work_func and is identified
+// (for debugging/performance-analysis) by thread_name.
+//
+// The given param (which may be null) is passed to work_func when the thread
+// starts. In this way, data may be passed from the thread back to the caller.
+//
+// Caller takes ownership of the result and must call TF_JoinThread on it
+// eventually.
+TF_CAPI_EXPORT extern TF_Thread* TF_StartThread(const TF_ThreadOptions* options,
+ const char* thread_name,
+ void (*work_func)(void*),
+ void* param);
+
+// Waits for the given thread to finish execution, then deletes it.
+TF_CAPI_EXPORT extern void TF_JoinThread(TF_Thread* thread);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TENSORFLOW_C_ENV_H_
diff --git a/tensorflow/c/env_test.cc b/tensorflow/c/env_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..687ad024137352662759ec1f43df87e89faca353
--- /dev/null
+++ b/tensorflow/c/env_test.cc
@@ -0,0 +1,127 @@
+/* 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/env.h"
+
+#include "tensorflow/c/c_api.h"
+#include "tensorflow/core/lib/io/path.h"
+#include "tensorflow/core/platform/mutex.h"
+#include "tensorflow/core/platform/test.h"
+#include "tensorflow/core/platform/types.h"
+
+#define ASSERT_TF_OK(x) ASSERT_EQ(TF_OK, TF_GetCode(x))
+
+TEST(TestEnv, TestDirHandling) {
+ TF_StringStream* tempdirs = TF_GetLocalTempDirectories();
+ const char* tempdir;
+ bool found = false;
+ while (TF_StringStreamNext(tempdirs, &tempdir)) {
+ found = true;
+
+ TF_Status* s = TF_NewStatus();
+
+ ::tensorflow::string dirpath =
+ ::tensorflow::io::JoinPath(tempdir, "somedir");
+ TF_CreateDir(dirpath.c_str(), s);
+ ASSERT_TF_OK(s) << "TF_CreateDir failed for " << dirpath << ": "
+ << TF_Message(s);
+
+ ::tensorflow::string filepath =
+ ::tensorflow::io::JoinPath(dirpath, "somefile.txt");
+ TF_WritableFileHandle* handle;
+ TF_NewWritableFile(filepath.c_str(), &handle, s);
+ ASSERT_TF_OK(s) << "NewWritableFile failed for " << filepath << ": "
+ << TF_Message(s);
+
+ const char* data = "Hello, world!\n";
+ TF_AppendWritableFile(handle, data, strlen(data), s);
+ ASSERT_TF_OK(s) << "TF_AppendWritableFile failed to append data to file at "
+ << filepath << ": " << TF_Message(s);
+
+ TF_CloseWritableFile(handle, s);
+ ASSERT_TF_OK(s) << "TF_CloseWritableFile failed to close handle to "
+ << filepath << ": " << TF_Message(s);
+
+ TF_StringStream* children = TF_GetChildren(dirpath.c_str(), s);
+ ASSERT_TF_OK(s) << "TF_GetChildren failed for " << dirpath;
+ const char* childpath;
+ ASSERT_TRUE(TF_StringStreamNext(children, &childpath));
+ ASSERT_EQ(::tensorflow::string(childpath), "somefile.txt");
+ // There should only be one file in this directory.
+ ASSERT_FALSE(TF_StringStreamNext(children, &childpath));
+ ASSERT_EQ(childpath, nullptr);
+ TF_StringStreamDone(children);
+
+ TF_FileStatistics stats;
+ TF_FileStat(filepath.c_str(), &stats, s);
+ ASSERT_EQ(stats.length, strlen(data));
+ ASSERT_FALSE(stats.is_directory);
+ ASSERT_GT(stats.mtime_nsec, 0);
+
+ // Trying to delete a non-empty directory should fail.
+ TF_DeleteDir(dirpath.c_str(), s);
+ ASSERT_NE(TF_OK, TF_GetCode(s))
+ << "TF_DeleteDir unexpectedly succeeded with a non-empty directory "
+ << dirpath;
+
+ TF_DeleteFile(filepath.c_str(), s);
+ ASSERT_TF_OK(s) << "TF_DeleteFile failed for " << filepath << ": "
+ << TF_Message(s);
+
+ // Now deleting the directory should work.
+ TF_DeleteDir(dirpath.c_str(), s);
+ ASSERT_TF_OK(s) << "TF_DeleteDir failed for " << dirpath << ": "
+ << TF_Message(s);
+
+ TF_DeleteStatus(s);
+ break;
+ }
+
+ ASSERT_TRUE(found) << "expected at least one temp dir";
+
+ TF_StringStreamDone(tempdirs);
+}
+
+TEST(TestEnv, TestTimeFunctions) {
+ ASSERT_GE(TF_NowSeconds(), 946684800); // Midnight Jan 1, 2000
+ ASSERT_GE(TF_NowMicros(), 946684800 * 1e6);
+ ASSERT_GE(TF_NowNanos(), 946684800 * 1e9);
+}
+
+namespace {
+
+struct SomeThreadData {
+ ::tensorflow::mutex mu;
+ bool did_work = false;
+};
+
+void SomeThreadFunc(void* data) {
+ auto* real_data = static_cast(data);
+ ::tensorflow::mutex_lock l(real_data->mu);
+ real_data->did_work = true;
+}
+
+} // namespace
+
+TEST(TestEnv, TestThreads) {
+ TF_ThreadOptions options;
+ TF_DefaultThreadOptions(&options);
+ SomeThreadData data;
+ TF_Thread* thread =
+ TF_StartThread(&options, "SomeThreadName", &SomeThreadFunc, &data);
+ TF_JoinThread(thread);
+ ::tensorflow::mutex_lock l(data.mu);
+ ASSERT_TRUE(data.did_work);
+}
diff --git a/tensorflow/c/kernels.h b/tensorflow/c/kernels.h
index 1a91aa184f11ac8e45b38a1d106c7b445747a7c1..cefc30bcdf89bdc14a4406299cc29f74153e77ac 100644
--- a/tensorflow/c/kernels.h
+++ b/tensorflow/c/kernels.h
@@ -35,9 +35,9 @@ extern "C" {
// `TF_RegisterKernelBuilder`, which will allow TF to construct user-provided
// kernels when necessary.
-struct TF_KernelBuilder;
-struct TF_OpKernelConstruction;
-struct TF_OpKernelContext;
+typedef struct TF_KernelBuilder TF_KernelBuilder;
+typedef struct TF_OpKernelConstruction TF_OpKernelConstruction;
+typedef struct TF_OpKernelContext TF_OpKernelContext;
// Allocates a new kernel builder and returns a pointer to it.
//
diff --git a/tensorflow/cc/gradients/image_grad.cc b/tensorflow/cc/gradients/image_grad.cc
index 882709e1e2817431a32c453fe0f35f2b2e6c69b0..05c287bdc62cdb8be7208ce3975f280aaa816766 100644
--- a/tensorflow/cc/gradients/image_grad.cc
+++ b/tensorflow/cc/gradients/image_grad.cc
@@ -69,6 +69,23 @@ Status ResizeBicubicGradHelper(const Scope& scope, const Operation& op,
}
REGISTER_GRADIENT_OP("ResizeBicubic", ResizeBicubicGradHelper);
+Status ScaleAndTranslateGradHelper(const Scope& scope, const Operation& op,
+ const std::vector