HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CE_MemoryPool.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: CE_MemoryPool.h ( CE Library, C++)
7  *
8  * COMMENTS: Compute Engine Memory Pool.
9  */
10 
11 #ifndef __CE_MemoryPool__
12 #define __CE_MemoryPool__
13 
14 #include "CE_API.h"
15 
16 #include <UT/UT_Array.h>
17 #include <UT/UT_Lock.h>
18 #include <UT/UT_LRUCache.h>
19 #include <UT/UT_Map.h>
20 #include <UT/UT_MemoryResource.h>
21 #include <UT/UT_UniquePtr.h>
22 #include <SYS/SYS_Types.h>
23 
24 #include <iosfwd>
25 
26 #if UT_ASSERT_LEVEL >= UT_ASSERT_LEVEL_NORMAL
27 #include <set>
28 #endif
29 
30 class CE_Context;
31 
32 /// This class implements a memory pool for OpenCL buffer objects, using an
33 /// LRUCache to limit the size of the pool.
35 {
36 public:
37  /// Initialize the pool with specified maximum size.
39  virtual ~CE_MemoryPool();
40 
41  /// Empty the memory pool of all held buffers.
42  void clear();
43 
44  /// Set the maximums size of the pool. This will prune the LRUCache as
45  /// needed to fit the size.
46  void setMaxSize(int64 size) { myLRUCache.setMaxSize(size); }
47 
48  /// Returns the maximum size of the pool.
49  int64 getMaxSize() const { return myLRUCache.maxSize(); }
50 
51  /// Dump memory usage statistics to stderr.
52  void reportUsage() const;
53 
54  /// Dump memory to a stream
55  void reportUsage(std::ostream &os) const;
56 
57  /// Query the current usage; total is the total amount of memory held by the
58  /// pool, not_in_use is the amount that can be freed immediately on demand.
59  void getUsage(exint& total, exint& not_in_use) const
60  {
61  not_in_use = myLRUCache.currentSize();
62  total = not_in_use + myInUseSize;
63  }
64 
65  /// Allocate a buffer for the provided context. If a buffer of the
66  /// specified size already exists in the pool, it will be returned.
67  /// Otherwise a new one will be created on the device.
68  cl::Buffer allocBuffer(CE_Context *, int64 size);
69 
70  /// Check the provided buffer's reference count. If it is about to be
71  /// released, return it to the pool if it will fit, else release it. If
72  /// the reference count is higher than 1, meaning it is still active in
73  /// an asynchronous operation like a kernel, put it on the inUse list to
74  /// check later in sweepInUse().
75  void returnBuffer(cl::Buffer &&buf, bool use_pool);
76 
77  /// Sweep the inUse list, looking for buffers that are no longer being used
78  /// in an asynchronous operation and can be returned to the pool. Returns
79  /// the amount of released memory (i.e. memory that's returned back to the
80  /// system).
81  exint sweepInUse();
82 
83  /// Attempts to release the requested amount of memory back to the system.
84  /// Returns the amount actually freed.
85  exint freeMemory(exint amount);
86 
87  /// Registers this memory pool as a client for the given resource. This must
88  /// be called with the appropriate memory resource to ensure that the memory
89  /// pool can be asked to unload when device memory is tight.
91  {
92  resource->registerClient(&myMemoryClient, UT_MemoryClient::NORMAL_FREE);
93  }
94  /// Unregisters this memory pool as a client for the given resource. This
95  /// must be called on destruction with the same resource used with
96  /// registerClient().
98  {
99  resource->unregisterClient(&myMemoryClient);
100  }
101 
102 private:
103  // This class just holds a cl::Buffer while it's in the LRUCache. It's also
104  // responsible for alerting the CE_MemoryPool object when it's deleted
105  // by pruning or other means. Each cl::Buffer is owned by only one of
106  // these objects, as maintained by being non-copyable and having move
107  // semantics.
108  class ut_clBuffer : public UT_NonCopyable
109  {
110  public:
111  ut_clBuffer(CE_MemoryPool *pool, const cl::Buffer &buf, int64 size);
112 
113  ut_clBuffer(ut_clBuffer &&b);
114 
115  ~ut_clBuffer();
116 
117  ut_clBuffer &operator=(ut_clBuffer &&b);
118 
119  static exint size(const ut_clBuffer &b) { return b.mySize; }
120 
121  private:
122  int64 mySize;
123  cl::Buffer myBuffer;
124  CE_MemoryPool *myPool;
125  };
126 
127  /// This memory client is used to ensure that this memory pool plays nicely
128  /// with other users of memory on the OpenCL device.
129  class MemoryClient : public UT_MemoryClient
130  {
131  public:
132  MemoryClient(CE_MemoryPool& pool) : myMemoryPool(pool) {}
133 
134  const char* name() const override
135  {
136  return "OpenCL Buffer Pool";
137  }
138 
139  bool freeMemoryRequest(const UT_MemoryResource* resource,
140  RequestSeverity severity, Niceness niceness,
141  exint amount, exint& freed_amount) override
142  {
143  freed_amount = myMemoryPool.sweepInUse();
144  if (freed_amount < amount)
145  freed_amount += myMemoryPool.freeMemory(amount - freed_amount);
146  return freed_amount > 0;
147  }
148 
149  bool memoryUse(const UT_MemoryResource* resource, exint& in_use,
150  exint& cache) override
151  {
152  myMemoryPool.getUsage(in_use, cache);
153  return true;
154  }
155 
156  private:
157  CE_MemoryPool& myMemoryPool;
158  };
159 
160  friend class ut_clBuffer;
161  friend class CE_Context;
162 
163  bool getBufferFromPool(int64 size, cl::Buffer &buf);
164 
165  /// Add the buffer to the pool. Returns false if it operation fails.
166  bool appendToPool(const cl::Buffer &buf, int64 size);
167 
168  /// Remove the the buffer from the pool.
169  void releaseBuffer(const cl::Buffer &buf, int64 size);
170 
171  /// Used for tracing and debugging buffer allocations.
172  void recordAlloc(cl_mem buffer, int64 size);
173  void recordDealloc(cl_mem buffer, int64 size, bool returning=true);
174 
177  using BufferPtr = UT_UniquePtr<cl::Buffer>;
178 
179  BufferCache myLRUCache;
180  UT_Array<BufferPtr> myInUseList;
181  BufferTable myBufferTable;
182  int64 myInUseSize;
183  int64 myTotalAllocSize;
184  mutable UT_Lock myMemoryPoolLock;
185 
186  /// The memory client that's registered with the OpenCL device.
187  MemoryClient myMemoryClient;
188 
189 #if UT_ASSERT_LEVEL >= UT_ASSERT_LEVEL_NORMAL
190  // Used for catching dangling buffers in debug/opt builds.
191  void validateAndFreeBuffer(cl_mem buf);
192  static void memDestructorCallback(cl_mem, void *);
193  UT_Map<cl_mem, int64> myActiveBuffers;
194  std::multiset<cl_mem> myReturnedBuffers;
195 #endif
196 };
197 
198 
199 #endif
#define CE_API
Definition: CE_API.h:13
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
void getUsage(exint &total, exint &not_in_use) const
Definition: CE_MemoryPool.h:59
Unsorted map container.
Definition: UT_Map.h:109
int64 exint
Definition: SYS_Types.h:125
void releaseBuffer(cl::Buffer &&buf, bool use_pool=true)
Release the specified buffer, possibly to the CE_MemoryPool.
void setMaxSize(int64 size)
Definition: CE_MemoryPool.h:46
GLuint buffer
Definition: glcorearb.h:660
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
bool registerClient(UT_MemoryClient *client, UT_MemoryClient::Niceness niceness)
Register as a client of the memory resource.
long long int64
Definition: SYS_Types.h:116
GLenum GLenum severity
Definition: glcorearb.h:2539
struct _cl_mem * cl_mem
Definition: cl.h:33
GLuint const GLchar * name
Definition: glcorearb.h:786
bool unregisterClient(UT_MemoryClient *client)
Remove 'client' from this memory resource.
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
int64 getMaxSize() const
Returns the maximum size of the pool.
Definition: CE_MemoryPool.h:49
GLsizeiptr size
Definition: glcorearb.h:664
void registerClient(UT_MemoryResource *resource)
Definition: CE_MemoryPool.h:90
LeafData & operator=(const LeafData &)=delete
Memory buffer interface.
Definition: cl.hpp:1867
Wrapper for a client of a limit memory resource.
void unregisterClient(UT_MemoryResource *resource)
Definition: CE_MemoryPool.h:97
**Note that the tasks the is the thread number *for the pool
Definition: thread.h:646