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