Export the events_writer functions from C++ to Python with pybind11 instead of swig. This is part of a larger effort to deprecate swig and eventually with modularization break pywrap_tensorflow into smaller components. It will also make exporting C++ ops to Python significantly easier. XLA is using the pybind11 macros already. Please refer to https://github.com/tensorflow/community/blob/master/rfcs/20190208-pybind11.md for more information.
We are slightly changing the behavior of EventsWriter. Rather than returning a bad status when writing to a deleted file which is often ignored by the user, we are removing the FileStillExists check. TensorBoard has already been prepared for this change via: https://github.com/tensorflow/tensorboard/pull/2683 PiperOrigin-RevId: 270945727
This commit is contained in:
		
							parent
							
								
									e9c8a604cf
								
							
						
					
					
						commit
						98f2265343
					
				| @ -131,18 +131,6 @@ Status EventsWriter::Flush() { | |||||||
|   TF_RETURN_WITH_CONTEXT_IF_ERROR(recordio_file_->Sync(), "Failed to sync ", |   TF_RETURN_WITH_CONTEXT_IF_ERROR(recordio_file_->Sync(), "Failed to sync ", | ||||||
|                                   num_outstanding_events_, " events to ", |                                   num_outstanding_events_, " events to ", | ||||||
|                                   filename_); |                                   filename_); | ||||||
| 
 |  | ||||||
|   // The FileStillExists() condition is necessary because
 |  | ||||||
|   // recordio_writer_->Sync() can return OK even if the underlying
 |  | ||||||
|   // file has been deleted.  EventWriter.FileDeletionBeforeWriting
 |  | ||||||
|   // demonstrates this and will fail if the FileHasDisappeared()
 |  | ||||||
|   // condition is removed.
 |  | ||||||
|   // Also, we deliberately attempt to Sync() before checking for a
 |  | ||||||
|   // disappearing file, in case for some file system File::Exists() is
 |  | ||||||
|   // false after File::Open() but before File::Sync().
 |  | ||||||
|   TF_RETURN_WITH_CONTEXT_IF_ERROR(FileStillExists(), "Failed to flush ", |  | ||||||
|                                   num_outstanding_events_, " events to ", |  | ||||||
|                                   filename_); |  | ||||||
|   VLOG(1) << "Wrote " << num_outstanding_events_ << " events to disk."; |   VLOG(1) << "Wrote " << num_outstanding_events_ << " events to disk."; | ||||||
|   num_outstanding_events_ = 0; |   num_outstanding_events_ = 0; | ||||||
|   return Status::OK(); |   return Status::OK(); | ||||||
|  | |||||||
| @ -142,9 +142,7 @@ TEST(EventWriter, FailFlush) { | |||||||
|   WriteFile(&writer); |   WriteFile(&writer); | ||||||
|   TF_EXPECT_OK(env()->FileExists(filename)); |   TF_EXPECT_OK(env()->FileExists(filename)); | ||||||
|   TF_ASSERT_OK(env()->DeleteFile(filename)); |   TF_ASSERT_OK(env()->DeleteFile(filename)); | ||||||
|   EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code()); |   EXPECT_TRUE(writer.Flush().ok()); | ||||||
|   EXPECT_FALSE(writer.Flush().ok()); |  | ||||||
|   EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST(EventWriter, FailClose) { | TEST(EventWriter, FailClose) { | ||||||
| @ -154,9 +152,7 @@ TEST(EventWriter, FailClose) { | |||||||
|   WriteFile(&writer); |   WriteFile(&writer); | ||||||
|   TF_EXPECT_OK(env()->FileExists(filename)); |   TF_EXPECT_OK(env()->FileExists(filename)); | ||||||
|   TF_ASSERT_OK(env()->DeleteFile(filename)); |   TF_ASSERT_OK(env()->DeleteFile(filename)); | ||||||
|   EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code()); |   EXPECT_TRUE(writer.Close().ok()); | ||||||
|   EXPECT_FALSE(writer.Close().ok()); |  | ||||||
|   EXPECT_EQ(errors::Code::NOT_FOUND, env()->FileExists(filename).code()); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST(EventWriter, InitWriteClose) { | TEST(EventWriter, InitWriteClose) { | ||||||
|  | |||||||
| @ -98,6 +98,7 @@ py_library( | |||||||
|         "//third_party/py/tensorflow_core:__subpackages__", |         "//third_party/py/tensorflow_core:__subpackages__", | ||||||
|     ], |     ], | ||||||
|     deps = [ |     deps = [ | ||||||
|  |         ":_pywrap_events_writer", | ||||||
|         ":_pywrap_stat_summarizer", |         ":_pywrap_stat_summarizer", | ||||||
|         ":_pywrap_tfprof", |         ":_pywrap_tfprof", | ||||||
|         ":_pywrap_util_port", |         ":_pywrap_util_port", | ||||||
| @ -463,7 +464,7 @@ tf_python_pybind_extension( | |||||||
|     ], |     ], | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| pybind_extension( | tf_python_pybind_extension( | ||||||
|     name = "_pywrap_util_port", |     name = "_pywrap_util_port", | ||||||
|     srcs = ["util/port_wrapper.cc"], |     srcs = ["util/port_wrapper.cc"], | ||||||
|     hdrs = ["//tensorflow/core:util_port_hdrs"], |     hdrs = ["//tensorflow/core:util_port_hdrs"], | ||||||
| @ -475,6 +476,23 @@ pybind_extension( | |||||||
|     ], |     ], | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | tf_python_pybind_extension( | ||||||
|  |     name = "_pywrap_events_writer", | ||||||
|  |     srcs = ["client/events_writer_wrapper.cc"], | ||||||
|  |     module_name = "_pywrap_events_writer", | ||||||
|  |     deps = [ | ||||||
|  |         ":pybind11_absl", | ||||||
|  |         ":pybind11_proto", | ||||||
|  |         ":pybind11_status", | ||||||
|  |         "//tensorflow/core:framework", | ||||||
|  |         "//tensorflow/core:lib", | ||||||
|  |         "//tensorflow/core:protos_all_cc", | ||||||
|  |         "//third_party/python_runtime:headers", | ||||||
|  |         "@com_google_absl//absl/strings", | ||||||
|  |         "@pybind11", | ||||||
|  |     ], | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| cc_library( | cc_library( | ||||||
|     name = "cpp_python_util", |     name = "cpp_python_util", | ||||||
|     srcs = ["util/util.cc"], |     srcs = ["util/util.cc"], | ||||||
| @ -784,6 +802,7 @@ py_library( | |||||||
|     ], |     ], | ||||||
|     srcs_version = "PY2AND3", |     srcs_version = "PY2AND3", | ||||||
|     deps = [ |     deps = [ | ||||||
|  |         ":_pywrap_events_writer", | ||||||
|         ":_pywrap_stat_summarizer", |         ":_pywrap_stat_summarizer", | ||||||
|         ":_pywrap_tfprof", |         ":_pywrap_tfprof", | ||||||
|         ":_pywrap_util_port", |         ":_pywrap_util_port", | ||||||
| @ -4990,7 +5009,6 @@ tf_py_wrap_cc( | |||||||
|     srcs = ["tensorflow.i"], |     srcs = ["tensorflow.i"], | ||||||
|     swig_includes = [ |     swig_includes = [ | ||||||
|         "client/device_lib.i", |         "client/device_lib.i", | ||||||
|         "client/events_writer.i", |  | ||||||
|         "client/tf_session.i", |         "client/tf_session.i", | ||||||
|         "client/tf_sessionrun_wrapper.i", |         "client/tf_sessionrun_wrapper.i", | ||||||
|         "framework/python_op_gen.i", |         "framework/python_op_gen.i", | ||||||
|  | |||||||
| @ -49,6 +49,7 @@ import numpy as np | |||||||
| from tensorflow.python import pywrap_tensorflow | from tensorflow.python import pywrap_tensorflow | ||||||
| from tensorflow.python import _pywrap_utils | from tensorflow.python import _pywrap_utils | ||||||
| from tensorflow.python import _pywrap_tfprof | from tensorflow.python import _pywrap_tfprof | ||||||
|  | from tensorflow.python import _pywrap_events_writer | ||||||
| from tensorflow.python import _pywrap_util_port | from tensorflow.python import _pywrap_util_port | ||||||
| from tensorflow.python import _pywrap_stat_summarizer | from tensorflow.python import _pywrap_stat_summarizer | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,54 +0,0 @@ | |||||||
| /* 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. |  | ||||||
| ==============================================================================*/ |  | ||||||
| 
 |  | ||||||
| %include "tensorflow/python/lib/core/strings.i" |  | ||||||
| %include "tensorflow/python/platform/base.i" |  | ||||||
| 
 |  | ||||||
| %{ |  | ||||||
| #include "tensorflow/core/util/events_writer.h" |  | ||||||
| #include "tensorflow/core/util/event.pb.h" |  | ||||||
| %} |  | ||||||
| 
 |  | ||||||
| %nodefaultctor EventsWriter; |  | ||||||
| 
 |  | ||||||
| %ignore tensorflow::Status::operator=; |  | ||||||
| %include "tensorflow/core/lib/core/status.h" |  | ||||||
| 
 |  | ||||||
| %ignoreall |  | ||||||
| %unignore tensorflow; |  | ||||||
| %unignore tensorflow::EventsWriter; |  | ||||||
| %unignore tensorflow::EventsWriter::EventsWriter; |  | ||||||
| %unignore tensorflow::EventsWriter::~EventsWriter; |  | ||||||
| %unignore tensorflow::EventsWriter::InitWithSuffix; |  | ||||||
| %unignore tensorflow::EventsWriter::FileName; |  | ||||||
| %rename("_WriteSerializedEvent") tensorflow::EventsWriter::WriteSerializedEvent; |  | ||||||
| %unignore tensorflow::EventsWriter::Flush; |  | ||||||
| %unignore tensorflow::EventsWriter::Close; |  | ||||||
| %include "tensorflow/core/util/events_writer.h" |  | ||||||
| %unignoreall |  | ||||||
| 
 |  | ||||||
| %newobject tensorflow::EventsWriter::EventsWriter; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| %extend tensorflow::EventsWriter { |  | ||||||
| %insert("python") %{ |  | ||||||
|   def WriteEvent(self, event): |  | ||||||
|     from tensorflow.core.util.event_pb2 import Event |  | ||||||
|     if not isinstance(event, Event): |  | ||||||
|       raise TypeError("Expected an event_pb2.Event proto, " |  | ||||||
|                       " but got %s" % type(event)) |  | ||||||
|     return self._WriteSerializedEvent(event.SerializeToString()) |  | ||||||
| %} |  | ||||||
| } |  | ||||||
| @ -22,7 +22,7 @@ import os.path | |||||||
| 
 | 
 | ||||||
| from tensorflow.core.framework import summary_pb2 | from tensorflow.core.framework import summary_pb2 | ||||||
| from tensorflow.core.util import event_pb2 | from tensorflow.core.util import event_pb2 | ||||||
| from tensorflow.python import pywrap_tensorflow | from tensorflow.python import _pywrap_events_writer | ||||||
| from tensorflow.python.framework import errors | from tensorflow.python.framework import errors | ||||||
| from tensorflow.python.framework import test_util | from tensorflow.python.framework import test_util | ||||||
| from tensorflow.python.lib.io import tf_record | from tensorflow.python.lib.io import tf_record | ||||||
| @ -34,7 +34,7 @@ class PywrapeventsWriterTest(test_util.TensorFlowTestCase): | |||||||
| 
 | 
 | ||||||
|   def testWriteEvents(self): |   def testWriteEvents(self): | ||||||
|     file_prefix = os.path.join(self.get_temp_dir(), "events") |     file_prefix = os.path.join(self.get_temp_dir(), "events") | ||||||
|     writer = pywrap_tensorflow.EventsWriter(compat.as_bytes(file_prefix)) |     writer = _pywrap_events_writer.EventsWriter(compat.as_bytes(file_prefix)) | ||||||
|     filename = compat.as_text(writer.FileName()) |     filename = compat.as_text(writer.FileName()) | ||||||
|     event_written = event_pb2.Event( |     event_written = event_pb2.Event( | ||||||
|         wall_time=123.45, |         wall_time=123.45, | ||||||
| @ -74,7 +74,7 @@ class PywrapeventsWriterTest(test_util.TensorFlowTestCase): | |||||||
|         return "Invalid" |         return "Invalid" | ||||||
| 
 | 
 | ||||||
|     with self.assertRaisesRegexp(TypeError, "Invalid"): |     with self.assertRaisesRegexp(TypeError, "Invalid"): | ||||||
|       pywrap_tensorflow.EventsWriter(b"foo").WriteEvent(_Invalid()) |       _pywrap_events_writer.EventsWriter(b"foo").WriteEvent(_Invalid()) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|  | |||||||
							
								
								
									
										49
									
								
								tensorflow/python/client/events_writer_wrapper.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								tensorflow/python/client/events_writer_wrapper.cc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | /* Copyright 2019 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 "absl/strings/string_view.h" | ||||||
|  | #include "include/pybind11/pybind11.h" | ||||||
|  | #include "include/pybind11/pytypes.h" | ||||||
|  | #include "tensorflow/core/util/events_writer.h" | ||||||
|  | #include "tensorflow/python/lib/core/pybind11_absl.h" | ||||||
|  | #include "tensorflow/python/lib/core/pybind11_proto.h" | ||||||
|  | #include "tensorflow/python/lib/core/pybind11_status.h" | ||||||
|  | 
 | ||||||
|  | namespace py = pybind11; | ||||||
|  | 
 | ||||||
|  | PYBIND11_MODULE(_pywrap_events_writer, m) { | ||||||
|  |   py::class_<tensorflow::EventsWriter> events_writer_class(m, "EventsWriter"); | ||||||
|  |   events_writer_class.def(py::init<const std::string&>()) | ||||||
|  |       .def("InitWithSuffix", | ||||||
|  |            [](tensorflow::EventsWriter& self, const std::string& suffix) { | ||||||
|  |              return self.InitWithSuffix(suffix); | ||||||
|  |            }) | ||||||
|  |       .def("FileName", | ||||||
|  |            [](tensorflow::EventsWriter& self) { return self.FileName(); }) | ||||||
|  |       .def("_WriteSerializedEvent", | ||||||
|  |            [](tensorflow::EventsWriter& self, | ||||||
|  |               const absl::string_view event_str) { | ||||||
|  |              self.WriteSerializedEvent(event_str); | ||||||
|  |            }) | ||||||
|  |       .def("Flush", [](tensorflow::EventsWriter& self) { return self.Flush(); }) | ||||||
|  |       .def("Close", [](tensorflow::EventsWriter& self) { return self.Close(); }) | ||||||
|  |       .def("WriteEvent", | ||||||
|  |            [](tensorflow::EventsWriter& self, const py::object obj) { | ||||||
|  |              // Verify the proto type is an event prior to writing.
 | ||||||
|  |              tensorflow::CheckProtoType(obj, "tensorflow.Event"); | ||||||
|  |              self.WriteSerializedEvent( | ||||||
|  |                  obj.attr("SerializeToString")().cast<std::string>()); | ||||||
|  |            }); | ||||||
|  | }; | ||||||
| @ -38,6 +38,7 @@ import datetime | |||||||
| import os | import os | ||||||
| import threading | import threading | ||||||
| 
 | 
 | ||||||
|  | from tensorflow.python import _pywrap_events_writer | ||||||
| from tensorflow.python import pywrap_tensorflow | from tensorflow.python import pywrap_tensorflow | ||||||
| from tensorflow.python.eager import context | from tensorflow.python.eager import context | ||||||
| from tensorflow.python.framework import c_api_util | from tensorflow.python.framework import c_api_util | ||||||
| @ -122,7 +123,7 @@ def maybe_create_event_file(logdir): | |||||||
|     if file_name.endswith(_EVENT_FILE_SUFFIX): |     if file_name.endswith(_EVENT_FILE_SUFFIX): | ||||||
|       return |       return | ||||||
|   # TODO(b/127330388): Use summary_ops_v2.create_file_writer instead. |   # TODO(b/127330388): Use summary_ops_v2.create_file_writer instead. | ||||||
|   event_writer = pywrap_tensorflow.EventsWriter( |   event_writer = _pywrap_events_writer.EventsWriter( | ||||||
|       compat.as_bytes(os.path.join(logdir, 'events'))) |       compat.as_bytes(os.path.join(logdir, 'events'))) | ||||||
|   event_writer.InitWithSuffix(compat.as_bytes(_EVENT_FILE_SUFFIX)) |   event_writer.InitWithSuffix(compat.as_bytes(_EVENT_FILE_SUFFIX)) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -25,7 +25,7 @@ import time | |||||||
| import six | import six | ||||||
| 
 | 
 | ||||||
| from tensorflow.core.util import event_pb2 | from tensorflow.core.util import event_pb2 | ||||||
| from tensorflow.python import pywrap_tensorflow | from tensorflow.python import _pywrap_events_writer | ||||||
| from tensorflow.python.platform import gfile | from tensorflow.python.platform import gfile | ||||||
| from tensorflow.python.util import compat | from tensorflow.python.util import compat | ||||||
| 
 | 
 | ||||||
| @ -66,7 +66,7 @@ class EventFileWriter(object): | |||||||
|     if not gfile.IsDirectory(self._logdir): |     if not gfile.IsDirectory(self._logdir): | ||||||
|       gfile.MakeDirs(self._logdir) |       gfile.MakeDirs(self._logdir) | ||||||
|     self._event_queue = six.moves.queue.Queue(max_queue) |     self._event_queue = six.moves.queue.Queue(max_queue) | ||||||
|     self._ev_writer = pywrap_tensorflow.EventsWriter( |     self._ev_writer = _pywrap_events_writer.EventsWriter( | ||||||
|         compat.as_bytes(os.path.join(self._logdir, "events"))) |         compat.as_bytes(os.path.join(self._logdir, "events"))) | ||||||
|     self._flush_secs = flush_secs |     self._flush_secs = flush_secs | ||||||
|     self._sentinel_event = self._get_sentinel_event() |     self._sentinel_event = self._get_sentinel_event() | ||||||
|  | |||||||
| @ -26,7 +26,6 @@ limitations under the License. | |||||||
| 
 | 
 | ||||||
| %include "tensorflow/python/lib/io/py_record_reader.i" | %include "tensorflow/python/lib/io/py_record_reader.i" | ||||||
| %include "tensorflow/python/lib/io/py_record_writer.i" | %include "tensorflow/python/lib/io/py_record_writer.i" | ||||||
| %include "tensorflow/python/client/events_writer.i" |  | ||||||
| 
 | 
 | ||||||
| %include "tensorflow/python/client/tf_session.i" | %include "tensorflow/python/client/tf_session.i" | ||||||
| %include "tensorflow/python/client/device_lib.i" | %include "tensorflow/python/client/device_lib.i" | ||||||
|  | |||||||
| @ -44,3 +44,11 @@ tensorflow::grappler::graph_analyzer::GraphAnalyzerTool | |||||||
| [bfloat16_lib] # bfloat16 | [bfloat16_lib] # bfloat16 | ||||||
| tensorflow::RegisterNumpyBfloat16 | tensorflow::RegisterNumpyBfloat16 | ||||||
| tensorflow::Bfloat16PyType | tensorflow::Bfloat16PyType | ||||||
|  | 
 | ||||||
|  | [events_writer] # events_writer | ||||||
|  | tensorflow::EventsWriter::Init | ||||||
|  | tensorflow::EventsWriter::InitWithSuffix | ||||||
|  | tensorflow::EventsWriter::WriteSerializedEvent | ||||||
|  | tensorflow::EventsWriter::Flush | ||||||
|  | tensorflow::EventsWriter::Close | ||||||
|  | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user