• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #ifndef TENSORFLOW_COMPILER_XLA_SERVICE_OWNING_DEVICE_MEMORY_H_
17 #define TENSORFLOW_COMPILER_XLA_SERVICE_OWNING_DEVICE_MEMORY_H_
18 
19 #include "tensorflow/compiler/xla/statusor.h"
20 #include "tensorflow/compiler/xla/types.h"
21 #include "tensorflow/core/platform/macros.h"
22 #include "tensorflow/core/platform/stream_executor_no_cuda.h"
23 
24 namespace xla {
25 
26 // Break circular dependency between this file and device_memory_allocator.h.
27 class DeviceMemoryAllocator;
28 
29 // Owning pointer for memory on a device.
30 //
31 // OwningDeviceMemory is an owning pointer like std::unique_ptr, but it can
32 // point to memory that resides on a "device" (e.g. a GPU).  When an
33 // OwningDeviceMemory goes out of scope, it frees the memory it owns.
34 //
35 // We say that an instance of OwningDeviceMemory is "active" if it currently
36 // owns a (possibly empty) slice of memory on the device.  Moving, Forget()'ing,
37 // Free()'ing, and other actions can deactive an active object.
38 //
39 // Note that we can't simply use stream_executor::ScopedDeviceMemory instead of
40 // OwningDeviceMemory, because ScopedDeviceMemory frees its pointer via a
41 // StreamExecutor.  This class needs to free via a xla::DeviceMemoryAllocator.
42 class OwningDeviceMemory {
43  public:
OwningDeviceMemory()44   OwningDeviceMemory() : device_ordinal_(-1), allocator_(nullptr) {}
45 
OwningDeviceMemory(se::DeviceMemoryBase mem,int device_ordinal,DeviceMemoryAllocator * allocator)46   explicit OwningDeviceMemory(se::DeviceMemoryBase mem, int device_ordinal,
47                               DeviceMemoryAllocator* allocator)
48       : mem_(mem), device_ordinal_(device_ordinal), allocator_(allocator) {
49     CHECK(allocator != nullptr) << "allocator cannot be null.";
50   }
51 
OwningDeviceMemory(OwningDeviceMemory && other)52   OwningDeviceMemory(OwningDeviceMemory&& other)
53       : mem_(other.mem_),
54         device_ordinal_(other.device_ordinal_),
55         allocator_(other.allocator_) {
56     other.mem_ = se::DeviceMemoryBase();
57     other.allocator_ = nullptr;
58   }
59 
60   OwningDeviceMemory& operator=(OwningDeviceMemory&& other) {
61     if (allocator_ != nullptr) {
62       Free();
63     }
64     mem_ = other.mem_;
65     device_ordinal_ = other.device_ordinal_;
66     allocator_ = other.allocator_;
67 
68     other.mem_ = se::DeviceMemoryBase();
69     other.allocator_ = nullptr;
70     return *this;
71   }
72 
73   // Deactivates this instance if it's active.  Nop if it's not active.
74   OwningDeviceMemory& operator=(std::nullptr_t) {
75     if (allocator_ != nullptr) {
76       Free();
77     }
78     return *this;
79   }
80 
~OwningDeviceMemory()81   ~OwningDeviceMemory() {
82     if (allocator_ != nullptr) {
83       Free();
84     }
85   }
86 
87   // The returned allocator is nonnull iff this object is active.
allocator()88   DeviceMemoryAllocator* allocator() const { return allocator_; }
89 
device_ordinal()90   int device_ordinal() const { return device_ordinal_; }
91 
92   // Gets the device memory pointer.
opaque()93   const void* opaque() const { return mem_.opaque(); }
opaque()94   void* opaque() { return mem_.opaque(); }
95 
size()96   uint64 size() const { return mem_.size(); }
97 
98   // Determines whether this wraps a null pointer.
99   //
100   // !is_null() is sufficient but not necessary to imply `this` is active.
is_null()101   bool is_null() const { return mem_.is_null(); }
102 
AsDeviceMemoryBase()103   se::DeviceMemoryBase AsDeviceMemoryBase() {
104     return se::DeviceMemoryBase(opaque(), size(), /*is_sub_buffer=*/false);
105   }
106 
107   // Returns the wrapped DeviceMemoryBase without freeing it, and deactivates
108   // this object.  Precondition: `this` is active.
Forget()109   TF_MUST_USE_RESULT se::DeviceMemoryBase Forget() {
110     CHECK(allocator_ != nullptr)
111         << "Can't call Forget() on an inactive (i.e. moved from, Forget()'ten, "
112            "or Free()'ed) instance.";
113     allocator_ = nullptr;
114     se::DeviceMemoryBase mem(mem_);
115     mem_ = se::DeviceMemoryBase();
116     return mem;
117   }
118 
119   // Frees the wrapped DeviceMemoryBase and deactivates this object.
120   // Precondition: `this` is active.
121   void Free();
122 
123  private:
124   se::DeviceMemoryBase mem_;
125   int device_ordinal_;
126   DeviceMemoryAllocator* allocator_;  // Null if this object is inactive.
127 };
128 
129 }  // namespace xla
130 
131 #endif  // TENSORFLOW_COMPILER_XLA_SERVICE_OWNING_DEVICE_MEMORY_H_
132