From 2d0d126749d6d0cf82fb86691362c923a1bfbfe4 Mon Sep 17 00:00:00 2001 From: Vijay Vasudevan <vrv@google.com> Date: Mon, 8 Aug 2016 14:06:20 -0800 Subject: [PATCH] Change DeviceFactory functions that create devices to propagate Statuses, so that failures to initialize devices don't crash the program. Changes swig for device_lib to be a lot simpler, thanks to mrry@ and keveman@'s help. Change allocation of eigen scratch memory to go through the allocator. Re-enable test for local devices now that python3 issue is fixed. Change: 129678132 --- RELEASE.md | 6 ++ .../core/common_runtime/constant_folding.cc | 6 +- .../core/common_runtime/device_factory.cc | 20 +++-- .../core/common_runtime/device_factory.h | 14 +-- .../core/common_runtime/direct_session.cc | 9 +- .../core/common_runtime/gpu/gpu_device.cc | 88 ++++++++++++------- .../core/common_runtime/gpu/gpu_device.h | 24 ++--- .../common_runtime/gpu/gpu_device_factory.cc | 18 ++-- .../threadpool_device_factory.cc | 6 +- .../rpc/grpc_server_lib.cc | 3 +- tensorflow/python/client/device_lib.i | 86 +++++++++--------- tensorflow/python/client/device_lib.py | 3 +- tensorflow/python/client/device_lib_test.py | 3 +- tensorflow/python/lib/core/strings.i | 10 +-- tensorflow/python/lib/io/file_io.py | 6 +- 15 files changed, 175 insertions(+), 127 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 4c9c33bf0dc..ba991fabb66 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,3 +1,9 @@ +# Changes since last release + +## Breaking Changes to the API + +* DeviceFactory's AddDevices and CreateDevices functions now return + a Status instead of void. # Release 0.10.0 diff --git a/tensorflow/core/common_runtime/constant_folding.cc b/tensorflow/core/common_runtime/constant_folding.cc index 2689dcc276d..3d31ca8ce78 100644 --- a/tensorflow/core/common_runtime/constant_folding.cc +++ b/tensorflow/core/common_runtime/constant_folding.cc @@ -173,9 +173,9 @@ Device* GetCPUDevice() { mutex_lock l(mu); if (!device) { std::vector<Device*> devices; - DeviceFactory::GetFactory(DEVICE_CPU) - ->CreateDevices(SessionOptions{}, "", &devices); - if (devices.size() > 0) { + Status s = DeviceFactory::GetFactory(DEVICE_CPU) + ->CreateDevices(SessionOptions{}, "", &devices); + if (s.ok() && devices.size() > 0) { device = devices[0]; } } diff --git a/tensorflow/core/common_runtime/device_factory.cc b/tensorflow/core/common_runtime/device_factory.cc index 7d0a2380cbd..8104f446366 100644 --- a/tensorflow/core/common_runtime/device_factory.cc +++ b/tensorflow/core/common_runtime/device_factory.cc @@ -20,6 +20,7 @@ limitations under the License. #include <unordered_map> #include <vector> +#include "tensorflow/core/lib/core/errors.h" #include "tensorflow/core/lib/strings/strcat.h" #include "tensorflow/core/platform/logging.h" #include "tensorflow/core/platform/mutex.h" @@ -74,25 +75,26 @@ DeviceFactory* DeviceFactory::GetFactory(const string& device_type) { return it->second.factory.get(); } -void DeviceFactory::AddDevices(const SessionOptions& options, - const string& name_prefix, - std::vector<Device*>* devices) { +Status DeviceFactory::AddDevices(const SessionOptions& options, + const string& name_prefix, + std::vector<Device*>* devices) { // CPU first. auto cpu_factory = GetFactory("CPU"); if (!cpu_factory) { - LOG(FATAL) - << "CPU Factory not registered. Did you link in threadpool_device?"; + return errors::NotFound( + "CPU Factory not registered. Did you link in threadpool_device?"); } size_t init_size = devices->size(); cpu_factory->CreateDevices(options, name_prefix, devices); if (devices->size() == init_size) { - LOG(FATAL) << "No CPU devices are available in this process"; + return errors::NotFound("No CPU devices are available in this process"); } // Then GPU. auto gpu_factory = GetFactory("GPU"); if (gpu_factory) { - gpu_factory->CreateDevices(options, name_prefix, devices); + TF_RETURN_IF_ERROR( + gpu_factory->CreateDevices(options, name_prefix, devices)); } // Then the rest. @@ -100,9 +102,11 @@ void DeviceFactory::AddDevices(const SessionOptions& options, for (auto& p : device_factories()) { auto factory = p.second.factory.get(); if (factory != cpu_factory && factory != gpu_factory) { - factory->CreateDevices(options, name_prefix, devices); + TF_RETURN_IF_ERROR(factory->CreateDevices(options, name_prefix, devices)); } } + + return Status::OK(); } Device* DeviceFactory::NewDevice(const string& type, diff --git a/tensorflow/core/common_runtime/device_factory.h b/tensorflow/core/common_runtime/device_factory.h index bb1f93623ff..3852dd2223f 100644 --- a/tensorflow/core/common_runtime/device_factory.h +++ b/tensorflow/core/common_runtime/device_factory.h @@ -18,6 +18,8 @@ limitations under the License. #include <string> #include <vector> + +#include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/platform/types.h" namespace tensorflow { @@ -36,9 +38,9 @@ class DeviceFactory { // any device type specific properties/counts listed in "options". // // CPU devices are added first. - static void AddDevices(const SessionOptions& options, - const string& name_prefix, - std::vector<Device*>* devices); + static Status AddDevices(const SessionOptions& options, + const string& name_prefix, + std::vector<Device*>* devices); // Helper for tests. Create a single device of type "type". The // returned device is always numbered zero, so if creating multiple @@ -47,9 +49,9 @@ class DeviceFactory { const string& name_prefix); // Most clients should call AddDevices() instead. - virtual void CreateDevices(const SessionOptions& options, - const string& name_prefix, - std::vector<Device*>* devices) = 0; + virtual Status CreateDevices(const SessionOptions& options, + const string& name_prefix, + std::vector<Device*>* devices) = 0; }; namespace dfactory { diff --git a/tensorflow/core/common_runtime/direct_session.cc b/tensorflow/core/common_runtime/direct_session.cc index 9e20aee879a..55e83155b92 100644 --- a/tensorflow/core/common_runtime/direct_session.cc +++ b/tensorflow/core/common_runtime/direct_session.cc @@ -1045,8 +1045,13 @@ class DirectSessionFactory : public SessionFactory { EnableCPUAllocatorFullStats(true); } std::vector<Device*> devices; - DeviceFactory::AddDevices(options, "/job:localhost/replica:0/task:0", - &devices); + Status s = DeviceFactory::AddDevices( + options, "/job:localhost/replica:0/task:0", &devices); + if (!s.ok()) { + LOG(ERROR) << s; + return nullptr; + } + return new DirectSession(options, new DeviceMgr(devices)); } }; diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.cc b/tensorflow/core/common_runtime/gpu/gpu_device.cc index c9163d6e081..65615891ef7 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device.cc @@ -229,22 +229,38 @@ BaseGPUDevice::BaseGPUDevice(const SessionOptions& options, const string& name, gpu_allocator_(gpu_allocator), cpu_allocator_(cpu_allocator), gpu_id_(gpu_id), - sync_every_op_(sync_every_op) { + sync_every_op_(sync_every_op), + max_streams_(max_streams) { ProcessState::singleton()->EnableGPUDevice(); +} - executor_ = GPUMachineManager()->ExecutorForDevice(gpu_id_).ValueOrDie(); - if (!executor_) { - LOG(ERROR) << "Failed to get StreamExecutor for device " << gpu_id_; - return; +BaseGPUDevice::~BaseGPUDevice() { + delete gpu_device_info_; + for (auto ctx : device_contexts_) ctx->Unref(); + for (auto& stream_group : streams_) { + delete stream_group.compute; + delete stream_group.host_to_device; + delete stream_group.device_to_host; + delete stream_group.device_to_device; } +} + +Status BaseGPUDevice::Init(const SessionOptions& options) { + auto executor_status = GPUMachineManager()->ExecutorForDevice(gpu_id_); + if (!executor_status.status().ok()) { + return errors::Internal("Failed to get StreamExecutor for device ", + gpu_id_); + } + + executor_ = executor_status.ValueOrDie(); em_.reset(new EventMgr(executor_, options.config.gpu_options())); - if (max_streams < 1) { - LOG(FATAL) << "Invalid value for max_streams."; + if (max_streams_ < 1) { + return errors::InvalidArgument("Invalid value for max_streams."); } // Create the specified number of GPU streams - for (int i = 0; i < max_streams; i++) { + for (int i = 0; i < max_streams_; i++) { auto stream = new gpu::Stream(executor_); stream->Init(); VLOG(2) << "Created stream[" << i << "] = " << stream; @@ -267,14 +283,24 @@ BaseGPUDevice::BaseGPUDevice(const SessionOptions& options, const string& name, streams_.push_back({stream, host_to_device_stream, device_to_host_stream, device_to_device_stream}); - perftools::gputools::DeviceMemory<char> mem = - executor_->AllocateArray<char>(Eigen::kCudaScratchSize + - sizeof(unsigned int)); - scratch_.push_back(static_cast<char*>(mem.opaque())); + size_t scratch_buffer_size = Eigen::kCudaScratchSize + sizeof(unsigned int); + void* scratch_buffer = gpu_allocator_->AllocateRaw( + Allocator::kAllocatorAlignment, scratch_buffer_size); + if (scratch_buffer == nullptr) { + return errors::FailedPrecondition( + "Failed to allocate scratch buffer for device ", gpu_id_); + } + scratch_.push_back(static_cast<char*>(scratch_buffer)); + + perftools::gputools::DeviceMemory<char> mem( + perftools::gputools::DeviceMemoryBase(scratch_buffer, + scratch_buffer_size)); + bool ok = executor_->SynchronousMemZero( &mem, Eigen::kCudaScratchSize + sizeof(unsigned int)); if (!ok) { - LOG(FATAL) << "Failed to initialize device " << gpu_id; + return errors::FailedPrecondition( + "Failed to memcopy into scratch buffer for device ", gpu_id_); } device_contexts_.push_back( @@ -286,17 +312,8 @@ BaseGPUDevice::BaseGPUDevice(const SessionOptions& options, const string& name, gpu_device_info_->default_context = device_contexts_[0]; gpu_device_info_->event_mgr = em_.get(); set_tensorflow_gpu_device_info(gpu_device_info_); -} -BaseGPUDevice::~BaseGPUDevice() { - delete gpu_device_info_; - for (auto ctx : device_contexts_) ctx->Unref(); - for (auto& stream_group : streams_) { - delete stream_group.compute; - delete stream_group.host_to_device; - delete stream_group.device_to_host; - delete stream_group.device_to_device; - } + return Status::OK(); } bool BaseGPUDevice::RequiresRecordingAccessedTensors() const { @@ -571,9 +588,9 @@ void BaseGPUDevice::ReinitializeGpuDevice(OpKernelContext* context, } } -void BaseGPUDeviceFactory::CreateDevices(const SessionOptions& options, - const string& name_prefix, - std::vector<Device*>* devices) { +Status BaseGPUDeviceFactory::CreateDevices(const SessionOptions& options, + const string& name_prefix, + std::vector<Device*>* devices) { int n = INT_MAX; auto iter = options.config.device_count().find("GPU"); if (iter != options.config.device_count().end()) { @@ -585,9 +602,15 @@ void BaseGPUDeviceFactory::CreateDevices(const SessionOptions& options, n = valid_gpu_ids.size(); } for (int i = 0; i < n; i++) { - devices->push_back(CreateGPUDevice( - options, strings::StrCat(name_prefix, "/gpu:", i), valid_gpu_ids[i])); + BaseGPUDevice* gpu_device; + TF_RETURN_IF_ERROR(CreateGPUDevice(options, + strings::StrCat(name_prefix, "/gpu:", i), + valid_gpu_ids[i], &gpu_device)); + TF_RETURN_IF_ERROR(gpu_device->Init(options)); + devices->push_back(gpu_device); } + + return Status::OK(); } namespace { @@ -615,8 +638,9 @@ static string GetShortDeviceDescription(int device_id, ", pci bus id: ", desc.pci_bus_id()); } -LocalDevice* BaseGPUDeviceFactory::CreateGPUDevice( - const SessionOptions& options, const string& name, int gpu_id) { +Status BaseGPUDeviceFactory::CreateGPUDevice(const SessionOptions& options, + const string& name, int gpu_id, + BaseGPUDevice** out_device) { CHECK_GE(gpu_id, 0); // Look up the device, to see its attributes. @@ -675,12 +699,14 @@ LocalDevice* BaseGPUDeviceFactory::CreateGPUDevice( << " numa: " << numa_node << " pci: " << desc.pci_bus_id(); ProcessState* process_state = ProcessState::singleton(); - return CreateGPUDevice( + *out_device = CreateGPUDevice( options, name, allocated_bytes, bus_adjacency, gpu_id, GetShortDeviceDescription(gpu_id, desc), process_state->GetGPUAllocator(options.config.gpu_options(), gpu_id, allocated_memory), process_state->GetCPUAllocator(numa_node)); + + return Status::OK(); } static int GetDefaultMinGPUMultiprocessorCount(gpu::Platform* gpu_manager) { diff --git a/tensorflow/core/common_runtime/gpu/gpu_device.h b/tensorflow/core/common_runtime/gpu/gpu_device.h index 4ac9c4021dd..03090aa5374 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device.h +++ b/tensorflow/core/common_runtime/gpu/gpu_device.h @@ -48,6 +48,9 @@ class BaseGPUDevice : public LocalDevice { ~BaseGPUDevice() override; + // Initialize the device and return the status of initialization. + Status Init(const SessionOptions& options); + // GPU devices require the Op Compute method to save a reference to // any temporary tensors that are allocated until the Op execution // completes. @@ -97,6 +100,7 @@ class BaseGPUDevice : public LocalDevice { mutex trace_mu_; int gpu_id_ = -1; const bool sync_every_op_ = false; + const int32 max_streams_; std::unique_ptr<EventMgr> em_; void ReinitializeDevice(OpKernelContext* context, PerOpGpuDevice* device, @@ -105,19 +109,19 @@ class BaseGPUDevice : public LocalDevice { class BaseGPUDeviceFactory : public DeviceFactory { public: - void CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector<Device*>* devices) override; + Status CreateDevices(const SessionOptions& options, const string& name_prefix, + std::vector<Device*>* devices) override; private: - LocalDevice* CreateGPUDevice(const SessionOptions& options, - const string& name, int gpu_id); + Status CreateGPUDevice(const SessionOptions& options, const string& name, + int gpu_id, BaseGPUDevice** out_device); - virtual LocalDevice* CreateGPUDevice(const SessionOptions& options, - const string& name, Bytes memory_limit, - BusAdjacency bus_adjacency, int gpu_id, - const string& physical_device_desc, - Allocator* gpu_allocator, - Allocator* cpu_allocator) = 0; + virtual BaseGPUDevice* CreateGPUDevice(const SessionOptions& options, + const string& name, Bytes memory_limit, + BusAdjacency bus_adjacency, int gpu_id, + const string& physical_device_desc, + Allocator* gpu_allocator, + Allocator* cpu_allocator) = 0; void GetValidDeviceIds(std::vector<int>* ids); }; diff --git a/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc b/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc index 96a4c06d2b2..a7e3773ac89 100644 --- a/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc +++ b/tensorflow/core/common_runtime/gpu/gpu_device_factory.cc @@ -49,12 +49,12 @@ class GPUDevice : public BaseGPUDevice { class GPUDeviceFactory : public BaseGPUDeviceFactory { private: - LocalDevice* CreateGPUDevice(const SessionOptions& options, - const string& name, Bytes memory_limit, - BusAdjacency bus_adjacency, int gpu_id, - const string& physical_device_desc, - Allocator* gpu_allocator, - Allocator* cpu_allocator) override { + BaseGPUDevice* CreateGPUDevice(const SessionOptions& options, + const string& name, Bytes memory_limit, + BusAdjacency bus_adjacency, int gpu_id, + const string& physical_device_desc, + Allocator* gpu_allocator, + Allocator* cpu_allocator) override { return new GPUDevice(options, name, memory_limit, bus_adjacency, gpu_id, physical_device_desc, gpu_allocator, cpu_allocator); } @@ -89,8 +89,8 @@ class GPUCompatibleCPUDevice : public ThreadPoolDevice { // The associated factory. class GPUCompatibleCPUDeviceFactory : public DeviceFactory { public: - void CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector<Device*>* devices) override { + Status CreateDevices(const SessionOptions& options, const string& name_prefix, + std::vector<Device*>* devices) override { int n = 1; auto iter = options.config.device_count().find("CPU"); if (iter != options.config.device_count().end()) { @@ -101,6 +101,8 @@ class GPUCompatibleCPUDeviceFactory : public DeviceFactory { devices->push_back(new GPUCompatibleCPUDevice( options, name, Bytes(256 << 20), BUS_ANY, cpu_allocator())); } + + return Status::OK(); } }; REGISTER_LOCAL_DEVICE_FACTORY("CPU", GPUCompatibleCPUDeviceFactory, 50); diff --git a/tensorflow/core/common_runtime/threadpool_device_factory.cc b/tensorflow/core/common_runtime/threadpool_device_factory.cc index 5ae9ee0e360..93772a750ef 100644 --- a/tensorflow/core/common_runtime/threadpool_device_factory.cc +++ b/tensorflow/core/common_runtime/threadpool_device_factory.cc @@ -26,8 +26,8 @@ namespace tensorflow { // TODO(zhifengc/tucker): Figure out the bytes of available RAM. class ThreadPoolDeviceFactory : public DeviceFactory { public: - void CreateDevices(const SessionOptions& options, const string& name_prefix, - std::vector<Device*>* devices) override { + Status CreateDevices(const SessionOptions& options, const string& name_prefix, + std::vector<Device*>* devices) override { // TODO(zhifengc/tucker): Figure out the number of available CPUs // and/or NUMA configuration. int n = 1; @@ -40,6 +40,8 @@ class ThreadPoolDeviceFactory : public DeviceFactory { devices->push_back(new ThreadPoolDevice(options, name, Bytes(256 << 20), BUS_ANY, cpu_allocator())); } + + return Status::OK(); } }; REGISTER_LOCAL_DEVICE_FACTORY("CPU", ThreadPoolDeviceFactory); diff --git a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc index ea8de56e324..905e4619b38 100644 --- a/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc +++ b/tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc @@ -86,7 +86,8 @@ Status GrpcServer::Init() { string name_prefix = strings::StrCat("/job:", server_def_.job_name(), "/replica:0", "/task:", server_def_.task_index()); - DeviceFactory::AddDevices(sess_opts, name_prefix, &master_env_.local_devices); + TF_RETURN_IF_ERROR(DeviceFactory::AddDevices(sess_opts, name_prefix, + &master_env_.local_devices)); worker_env_.device_mgr = new DeviceMgr(master_env_.local_devices); string unused; if (!DeviceNameUtils::SplitDeviceName(master_env_.local_devices[0]->name(), diff --git a/tensorflow/python/client/device_lib.i b/tensorflow/python/client/device_lib.i index 502f81040ea..7b280e2beb1 100644 --- a/tensorflow/python/client/device_lib.i +++ b/tensorflow/python/client/device_lib.i @@ -19,69 +19,63 @@ limitations under the License. #include "tensorflow/core/common_runtime/device.h" #include "tensorflow/core/common_runtime/device_factory.h" #include "tensorflow/core/framework/device_attributes.pb.h" +#include "tensorflow/core/lib/core/status.h" #include "tensorflow/core/public/session_options.h" -%} -%typemap(in, numinputs=0) const tensorflow::SessionOptions& options ( - tensorflow::SessionOptions temp) { - $1 = &temp; -} +namespace tensorflow { +namespace swig { -%typemap(in, numinputs=0) std::vector<tensorflow::Device*>* devices ( - std::vector<tensorflow::Device*> temp) { - $1 = &temp; -} - -// Handle string input into AddDevices -%typemap(in, numinputs=0) const string& name_prefix ( - string temp) { - // Always pass an empty name_prefix. - $1 = &temp; -} - -%typemap(argout) std::vector<tensorflow::Device*>* devices { - std::vector< std::unique_ptr<tensorflow::Device> > safe_devices; - for (auto* device : *$1) safe_devices.emplace_back(device); - - auto temp_string_list = tensorflow::make_safe(PyList_New(0)); - if (!temp_string_list) { - SWIG_fail; +static std::vector<string> ListDevices(TF_Status* out_status) { + std::vector<string> output; + SessionOptions options; + std::vector<Device*> devices; + Status status = DeviceFactory::AddDevices( + options, "" /* name_prefix */, &devices); + if (!status.ok()) { + Set_TF_Status_from_Status(out_status, status); } - for (const auto& device : safe_devices) { - const tensorflow::DeviceAttributes& attr = device->attributes(); + for (const Device* device : devices) { + const DeviceAttributes& attr = device->attributes(); string attr_serialized; if (!attr.SerializeToString(&attr_serialized)) { - PyErr_SetString(PyExc_RuntimeError, - "Unable to serialize DeviceAttributes"); - SWIG_fail; - } - - tensorflow::Safe_PyObjectPtr safe_attr_string = tensorflow::make_safe( - %#if PY_MAJOR_VERSION < 3 - PyString_FromStringAndSize( - %#else - PyBytes_FromStringAndSize( - %#endif - reinterpret_cast<const char*>( - attr_serialized.data()), attr_serialized.size())); - - if (PyList_Append(temp_string_list.get(), safe_attr_string.get()) == -1) { - SWIG_fail; + Set_TF_Status_from_Status( + out_status, + errors::Internal("Could not serialize device string")); + output.clear(); + return output; } + output.push_back(attr_serialized); } - $result = temp_string_list.release(); + return output; } +} // namespace swig +} // namespace tensorflow + +%} %ignoreall %unignore tensorflow; -%unignore tensorflow::DeviceFactory; -%unignore tensorflow::DeviceFactory::AddDevices; +%unignore tensorflow::swig; +%unignore tensorflow::swig::ListDevices; -%include "tensorflow/core/common_runtime/device_factory.h" +// Wrap this function +namespace tensorflow { +namespace swig { +std::vector<string> ListDevices(TF_Status* out_status); +} // namespace swig +} // namespace tensorflow + +%insert("python") %{ +def list_devices(): + from tensorflow.python.framework import errors + + with errors.raise_exception_on_not_ok_status() as status: + return ListDevices(status) +%} %unignoreall diff --git a/tensorflow/python/client/device_lib.py b/tensorflow/python/client/device_lib.py index ea251288f32..f67f3264fe4 100644 --- a/tensorflow/python/client/device_lib.py +++ b/tensorflow/python/client/device_lib.py @@ -34,4 +34,5 @@ def list_local_devices(): m = device_attributes_pb2.DeviceAttributes() m.ParseFromString(pb_str) return m - return [_convert(s) for s in pywrap_tensorflow.DeviceFactory_AddDevices()] + + return [_convert(s) for s in pywrap_tensorflow.list_devices()] diff --git a/tensorflow/python/client/device_lib_test.py b/tensorflow/python/client/device_lib_test.py index e1fed28d0fd..21c23266fc8 100644 --- a/tensorflow/python/client/device_lib_test.py +++ b/tensorflow/python/client/device_lib_test.py @@ -27,8 +27,7 @@ from tensorflow.python.platform import googletest class DeviceLibTest(test_util.TensorFlowTestCase): - # TODO(ebrevdo): fix python3 compatibility: b/27727661 - def _testListLocalDevices(self): + def testListLocalDevices(self): devices = device_lib.list_local_devices() self.assertGreater(len(devices), 0) self.assertEqual(devices[0].device_type, "CPU") diff --git a/tensorflow/python/lib/core/strings.i b/tensorflow/python/lib/core/strings.i index 62741d96702..d2b05588826 100644 --- a/tensorflow/python/lib/core/strings.i +++ b/tensorflow/python/lib/core/strings.i @@ -80,7 +80,7 @@ bool _BytesToStringPiece(PyObject* obj, tensorflow::StringPiece* result) { } } -// Converts a C++ string vector to a Python string list. +// Converts a C++ string vector to a a list of Python bytes objects. %typemap(out) std::vector<string> { const int size = $1.size(); auto temp_string_list = tensorflow::make_safe(PyList_New(size)); @@ -90,11 +90,9 @@ bool _BytesToStringPiece(PyObject* obj, tensorflow::StringPiece* result) { tensorflow::Safe_PyObjectVector converted; converted.reserve(size); for (const string& op : $1) { -%#if PY_MAJOR_VERSION >= 3 - PyObject* py_str = PyUnicode_FromStringAndSize(op.data(), op.size()); -%#else - PyObject* py_str = PyString_FromStringAndSize(op.data(), op.size()); -%#endif + // Always treat strings as bytes, consistent with the typemap + // for string. + PyObject* py_str = PyBytes_FromStringAndSize(op.data(), op.size()); if (!py_str) { SWIG_fail; } diff --git a/tensorflow/python/lib/io/file_io.py b/tensorflow/python/lib/io/file_io.py index f0fec9fef91..bca92aeaa93 100644 --- a/tensorflow/python/lib/io/file_io.py +++ b/tensorflow/python/lib/io/file_io.py @@ -99,7 +99,11 @@ def get_matching_files(filename): errors.OpError: If there are filesystem / directory listing errors. """ with errors.raise_exception_on_not_ok_status() as status: - return pywrap_tensorflow.GetMatchingFiles(compat.as_bytes(filename), status) + # Convert each element to string, since the return values of the + # vector of string should be interpreted as strings, not bytes. + return [compat.as_str(matching_filename) + for matching_filename in pywrap_tensorflow.GetMatchingFiles( + compat.as_bytes(filename), status)] def create_dir(dirname):