DFace C++ SDK  2.5.2
allocator.h
浏览该文件的文档.
1 #ifndef DFACE_ALLOCATOR_H
2 #define DFACE_ALLOCATOR_H
3 
4 #ifdef _WIN32
5 #define WIN32_LEAN_AND_MEAN
6 #include <windows.h>
7 #else
8 #include <pthread.h>
9 #endif
10 
11 #include <stdlib.h>
12 #include <list>
13 
14 namespace dface {
15 
16 // the alignment of all the allocated buffers
17 #define MALLOC_ALIGN 16
18 
19 // Aligns a pointer to the specified number of bytes
20 // ptr Aligned pointer
21 // n Alignment size that must be a power of two
22 template<typename _Tp> static inline _Tp* alignPtr(_Tp* ptr, int n=(int)sizeof(_Tp))
23 {
24  return (_Tp*)(((size_t)ptr + n-1) & -n);
25 }
26 
27 // Aligns a buffer size to the specified number of bytes
28 // The function returns the minimum number that is greater or equal to sz and is divisible by n
29 // sz Buffer size to align
30 // n Alignment size that must be a power of two
31 static inline size_t alignSize(size_t sz, int n)
32 {
33  return (sz + n-1) & -n;
34 }
35 
36 static inline void* fastMalloc(size_t size)
37 {
38  unsigned char* udata = (unsigned char*)malloc(size + sizeof(void*) + MALLOC_ALIGN);
39  if (!udata)
40  return 0;
41  unsigned char** adata = alignPtr((unsigned char**)udata + 1, MALLOC_ALIGN);
42  adata[-1] = udata;
43  return adata;
44 }
45 
46 static inline void fastFree(void* ptr)
47 {
48  if (ptr)
49  {
50  unsigned char* udata = ((unsigned char**)ptr)[-1];
51  free(udata);
52  }
53 }
54 
55 // exchange-add operation for atomic operations on reference counters
56 #if defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32)
57 // atomic increment on the linux version of the Intel(tm) compiler
58 # define DFACE_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast<void*>(reinterpret_cast<volatile void*>(addr)), delta)
59 #elif defined __GNUC__
60 # if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__)
61 # ifdef __ATOMIC_ACQ_REL
62 # define DFACE_XADD(addr, delta) __c11_atomic_fetch_add((_Atomic(int)*)(addr), delta, __ATOMIC_ACQ_REL)
63 # else
64 # define DFACE_XADD(addr, delta) __atomic_fetch_add((_Atomic(int)*)(addr), delta, 4)
65 # endif
66 # else
67 # if defined __ATOMIC_ACQ_REL && !defined __clang__
68 // version for gcc >= 4.7
69 # define DFACE_XADD(addr, delta) (int)__atomic_fetch_add((unsigned*)(addr), (unsigned)(delta), __ATOMIC_ACQ_REL)
70 # else
71 # define DFACE_XADD(addr, delta) (int)__sync_fetch_and_add((unsigned*)(addr), (unsigned)(delta))
72 # endif
73 # endif
74 #elif defined _MSC_VER && !defined RC_INVOKED
75 # include <intrin.h>
76 # define DFACE_XADD(addr, delta) (int)_InterlockedExchangeAdd((long volatile*)addr, delta)
77 #else
78 // thread-unsafe branch
79 static inline int DFACE_XADD(int* addr, int delta) { int tmp = *addr; *addr += delta; return tmp; }
80 #endif
81 
82 #ifdef _WIN32
83 class Mutex
84 {
85 public:
86  Mutex() { InitializeSRWLock(&srwlock); }
87  ~Mutex() {}
88  void lock() { AcquireSRWLockExclusive(&srwlock); }
89  void unlock() { ReleaseSRWLockExclusive(&srwlock); }
90 private:
91  // NOTE SRWLock is available from windows vista
92  SRWLOCK srwlock;
93 };
94 #else // _WIN32
95 class Mutex
96 {
97 public:
98  Mutex() { pthread_mutex_init(&mutex, 0); }
99  ~Mutex() { pthread_mutex_destroy(&mutex); }
100  void lock() { pthread_mutex_lock(&mutex); }
101  void unlock() { pthread_mutex_unlock(&mutex); }
102 private:
103  pthread_mutex_t mutex;
104 };
105 #endif // _WIN32
106 
108 {
109 public:
110  virtual void* fastMalloc(size_t size) = 0;
111  virtual void fastFree(void* ptr) = 0;
112 };
113 
114 class PoolAllocator : public Allocator
115 {
116 public:
118  size_compare_ratio = 192;
119  }
121  clear();
122 
123  if (!payouts.empty())
124  {
125  fprintf(stderr, "FATAL ERROR! pool allocator destroyed too early\n");
126  std::list< std::pair<size_t, void*> >::iterator it = payouts.begin();
127  for (; it != payouts.end(); it++)
128  {
129  void* ptr = it->second;
130  fprintf(stderr, "%p still in use\n", ptr);
131  }
132  }
133  }
134 
135  // ratio range 0 ~ 1
136  // default cr = 0.75
137  void set_size_compare_ratio(float scr){
138  if (scr < 0.f || scr > 1.f)
139  {
140  fprintf(stderr, "invalid size compare ratio %f\n", scr);
141  return;
142  }
143  size_compare_ratio = (unsigned int)(scr * 256);
144  }
145 
146  // release all budgets immediately
147  void clear(){
148  budgets_lock.lock();
149 
150  std::list< std::pair<size_t, void*> >::iterator it = budgets.begin();
151  for (; it != budgets.end(); it++)
152  {
153  void* ptr = it->second;
154  dface::fastFree(ptr);
155  }
156  budgets.clear();
157 
158  budgets_lock.unlock();
159  }
160 
161  void* fastMalloc(size_t size){
162  budgets_lock.lock();
163 
164  // find free budget
165  std::list< std::pair<size_t, void*> >::iterator it = budgets.begin();
166  for (; it != budgets.end(); it++)
167  {
168  size_t bs = it->first;
169 
170  // size_compare_ratio ~ 100%
171  if (bs >= size && ((bs * size_compare_ratio) >> 8) <= size)
172  {
173  void* ptr = it->second;
174 
175  budgets.erase(it);
176 
177  budgets_lock.unlock();
178 
179  payouts_lock.lock();
180 
181  payouts.push_back(std::make_pair(bs, ptr));
182 
183  payouts_lock.unlock();
184 
185  return ptr;
186  }
187  }
188 
189  budgets_lock.unlock();
190 
191  // new
192  void* ptr = dface::fastMalloc(size);
193 
194  payouts_lock.lock();
195 
196  payouts.push_back(std::make_pair(size, ptr));
197 
198  payouts_lock.unlock();
199 
200  return ptr;
201  }
202 
203  void fastFree(void* ptr){
204  payouts_lock.lock();
205 
206  // return to budgets
207  std::list< std::pair<size_t, void*> >::iterator it = payouts.begin();
208  for (; it != payouts.end(); it++)
209  {
210  if (it->second == ptr)
211  {
212  size_t size = it->first;
213 
214  payouts.erase(it);
215 
216  payouts_lock.unlock();
217 
218  budgets_lock.lock();
219 
220  budgets.push_back(std::make_pair(size, ptr));
221 
222  budgets_lock.unlock();
223 
224  return;
225  }
226  }
227 
228  payouts_lock.unlock();
229 
230  fprintf(stderr, "FATAL ERROR! pool allocator get wild %p\n", ptr);
231  dface::fastFree(ptr);
232  }
233 
234 private:
235  Mutex budgets_lock;
236  Mutex payouts_lock;
237  unsigned int size_compare_ratio;// 0~256
238  std::list< std::pair<size_t, void*> > budgets;
239  std::list< std::pair<size_t, void*> > payouts;
240 };
241 
243 {
244 public:
246  size_compare_ratio = 192;// 0.75f * 256
247  }
249  clear();
250 
251  if (!payouts.empty())
252  {
253  fprintf(stderr, "FATAL ERROR! unlocked pool allocator destroyed too early\n");
254  std::list< std::pair<size_t, void*> >::iterator it = payouts.begin();
255  for (; it != payouts.end(); it++)
256  {
257  void* ptr = it->second;
258  fprintf(stderr, "%p still in use\n", ptr);
259  }
260  }
261  }
262 
263  // ratio range 0 ~ 1
264  // default cr = 0.75
265  void set_size_compare_ratio(float scr){
266  if (scr < 0.f || scr > 1.f)
267  {
268  fprintf(stderr, "invalid size compare ratio %f\n", scr);
269  return;
270  }
271 
272  size_compare_ratio = (unsigned int)(scr * 256);
273  }
274 
275  // release all budgets immediately
276  void clear(){
277  std::list< std::pair<size_t, void*> >::iterator it = budgets.begin();
278  for (; it != budgets.end(); it++)
279  {
280  void* ptr = it->second;
281  dface::fastFree(ptr);
282  }
283  budgets.clear();
284  }
285 
286  virtual void* fastMalloc(size_t size){
287  // find free budget
288  std::list< std::pair<size_t, void*> >::iterator it = budgets.begin();
289  for (; it != budgets.end(); it++)
290  {
291  size_t bs = it->first;
292 
293  // size_compare_ratio ~ 100%
294  if (bs >= size && ((bs * size_compare_ratio) >> 8) <= size)
295  {
296  void* ptr = it->second;
297 
298  budgets.erase(it);
299 
300  payouts.push_back(std::make_pair(bs, ptr));
301 
302  return ptr;
303  }
304  }
305 
306  // new
307  void* ptr = dface::fastMalloc(size);
308 
309  payouts.push_back(std::make_pair(size, ptr));
310 
311  return ptr;
312  }
313 
314  virtual void fastFree(void* ptr){
315  // return to budgets
316  std::list< std::pair<size_t, void*> >::iterator it = payouts.begin();
317  for (; it != payouts.end(); it++)
318  {
319  if (it->second == ptr)
320  {
321  size_t size = it->first;
322 
323  payouts.erase(it);
324 
325  budgets.push_back(std::make_pair(size, ptr));
326 
327  return;
328  }
329  }
330 
331  fprintf(stderr, "FATAL ERROR! unlocked pool allocator get wild %p\n", ptr);
332  dface::fastFree(ptr);
333  }
334 
335 private:
336  unsigned int size_compare_ratio;// 0~256
337  std::list< std::pair<size_t, void*> > budgets;
338  std::list< std::pair<size_t, void*> > payouts;
339 };
340 
341 } // namespace dface
342 
343 #endif // DFACE_ALLOCATOR_H
Definition: allocator.h:14
Mutex()
Definition: allocator.h:98
virtual void fastFree(void *ptr)
Definition: allocator.h:314
Definition: allocator.h:242
UnlockedPoolAllocator()
Definition: allocator.h:245
void * fastMalloc(size_t size)
Definition: allocator.h:161
virtual void * fastMalloc(size_t size)
Definition: allocator.h:286
#define MALLOC_ALIGN
Definition: allocator.h:17
void lock()
Definition: allocator.h:100
~UnlockedPoolAllocator()
Definition: allocator.h:248
Definition: allocator.h:114
void clear()
Definition: allocator.h:147
void clear()
Definition: allocator.h:276
void fastFree(void *ptr)
Definition: allocator.h:203
~Mutex()
Definition: allocator.h:99
void set_size_compare_ratio(float scr)
Definition: allocator.h:265
void unlock()
Definition: allocator.h:101
Definition: allocator.h:95
~PoolAllocator()
Definition: allocator.h:120
void set_size_compare_ratio(float scr)
Definition: allocator.h:137
Definition: allocator.h:107
PoolAllocator()
Definition: allocator.h:117