Home | History | Annotate | Download | only in stream_executor
      1 /* Copyright 2015 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 // The temporary-memory-manager is a helper class for a Stream to keep track of
     17 // temporary allocations. These allocations defer their deallocation to the next
     18 // Stream::BlockHostUntilDone call for efficiency purposes (as deallocation
     19 // itself generally forces synchronization to occur).
     20 
     21 #ifndef TENSORFLOW_STREAM_EXECUTOR_TEMPORARY_MEMORY_MANAGER_H_
     22 #define TENSORFLOW_STREAM_EXECUTOR_TEMPORARY_MEMORY_MANAGER_H_
     23 
     24 #include <map>
     25 #include <memory>
     26 
     27 #include "tensorflow/stream_executor/device_memory.h"
     28 #include "tensorflow/stream_executor/lib/status.h"
     29 #include "tensorflow/stream_executor/lib/statusor.h"
     30 #include "tensorflow/stream_executor/platform/mutex.h"
     31 #include "tensorflow/stream_executor/platform/thread_annotations.h"
     32 #include "tensorflow/stream_executor/temporary_device_memory.h"
     33 
     34 namespace stream_executor {
     35 namespace internal {
     36 
     37 // Record used inside the TemporaryMemoryManager as metadata for a given device
     38 // memory region.
     39 struct TemporaryMemoryRecord {
     40   // What "generation" this record was allocated in.
     41   //
     42   // Currently the generation counter is bumped for every allocation, but this
     43   // could be made coarser if necessary.
     44   uint64 allocation_generation;
     45 
     46   // Notes whether the temporary memory has been marked as finalized, such that
     47   // we can release the DeviceMemory associated with this record at
     48   // synchronization time.
     49   bool finalized;
     50 };
     51 
     52 // Manages temporary memories associated with a stream -- keeps records of
     53 // outstanding temporaries and their state, and can deallocate them
     54 // appropriately at points in the Stream lifecycle (e.g. BlockHostUntilDone,
     55 // destruction).
     56 class TemporaryMemoryManager {
     57  public:
     58   explicit TemporaryMemoryManager(Stream* stream) : stream_(stream) {}
     59 
     60   // Allocates a temporary array that is then managed by this object.
     61   template <typename T>
     62   port::StatusOr<std::unique_ptr<TemporaryDeviceMemory<T>>> AllocateArray(
     63       uint64 element_count);
     64 
     65   // Forces deallocation of all managed temporary memory regions.
     66   //
     67   // Called, for example, when the Stream owning this temporary memory manager
     68   // is destroyed.
     69   //
     70   // Note: These calls to Deallocate will likely force synchronization.
     71   void ForceDeallocateAll();
     72 
     73   // Marks the given memory region as finalized.
     74   //
     75   // If must_exist is set, this will check-fail if the temporary memory record
     76   // is not found.
     77   void MarkFinalized(const DeviceMemoryBase& device_memory, uint64 generation,
     78                      bool must_exist);
     79 
     80   // Deallocates temporary memories that have been finalized.
     81   //
     82   // Note: These calls to Deallocate will likely force synchronization, so it is
     83   // meant to be called before a "BlockHostUntilDone" is about to be performed.
     84   void DeallocateFinalizedTemporaries();
     85 
     86   // Returns whether the provided device_memory is finalized.
     87   //
     88   // In the vacuous case where the device memory doesn't appear in the temporary
     89   // memory records, it is either not a temporary at all, or has already been
     90   // deallocated, and thus returns true.
     91   bool IsFinalized(const DeviceMemoryBase& device_memory,
     92                    uint64 allocation_generation) const;
     93 
     94   // Returns whether the manager has a live allocation record for the given
     95   // device memory pointer with the given generation counter.
     96   //
     97   // Note: this is a polling call -- there is no guarantee that the region is
     98   // still allocated once the call has completed.
     99   bool HasAllocated(const DeviceMemoryBase& device_memory,
    100                     uint64 generation) const;
    101 
    102  private:
    103   // Allocates an array without type parameterization, so that the
    104   // implementation can live in the source file. Without this base allocation
    105   // method, we incur a circular dependency between the StreamExecutor
    106   // definition and this class' definition.
    107   port::StatusOr<std::unique_ptr<TemporaryDeviceMemoryBase>> AllocateArrayBase(
    108       uint64 element_count, uint64 element_size);
    109 
    110   // Mutex to guard temporary record state.
    111   mutable mutex mutex_;
    112 
    113   // Mapping from device memory to the current (live) temporary memory record.
    114   //
    115   // If a device memory is not in this mapping, it is not a temporary currently
    116   // allocated and owned by this temporary memory manager.
    117   std::map<DeviceMemoryBase, TemporaryMemoryRecord> records_ GUARDED_BY(mutex_);
    118 
    119   // Allocation generation -- we bump this counter to distinguish temporary
    120   // memory handles that have been deallocated and later reallocated at the same
    121   // device memory address.
    122   uint64 generation_ GUARDED_BY(mutex_);
    123 
    124   // The stream (parent object) for this temporary memory manager -- allocations
    125   // are performed through this stream handle.
    126   Stream* stream_;
    127 
    128   SE_DISALLOW_COPY_AND_ASSIGN(TemporaryMemoryManager);
    129 };
    130 
    131 ////////////
    132 // Inlines
    133 
    134 template <typename T>
    135 port::StatusOr<std::unique_ptr<TemporaryDeviceMemory<T>>>
    136 TemporaryMemoryManager::AllocateArray(uint64 element_count) {
    137   port::StatusOr<std::unique_ptr<TemporaryDeviceMemoryBase>> temporary_memory =
    138       AllocateArrayBase(element_count, sizeof(T));
    139   if (!temporary_memory.ok()) {
    140     return temporary_memory.status();
    141   }
    142 
    143   return std::unique_ptr<TemporaryDeviceMemory<T>>(
    144       reinterpret_cast<TemporaryDeviceMemory<T>*>(
    145           temporary_memory.ConsumeValueOrDie().release()));
    146 }
    147 
    148 }  // namespace internal
    149 }  // namespace stream_executor
    150 
    151 #endif  // TENSORFLOW_STREAM_EXECUTOR_TEMPORARY_MEMORY_MANAGER_H_
    152