11e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins/* Copyright 2017 The TensorFlow Authors. All Rights Reserved. 21e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 31e67c90e2caceeff82d09793d1ef5fa0300d219bPeter HawkinsLicensed under the Apache License, Version 2.0 (the "License"); 41e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkinsyou may not use this file except in compliance with the License. 51e67c90e2caceeff82d09793d1ef5fa0300d219bPeter HawkinsYou may obtain a copy of the License at 61e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 71e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins http://www.apache.org/licenses/LICENSE-2.0 81e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 91e67c90e2caceeff82d09793d1ef5fa0300d219bPeter HawkinsUnless required by applicable law or agreed to in writing, software 101e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkinsdistributed under the License is distributed on an "AS IS" BASIS, 111e67c90e2caceeff82d09793d1ef5fa0300d219bPeter HawkinsWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 121e67c90e2caceeff82d09793d1ef5fa0300d219bPeter HawkinsSee the License for the specific language governing permissions and 131e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkinslimitations under the License. 141e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins==============================================================================*/ 151e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 161e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#ifndef TENSORFLOW_COMPILER_XLA_SERVICE_TRANSFER_MANAGER_H_ 171e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#define TENSORFLOW_COMPILER_XLA_SERVICE_TRANSFER_MANAGER_H_ 181e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 191e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include <map> 201e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include <set> 211e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include <vector> 221e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 2302ac85399d4fb35d5055ecf426632b9446a70041A. Unique TensorFlower#include "tensorflow/compiler/xla/literal_util.h" 2422d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan#include "tensorflow/compiler/xla/service/shaped_buffer.h" 251e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include "tensorflow/compiler/xla/statusor.h" 261e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include "tensorflow/compiler/xla/types.h" 271e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include "tensorflow/compiler/xla/xla_data.pb.h" 2899e1b19ceba32b8354dddc2841b81864c9ba96bbJacques Pienaar#include "tensorflow/core/lib/gtl/array_slice.h" 291e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include "tensorflow/core/platform/mutex.h" 301e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include "tensorflow/core/platform/stream_executor_no_cuda.h" 311e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include "tensorflow/core/platform/thread_annotations.h" 321e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#include "tensorflow/core/platform/types.h" 331e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 341e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkinsnamespace xla { 351e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 361e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins// The TransferManager interface lets backends provide platform-specific 371e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins// mechanisms for constructing literals from given device memory handles. 381e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins// This lets each platform customize how literals are transferred to/from the 391e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins// device in terms of padding, leading dimension, etc. 401e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkinsclass TransferManager { 411e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins public: 421e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins virtual ~TransferManager() {} 431e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 441e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // Returns the ID of the platform that this transfer manager acts on. 451e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins virtual perftools::gputools::Platform::Id PlatformId() const = 0; 461e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 470683cdbd8701e4e6a582db1e71d58fcad628e070A. Unique TensorFlower // Returns the shape of the on-device representation for the given shape on 480683cdbd8701e4e6a582db1e71d58fcad628e070A. Unique TensorFlower // the host. This is intended for use with ShapedBuffer where buffers are 490683cdbd8701e4e6a582db1e71d58fcad628e070A. Unique TensorFlower // pre-allocated by the host, e.g. TransferLiteralToDevice, without the user 500683cdbd8701e4e6a582db1e71d58fcad628e070A. Unique TensorFlower // needing to consider device-specific behaviors. 510683cdbd8701e4e6a582db1e71d58fcad628e070A. Unique TensorFlower virtual Shape HostShapeToDeviceShape(const Shape& host_shape) const { 520683cdbd8701e4e6a582db1e71d58fcad628e070A. Unique TensorFlower return host_shape; 530683cdbd8701e4e6a582db1e71d58fcad628e070A. Unique TensorFlower } 540683cdbd8701e4e6a582db1e71d58fcad628e070A. Unique TensorFlower 55fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // Returns a literal containing the data held in the given ShapedBuffer. 56fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // using the provided executor. The optional literal_shape will be the shape 57fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // for the literal. The shape of the ShapedBuffer and 58fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // DeviceShape(literal_shape) must be compatible, but need not have the same 59fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // layout. 6022d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan virtual StatusOr<std::unique_ptr<Literal>> TransferLiteralFromDevice( 6122d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan perftools::gputools::StreamExecutor* executor, 6222d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan const ShapedBuffer& device_buffer) = 0; 6322d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan 6422d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // Transfers the given literal into the previously allocated device memory 65fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // represented by the given ShapedBuffer using the given executor. The shape 66fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // of the ShapedBuffer and DeviceShape(literal.shape()) must be compatible, 67fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // but need not have the same layout 6822d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan virtual Status TransferLiteralToDevice( 6922d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan perftools::gputools::StreamExecutor* executor, const Literal& literal, 7022d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan const ShapedBuffer& device_buffer) = 0; 7122d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan 72fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // Convenience methods for transferring an array to or from the device at a 73fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // known address. This avoids having to construct a ShapedBuffer just to 74fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // transfer an array at a known address. 75fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower Status TransferArrayToDevice( 76fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower perftools::gputools::StreamExecutor* executor, const Literal& literal, 77fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower const perftools::gputools::DeviceMemoryBase& dest); 78fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower StatusOr<std::unique_ptr<Literal>> TransferArrayFromDevice( 79fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower perftools::gputools::StreamExecutor* executor, const Shape& shape, 80fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower const perftools::gputools::DeviceMemoryBase& source); 81fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower 821e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // Transfers the given literal into the Infeed interface of the device, 831e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // using the given executor. 841e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins virtual Status TransferLiteralToInfeed( 851e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins perftools::gputools::StreamExecutor* executor, 861e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins const Literal& literal) = 0; 871e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 88efc8f98d45df835bac2373e19f1da57e3a1ea2d0Jacques Pienaar // Transfers the given literal from the Outfeed interface of the device, 89efc8f98d45df835bac2373e19f1da57e3a1ea2d0Jacques Pienaar // using the given executor. 90efc8f98d45df835bac2373e19f1da57e3a1ea2d0Jacques Pienaar virtual Status TransferLiteralFromOutfeed( 91efc8f98d45df835bac2373e19f1da57e3a1ea2d0Jacques Pienaar perftools::gputools::StreamExecutor* executor, const Shape& literal_shape, 92efc8f98d45df835bac2373e19f1da57e3a1ea2d0Jacques Pienaar Literal* literal) = 0; 93efc8f98d45df835bac2373e19f1da57e3a1ea2d0Jacques Pienaar 9499e1b19ceba32b8354dddc2841b81864c9ba96bbJacques Pienaar // Resets the devices associated with this transfer manager. 9599e1b19ceba32b8354dddc2841b81864c9ba96bbJacques Pienaar virtual Status ResetDevices( 9699e1b19ceba32b8354dddc2841b81864c9ba96bbJacques Pienaar tensorflow::gtl::ArraySlice<perftools::gputools::StreamExecutor*> 9799e1b19ceba32b8354dddc2841b81864c9ba96bbJacques Pienaar executor) = 0; 981e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 9922d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // Given an allocated ShapedBuffer, constructs the tuple index table(s) in 10022d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // each buffer of the given ShapedBuffer corresponding to tuple shapes. If the 10122d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // ShapedBuffer is array-shaped this method does nothing. 10222d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan Status WriteTupleIndexTables(perftools::gputools::StreamExecutor* executor, 10322d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan const ShapedBuffer& device_buffer); 10406deeea373c93ea36547648481c5daf4dc56126fMark Heffernan 1051e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // Determines the byte size requirement for the given shape on the underlying 1061e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // architecture. This will be used to allocate an appropriately sized memory 1071e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // region for a host-to-device transfer. 1083f7d27ae53095a140994b3c0c00b12f7a6f5fd06A. Unique TensorFlower virtual int64 GetByteSizeRequirement(const Shape& shape) const = 0; 1091e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 110fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // Allocate a ShapedBuffer which can hold data with the given on-host 111fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // shape. The on-device shape may be different as indicated by 112fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // HostShapeToDeviceShape. 113fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower StatusOr<std::unique_ptr<ShapedBuffer>> AllocateShapedBuffer( 114fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower const Shape& on_host_shape, DeviceMemoryAllocator* allocator, 115fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower int device_ordinal); 116fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower StatusOr<std::unique_ptr<ScopedShapedBuffer>> AllocateScopedShapedBuffer( 117fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower const Shape& on_host_shape, DeviceMemoryAllocator* allocator, 118fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower int device_ordinal); 1191e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 1201e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins ///// 1211e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // The TransferManager class also serves as a point to register objects for 1221e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // the various platforms. 1231e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 1241e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // Registers the TransferManager singleton for the platform kind. This is 1251e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // assumed to be a singleton, so no ownership is transferred. 1261e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // 1271e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // Precondition: a platform kind must not be registered more than once. 128fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower typedef std::unique_ptr<TransferManager> (*TransferManagerCreationFunction)(); 1291e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins static void RegisterTransferManager( 1301e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins perftools::gputools::Platform::Id platform_id, 1311e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins TransferManagerCreationFunction transfer_manager); 1321e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 1331e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // Returns the transfer manager singleton pointer if it is available for the 1341e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // given platform, or an error status if it is not. 1351e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins static StatusOr<TransferManager*> GetForPlatform( 1361e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins const perftools::gputools::Platform* platform); 1371e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 13822d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan protected: 139fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // Transfer a memory block of the given size from 'source' buffer to the 140fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // Infeed interface of the device using the given executor. 141fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // 142fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // size is the size to transfer from source in bytes. 143fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // 144fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // source is the source data that must be in the target-dependent layout that 145fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // the Infeed HLO used in the computation expects. 146fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower virtual Status TransferBufferToInfeed( 147fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower perftools::gputools::StreamExecutor* executor, int64 size, 148fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower const void* source) = 0; 149fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower 15022d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // Transfer a memory block of the given size from the device source into the 15122d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // 'destination' buffer. 15222d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // 15322d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // size is the size to transfer to destination in bytes. 15422d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan virtual Status TransferBufferFromDevice( 15522d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan perftools::gputools::StreamExecutor* executor, 15622d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan const perftools::gputools::DeviceMemoryBase& source, int64 size, 15722d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan void* destination); 15822d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan 15922d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // Transfer a memory block of the given size from 'source' buffer to the given 16022d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // destination of the device. 16122d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // 16222d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // size is the size to transfer from source in bytes. 16322d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan virtual Status TransferBufferToDevice( 16422d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan perftools::gputools::StreamExecutor* executor, int64 size, 16522d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan const void* source, perftools::gputools::DeviceMemoryBase* destination); 16622d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan 16722d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan // Writes the given device-memory pointers in 'elements' to the given region 168fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // to construct a tuple index table in the platform-specific tuple 169fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower // representation. 170fc2526a8c1cf0bc2a93c8cc819ff7209eb4628c9A. Unique TensorFlower virtual Status WriteSingleTupleIndexTable( 17122d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan perftools::gputools::StreamExecutor* executor, 17222d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan tensorflow::gtl::ArraySlice<perftools::gputools::DeviceMemoryBase> 17322d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan elements, 17422d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan const Shape& shape, perftools::gputools::DeviceMemoryBase* region) = 0; 17522d948d2739ecaadfb4091302f2050ba9cf0d0c1Mark Heffernan 1761e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins private: 177b0bcf675a4b5d6217f3b58fd27b344f20e7bf25dSanjoy Das // The mutex that guards the platform-to-transfer manager map. 178b0bcf675a4b5d6217f3b58fd27b344f20e7bf25dSanjoy Das static tensorflow::mutex platform_transfer_manager_mutex_; 1791e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 1801e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // State kept for each kind of TransferManager. Registration functions 1811e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // set up creation_function, and then we use that to lazily create 1821e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // "manager" the first time GetForPlatform is invoked for a particular id. 1831e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins struct State { 1848cb5e9867482a8e05f756fad35634e1674fe7f16A. Unique TensorFlower std::unique_ptr<TransferManager> manager; 1851e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins TransferManagerCreationFunction creation_function = nullptr; 1861e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins }; 1871e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 1881e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins // Map from platform kind to transfer manager singleton. 1891e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins static std::map<perftools::gputools::Platform::Id, State>* 1901e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins GetPlatformTransferManagers(); 1911e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins}; 1921e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 1931e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins} // namespace xla 1941e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins 1951e67c90e2caceeff82d09793d1ef5fa0300d219bPeter Hawkins#endif // TENSORFLOW_COMPILER_XLA_SERVICE_TRANSFER_MANAGER_H_ 196