A platform for high-performance distributed tool and library development written in C++. It can be deployed in two different cluster modes: standalone or distributed. API for v0.5.0, released on June 13, 2018.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Allocator.cc
Go to the documentation of this file.
1 /*****************************************************************************
2  * *
3  * Copyright 2018 Rice University *
4  * *
5  * Licensed under the Apache License, Version 2.0 (the "License"); *
6  * you may not use this file except in compliance with the License. *
7  * You may obtain a copy of the License at *
8  * *
9  * http://www.apache.org/licenses/LICENSE-2.0 *
10  * *
11  * Unless required by applicable law or agreed to in writing, software *
12  * distributed under the License is distributed on an "AS IS" BASIS, *
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
14  * See the License for the specific language governing permissions and *
15  * limitations under the License. *
16  * *
17  *****************************************************************************/
18 
19 #ifndef ALLOCATOR_CC
20 #define ALLOCATOR_CC
21 
22 #include "PDBDebug.h"
23 #include <sstream>
24 #include <cstddef>
25 #include <iostream>
26 #include <vector>
27 #include <algorithm>
28 #include <iterator>
29 #include <cstring>
30 
31 namespace pdb {
32 
33 #define CHAR_PTR(c) ((char*)c)
34 #define ALLOCATOR_REF_COUNT (*((unsigned*)(CHAR_PTR(start) + 2 * sizeof(size_t))))
35 
37  start = nullptr;
38  end = 0;
39 }
40 
41 // free the memory associated with the block
43  if (start != nullptr)
44  free(start);
45 }
46 
47 // create a block
48 inline InactiveAllocationBlock::InactiveAllocationBlock(void* startIn, size_t numBytes) {
49  start = startIn;
50  end = CHAR_PTR(startIn) + numBytes;
51 }
52 
53 // returns true if the block is *before* compToMe, and does not contain it
54 inline bool operator<(const InactiveAllocationBlock& in, const void* compToMe) {
55  return (CHAR_PTR(in.end) < CHAR_PTR(compToMe));
56 }
57 
58 // returns true if the ends of the lhs is before the end of the rhs
59 inline bool operator<(const InactiveAllocationBlock& lhs, const InactiveAllocationBlock& rhs) {
60  return (CHAR_PTR(lhs.end) < CHAR_PTR(rhs.end));
61 }
62 
63 // returns true if the block is *after* compToMe, and does not contain it
64 inline bool operator>(const InactiveAllocationBlock& in, const void* compToMe) {
65  return (CHAR_PTR(in.start) > CHAR_PTR(compToMe));
66 }
67 
68 // returns true if the block contains compToMe
69 inline bool operator==(const InactiveAllocationBlock& in, const void* compToMe) {
70  return (CHAR_PTR(in.start) <= CHAR_PTR(compToMe) && CHAR_PTR(in.end) >= CHAR_PTR(compToMe));
71 }
72 
73 // decrement the reference count of this block
76 }
77 
78 // free it if there are no more references
80  return ALLOCATOR_REF_COUNT == 0;
81 }
82 
84  return ALLOCATOR_REF_COUNT;
85 }
86 
88  return (char*)end - (char*)start;
89 }
90 
92  return start;
93 }
94 
96  return end;
97 }
98 
99 // These macros are used to manipulate the block of RAM that makes up an allocation block
100 // The layout is | num bytes used | offset to root object | number active objects | data <--> |
101 #undef ALLOCATOR_REF_COUNT
102 #define ALLOCATOR_REF_COUNT (*((unsigned*)(CHAR_PTR(myState.activeRAM) + 2 * sizeof(size_t))))
103 #define LAST_USED (*((size_t*)myState.activeRAM))
104 #define OFFSET_TO_OBJECT (*((size_t*)(CHAR_PTR(myState.activeRAM) + sizeof(size_t))))
105 #define OFFSET_TO_OBJECT_RELATIVE(fromWhere) (*((size_t*)(CHAR_PTR(fromWhere) + sizeof(size_t))))
106 #define HEADER_SIZE (sizeof(unsigned) + 2 * sizeof(size_t))
107 #define GET_CHUNK_SIZE(ofMe) (*((unsigned*)ofMe))
108 #define CHUNK_HEADER_SIZE sizeof(unsigned)
109 
110 // free some RAM
111 #ifdef DEBUG_OBJECT_MODEL
112 inline void defaultFreeRAM(bool isContained,
113  void* here,
114  std::vector<InactiveAllocationBlock>& allInactives,
115  AllocatorState& myState,
116  int16_t typeId) {
117 #else
118 inline void defaultFreeRAM(bool isContained,
119  void* here,
120  std::vector<InactiveAllocationBlock>& allInactives,
121  AllocatorState& myState) {
122 #endif
123 
124  // see if this guy is from the active block
125  if (isContained) {
126 
127  here = CHAR_PTR(here) - CHUNK_HEADER_SIZE;
128 
129  // get the chunk size
130  unsigned chunkSize = GET_CHUNK_SIZE(here);
131 
132  // get the number of leading zeros
133  int leadingZeros = __builtin_clz(chunkSize);
134 
135  // and remember this chunk
136  myState.chunks[31 - leadingZeros].push_back(here);
137 
139 
140 #ifdef DEBUG_OBJECT_MODEL
141  std::cout << "**defaultFreeRAM**" << std::endl;
142  std::cout << "###################################" << std::endl;
143  std::cout << "allocator block reference count--=" << ALLOCATOR_REF_COUNT
144  << " with typeId=" << typeId << std::endl;
145  std::cout << "allocator block start =" << myState.activeRAM << std::endl;
146  std::cout << "allocator numBytes=" << myState.numBytes << std::endl;
147  std::cout << "freed numBytes=" << chunkSize << std::endl;
148  std::cout << "chunk index=" << 31 - leadingZeros << std::endl;
149  std::cout << "###################################" << std::endl;
150 #endif
151  return;
152  }
153 
154  // otherwise, he is not in the active block, so look for him
155  auto i = std::lower_bound(allInactives.begin(), allInactives.end(), here);
156 
157  // see if we found him
158  if (i != allInactives.end() && !(*i > here)) {
159 
160  // we did, so dec reference count
161  i->decReferenceCount();
162 #ifdef DEBUG_OBJECT_MODEL
163  std::cout << "###################################" << std::endl;
164  std::cout << "allocator block reference count--=" << i->getReferenceCount()
165  << " with typeId=" << typeId << std::endl;
166  std::cout << "allocator block starting address=" << i->getStart() << std::endl;
167  std::cout << "allocator block size=" << i->numBytes() << std::endl;
168  std::cout << "###################################" << std::endl;
169 #endif
170  // if he is done, delete him
171  if (i->areNoReferences()) {
172  i->freeBlock();
173  PDB_COUT << "Killed an old block naturally." << std::endl;
174  allInactives.erase(i);
175  }
176  return;
177  }
178 
179 // if we made it here, the object was allocated in some other way,
180 // so we can go ahead and forget about him
181 #ifdef DEBUG_OBJECT_MODEL
182  std::cout << "###################################################################" << std::endl;
183  std::cout << "We can't free the object, it may be allocated by some other thread!" << std::endl;
184  std::cout << "typeId=" << typeId << std::endl;
185  std::cout << "###################################################################" << std::endl;
186 #endif
187 }
188 
189 
190 // returns some RAM... this can throw an exception if the request is too large
191 // to be handled because there is not enough RAM in the current allocation block
192 #ifdef DEBUG_OBJECT_MODEL
193 inline void* defaultGetRAM(size_t howMuch, AllocatorState& myState, int16_t typeId) {
194  std::cout << "to get RAM with size = " << howMuch << " and typeId = " << typeId << std::endl;
195 #else
196 inline void* defaultGetRAM(size_t howMuch, AllocatorState& myState) {
197 #endif
198  unsigned bytesNeeded = (unsigned)(CHUNK_HEADER_SIZE + howMuch);
199  if ((bytesNeeded % 4) != 0) {
200  bytesNeeded += (4 - (bytesNeeded % 4));
201  }
202  // get the number of leading zero bits in bytesNeeded
203  unsigned int numLeadingZeros = __builtin_clz(bytesNeeded);
204 
205 #ifdef DEBUG_OBJECT_MODEL
206  std::cout << "howMuch=" << howMuch << ", bytesNeeded=" << bytesNeeded
207  << ", numLeadingZeros=" << numLeadingZeros << std::endl;
208 #endif
209 
210  // loop through all of the free chunks
211  // Lets say that someone asks for 54 bytes. In binary, this is ...000110110 and so there are 26
212  // leading zeros
213  // in the binary representation. So, we are going to loop through the sets of chunks at
214  // position 5 (2^5 and larger)
215  // at position 6 (2^6 and larger) at position 7 (2^7 and larger), and so on, trying to find one
216  // that fits.
217  for (unsigned int i = 31 - numLeadingZeros; i < 32; i++) {
218  int len = myState.chunks[i].size();
219  for (int j = len - 1; j >= 0; j--) {
220  if (GET_CHUNK_SIZE(myState.chunks[i][j]) >= bytesNeeded) {
221  void* returnVal = myState.chunks[i][j];
222  myState.chunks[i].erase(myState.chunks[i].begin() + j);
224  void* retAddress = CHAR_PTR(returnVal) + CHUNK_HEADER_SIZE;
225 #ifdef DEBUG_OBJECT_MODEL
226  std::cout << "**defaultGetRAM**" << std::endl;
227  std::cout << "###################################" << std::endl;
228  std::cout << "allocator block reference count++=" << ALLOCATOR_REF_COUNT
229  << " with typeId=" << typeId << std::endl;
230  std::cout << "allocator block start =" << myState.activeRAM << std::endl;
231  std::cout << "allocator numBytes=" << myState.numBytes << std::endl;
232  std::cout << "starting chunk index=" << 31 - numLeadingZeros << std::endl;
233  std::cout << "ending chunk index=" << i << std::endl;
234  std::cout << "bytes needed=" << bytesNeeded << std::endl;
235  std::cout << "###################################" << std::endl;
236 #endif
237  return retAddress;
238  }
239  }
240  }
241 
242  // if we got here, then we cannot fit, and we need to carve out a bit at the end
243  // if there is not enough RAM
244  if (LAST_USED + bytesNeeded > myState.numBytes) {
245 
246  // see how we are supposed to react...
247  if (myState.throwException) {
248  PDB_COUT << "Allocator: LAST_USED=" << LAST_USED << std::endl;
249  PDB_COUT << "Allocator: bytesNeeded=" << bytesNeeded << std::endl;
250  PDB_COUT << "Allocator: numBytes=" << myState.numBytes << std::endl;
251  // either we throw an exception...
252  throw myException;
253 
254  // or we return a nullptr
255  } else {
256  return nullptr;
257  }
258  }
259 
260  // now do the allocation
261  void* res = LAST_USED + CHAR_PTR(myState.activeRAM);
262  LAST_USED += bytesNeeded;
263  GET_CHUNK_SIZE(res) = bytesNeeded;
265  void* retAddress = CHAR_PTR(res) + CHUNK_HEADER_SIZE;
266 
267 #ifdef DEBUG_OBJECT_MODEL
268  std::cout << "###################################" << std::endl;
269  std::cout << "allocator block reference count++=" << ALLOCATOR_REF_COUNT
270  << " with typeId=" << typeId << std::endl;
271  std::cout << "allocator block start =" << myState.activeRAM << std::endl;
272  std::cout << "allocator numBytes=" << myState.numBytes << std::endl;
273  std::cout << "created a new chunk with size =" << bytesNeeded << std::endl;
274  std::cout << "###################################" << std::endl;
275 #endif
276  return retAddress;
277 }
278 
279 // returns some RAM... this can throw an exception if the request is too large
280 // to be handled because there is not enough RAM in the current allocation block
281 #ifdef DEBUG_OBJECT_MODEL
282 inline void* fastGetRAM(size_t howMuch, AllocatorState& myState, int16_t typeId) {
283  std::cout << "to get RAM with size = " << howMuch << " and typeId = " << typeId << std::endl;
284 #else
285 inline void* fastGetRAM(size_t howMuch, AllocatorState& myState) {
286 #endif
287  unsigned bytesNeeded = (unsigned)(CHUNK_HEADER_SIZE + howMuch);
288  if ((bytesNeeded % 4) != 0) {
289  bytesNeeded += (4 - (bytesNeeded % 4));
290  }
291 
292  // if we got here, then we cannot fit, and we need to carve out a bit at the end
293  // if there is not enough RAM
294  if (LAST_USED + bytesNeeded > myState.numBytes) {
295 
296  // see how we are supposed to react...
297  if (myState.throwException) {
298  PDB_COUT << "Allocator: LAST_USED=" << LAST_USED << std::endl;
299  PDB_COUT << "Allocator: bytesNeeded=" << bytesNeeded << std::endl;
300  PDB_COUT << "Allocator: numBytes=" << myState.numBytes << std::endl;
301  // either we throw an exception...
302  throw myException;
303 
304  // or we return a nullptr
305  } else {
306  return nullptr;
307  }
308  }
309 
310  // now do the allocation
311  void* res = LAST_USED + CHAR_PTR(myState.activeRAM);
312  LAST_USED += bytesNeeded;
313  GET_CHUNK_SIZE(res) = bytesNeeded;
315  void* retAddress = CHAR_PTR(res) + CHUNK_HEADER_SIZE;
316 
317 #ifdef DEBUG_OBJECT_MODEL
318  std::cout << "**fastGetRAM**" << std::endl;
319  std::cout << "###################################" << std::endl;
320  std::cout << "allocator block reference count++=" << ALLOCATOR_REF_COUNT
321  << " with typeId=" << typeId << std::endl;
322  std::cout << "allocator block start =" << myState.activeRAM << std::endl;
323  std::cout << "allocator numBytes=" << myState.numBytes << std::endl;
324  std::cout << "created a new chunk with size =" << bytesNeeded << std::endl;
325  std::cout << "###################################" << std::endl;
326 #endif
327  return retAddress;
328 }
329 
330 
331 // free some RAM
332 #ifdef DEBUG_OBJECT_MODEL
333 inline void DefaultPolicy::freeRAM(bool isContained,
334  void* here,
335  std::vector<InactiveAllocationBlock>& allInactives,
336  AllocatorState& myState,
337  int16_t typeId) {
338 #else
339 inline void DefaultPolicy::freeRAM(bool isContained,
340  void* here,
341  std::vector<InactiveAllocationBlock>& allInactives,
342  AllocatorState& myState) {
343 #endif
344 
345 #ifdef DEBUG_OBJECT_MODEL
346  defaultFreeRAM(isContained, here, allInactives, myState, typeId);
347 #else
348  defaultFreeRAM(isContained, here, allInactives, myState);
349 #endif
350 }
351 
352 // returns some RAM... this can throw an exception if the request is too large
353 // to be handled because there is not enough RAM in the current allocation block
354 #ifdef DEBUG_OBJECT_MODEL
355 inline void* DefaultPolicy::getRAM(size_t howMuch, AllocatorState& myState, int16_t typeId) {
356 #else
357 inline void* DefaultPolicy::getRAM(size_t howMuch, AllocatorState& myState) {
358 #endif
359 
360 #ifdef DEBUG_OBJECT_MODEL
361  return defaultGetRAM(howMuch, myState, typeId);
362 #else
363  return defaultGetRAM(howMuch, myState);
364 #endif
365 }
366 
367 
368 // free some RAM
369 #ifdef DEBUG_OBJECT_MODEL
370 inline void NoReusePolicy::freeRAM(bool isContained,
371  void* here,
372  std::vector<InactiveAllocationBlock>& allInactives,
373  AllocatorState& myState,
374  int16_t typeId) {
375 #else
376 inline void NoReusePolicy::freeRAM(bool isContained,
377  void* here,
378  std::vector<InactiveAllocationBlock>& allInactives,
379  AllocatorState& myState) {
380 #endif
381 
382 #ifdef DEBUG_OBJECT_MODEL
383  defaultFreeRAM(isContained, here, allInactives, myState, typeId);
384 #else
385  defaultFreeRAM(isContained, here, allInactives, myState);
386 #endif
387 }
388 
389 
390 // returns some RAM... this can throw an exception if the request is too large
391 // to be handled because there is not enough RAM in the current allocation block
392 #ifdef DEBUG_OBJECT_MODEL
393 inline void* NoReusePolicy::getRAM(size_t howMuch, AllocatorState& myState, int16_t typeId) {
394 #else
395 inline void* NoReusePolicy::getRAM(size_t howMuch, AllocatorState& myState) {
396 #endif
397 
398 #ifdef DEBUG_OBJECT_MODEL
399  return fastGetRAM(howMuch, myState, typeId);
400 #else
401  return fastGetRAM(howMuch, myState);
402 #endif
403 }
404 
405 
406 // free some RAM
407 #ifdef DEBUG_OBJECT_MODEL
408 inline void NoReferenceCountPolicy::freeRAM(bool isContained,
409  void* here,
410  std::vector<InactiveAllocationBlock>& allInactives,
411  AllocatorState& myState,
412  int16_t typeId) {
413  std::cout << "**NoReferenceCountPolicy**" << std::endl;
414 #else
415 inline void NoReferenceCountPolicy::freeRAM(bool isContained,
416  void* here,
417  std::vector<InactiveAllocationBlock>& allInactives,
418  AllocatorState& myState) {
419 #endif
420 }
421 
422 // returns some RAM... this can throw an exception if the request is too large
423 // to be handled because there is not enough RAM in the current allocation block
424 #ifdef DEBUG_OBJECT_MODEL
425 inline void* NoReferenceCountPolicy::getRAM(size_t howMuch,
426  AllocatorState& myState,
427  int16_t typeId) {
428 #else
429 inline void* NoReferenceCountPolicy::getRAM(size_t howMuch, AllocatorState& myState) {
430 #endif
431 
432 #ifdef DEBUG_OBJECT_MODEL
433  return defaultGetRAM(howMuch, myState, typeId);
434 #else
435  return defaultGetRAM(howMuch, myState);
436 #endif
437 }
438 
439 
440 // return true if allocations should not fail due to not enough RAM...
441 // in this case, a null pointer is returned on a bad allocate, and NOT
442 // an exception
443 template <typename FirstPolicy, typename... OtherPolicies>
445  return (myState.throwException == false);
446 }
447 
448 // destructor; if there is a self-allocated current allocation block, free it
449 template <typename FirstPolicy, typename... OtherPolicies>
451 
452  if (myState.activeRAM != nullptr && !myState.curBlockUserSupplied) {
454  std::cout << "This is bad. Current allocation block has "
455  << getNumObjectsInCurrentAllocatorBlock() << " references.\n";
456  }
457  free(myState.activeRAM);
458  }
459 
460  for (auto& a : allInactives) {
461  if (a.areNoReferences()) {
462  std::cout << "This is bad. There is an allocation block left with no references.\n";
463  // exit (1);
464  } else {
465  std::cout << "This is bad. There is an allocation block left with "
466  << a.getReferenceCount() << " references.\n";
467  // exit (1);
468  }
469  }
470 }
471 
472 // we have no active RAM
473 template <typename FirstPolicy, typename... OtherPolicies>
475  for (unsigned int i = 0; i < 32; i++) {
476  std::vector<void*> temp;
477  myState.chunks.push_back(temp);
478  }
479  myState.activeRAM = nullptr;
480  myState.numBytes = 0;
481 
482 // now, setup the active block
483 
484 // setupBlock (malloc (1024), 1024, true);
485 // JiaNote: we need initialize allocator block to make valgrind happy
486 #ifdef INITIALIZE_ALLOCATOR_BLOCK
487  void* putMeHere = calloc(1024, 1);
488 #else
489  void* putMeHere = malloc(1024);
490 #endif
491 
492  // JiaNote: malloc check
493  if (putMeHere == nullptr) {
494  std::cout << "Fatal Error in temporarilyUseBlockForAllocations(): out of memory with size="
495  << 1024 << std::endl;
496  exit(-1);
497  }
498  setupBlock(putMeHere, 1024, true);
499 
500  // by default, we optimize for space
501  setPolicy(defaultAllocator);
502 }
503 
504 template <typename FirstPolicy, typename... OtherPolicies>
506  for (unsigned int i = 0; i < 32; i++) {
507  std::vector<void*> temp;
508  myState.chunks.push_back(temp);
509  }
510  myState.activeRAM = nullptr;
511  myState.numBytes = 0;
512 
513 // now, setup the active block
514 // setupBlock (malloc (numBytesIn), numBytesIn, true);
515 
516 // JiaNote: we need initialize allocator block to make valgrind happy
517 #ifdef INITIALIZE_ALLOCATOR_BLOCK
518  void* putMeHere = calloc(1, numBytesIn);
519 #else
520  void* putMeHere = malloc(numBytesIn);
521 #endif
522  // JiaNote: malloc check
523  if (putMeHere == nullptr) {
524  std::cout << "Fatal Error in temporarilyUseBlockForAllocations(): out of memory with size="
525  << numBytesIn << std::endl;
526  exit(-1);
527  }
528  setupBlock(putMeHere, numBytesIn, true);
529 
530  // by default, we optimize for space
531  setPolicy(defaultAllocator);
532 }
533 
534 // set policy
535 template <typename FirstPolicy, typename... OtherPolicies>
537  // std :: cout << "to set policy " <<policy << std :: endl;
538  myPolicies.setPolicy(policy);
539 }
540 
541 // returns true if and only if the RAM is in the current allocation block
542 template <typename FirstPolicy, typename... OtherPolicies>
544  char* where = CHAR_PTR(whereIn);
545  char* target = CHAR_PTR(myState.activeRAM);
546  return (where >= target && where < target + myState.numBytes);
547 }
548 
549 
550 // returns some RAM... this can throw an exception if the request is too large
551 // to be handled because there is not enough RAM in the current allocation block
552 template <typename FirstPolicy, typename... OtherPolicies>
553 #ifdef DEBUG_OBJECT_MODEL
555  int16_t typeId) {
556 #else
558 #endif
559 
560 #ifdef DEBUG_OBJECT_MODEL
561  return myPolicies.getRAM(howMuch, myState, typeId);
562 #else
563  return myPolicies.getRAM(howMuch, myState);
564 #endif
565 
566  /*
567 
568  #ifdef DEBUG_OBJECT_MODEL
569  return defaultGetRAM (howMuch, myState, typeId);
570  #else
571  return defaultGetRAM (howMuch, myState);
572  #endif
573  */
574 }
575 
576 template <typename FirstPolicy, typename... OtherPolicies>
578 
579  // see if this guy is from the active block
580  if (contains(here)) {
581  return true;
582  }
583 
584  // otherwise, he is not in the active block, so look for him
585  auto i = std::lower_bound(allInactives.begin(), allInactives.end(), here);
586 
587  // see if we found him
588  if (i != allInactives.end() && !(*i > here)) {
589  return true;
590  }
591 
592  return false;
593 }
594 
595 template <typename FirstPolicy, typename... OtherPolicies>
597 
598  // if this is the active one, emty it out
599  if (contains(here)) {
600  // empty out the list of unused chunks of RAM in this block
601  for (auto& c : myState.chunks) {
602  c.clear();
603  }
604 
605  // LAST_USED = HEADER_SIZE;
607 
608  PDB_COUT << "Killed the current block.\n";
609  return;
610  }
611 
612  // otherwise, he is not in the active block, so look for him
613  auto i = std::lower_bound(allInactives.begin(), allInactives.end(), here);
614 
615  // see if we found him
616  if (i != allInactives.end() && !(*i > here)) {
617 
618  allInactives.erase(i);
619  PDB_COUT << "Killed an old block block.\n";
620  return;
621  }
622 
623  PDB_COUT << "This is kind of bad. You asked me to empty out a block, and I cannot find it.\n";
624 }
625 
626 // free some RAM
627 template <typename FirstPolicy, typename... OtherPolicies>
628 #ifdef DEBUG_OBJECT_MODEL
630  int16_t typeId) {
631 #else
633 #endif
634 
635  bool isContained = contains(here);
636 
637 #ifdef DEBUG_OBJECT_MODEL
638  myPolicies.freeRAM(isContained, here, allInactives, myState, typeId);
639 #else
640  myPolicies.freeRAM(isContained, here, allInactives, myState);
641 #endif
642 
643  /*
644  #ifdef DEBUG_OBJECT_MODEL
645  defaultFreeRAM (isContained, here, allInactives, myState, typeId);
646  #else
647  defaultFreeRAM (isContained, here, allInactives, myState);
648  #endif
649  */
650 }
651 
652 template <typename FirstPolicy, typename... OtherPolicies>
654  void* where, size_t numBytesIn, bool throwExceptionOnFail) {
655  setupBlock(where, numBytesIn, throwExceptionOnFail);
656  myState.curBlockUserSupplied = true;
657 }
658 
659 template <typename FirstPolicy, typename... OtherPolicies>
660 inline size_t
662 
663  // count all of the chunks that are not currently in use
664  unsigned amtUnused = 0;
665  for (auto& a : myState.chunks) {
666  for (auto& v : a) {
667  amtUnused += GET_CHUNK_SIZE(v);
668  }
669  }
670 
671  return myState.numBytes - LAST_USED + amtUnused;
672 }
673 
674 template <typename FirstPolicy, typename... OtherPolicies>
675 inline unsigned
677  return ALLOCATOR_REF_COUNT;
678 }
679 
680 template <typename FirstPolicy, typename... OtherPolicies>
682  void* here) {
683 
684  // see if this guy is from the active block
685  if (contains(here)) {
686  return ALLOCATOR_REF_COUNT;
687  }
688 
689  // otherwise, he is not in the active block, so look for him
690  auto i = std::lower_bound(allInactives.begin(), allInactives.end(), here);
691 
692  // see if we found him
693  if (i != allInactives.end() && !(*i > here)) {
694 
695  // we did, so dec reference count
696  return i->getReferenceCount();
697  }
698 
699  return 0;
700 }
701 
702 template <typename FirstPolicy, typename... OtherPolicies>
703 template <class ObjType>
705  Handle<ObjType>& forMe) {
706 
707  void* here = forMe.getTarget();
708  return getNumObjectsInAllocatorBlock(here);
709 }
710 
711 template <typename FirstPolicy, typename... OtherPolicies>
713  void* where, size_t numBytesIn, bool throwExceptionOnFail) {
714 
715 
716  // make sure that we are gonna be able to write the header
717  if (numBytesIn < HEADER_SIZE) {
718  std::cerr << "You need to have an allocation block that is at least " << HEADER_SIZE
719  << " bytes.\n";
720  exit(1);
721  }
722 
723  // make sure that pointer to where is valid-- added by Jia
724  if (where == nullptr) {
725  std::cerr << "Fatal Error in setupBlock(): The block doesn't have a valid address"
726  << std::endl;
727  exit(1);
728  }
729 
730  // remember how to handle a failed allocate
731  myState.throwException = throwExceptionOnFail;
732 
733  // if there is currently an active block, then it becomes inactive
734  if (myState.activeRAM != nullptr && !myState.curBlockUserSupplied) {
735 
736  // don't remember a block with no objects
737  if (ALLOCATOR_REF_COUNT != 0) {
738  allInactives.emplace_back(myState.activeRAM, myState.numBytes);
739  std::sort(allInactives.begin(), allInactives.end());
740  } else {
741  free(myState.activeRAM);
742  }
743  }
744 
745  // empty out the list of unused chunks of RAM in this block
746  for (auto& c : myState.chunks) {
747  c.clear();
748  }
749 
750  myState.activeRAM = where;
751 
752  myState.numBytes = numBytesIn;
753  myState.curBlockUserSupplied = false;
756 }
757 
758 template <typename FirstPolicy, typename... OtherPolicies>
759 template <class ObjType>
761  Handle<ObjType>& forMe) {
762 
763  // try to find the allocation block
764  void* here = forMe.getTarget();
765  // see if this guy is from the active block
766  if (contains(here)) {
767  // std :: cout << "getAllocationBlock: object offset =" << CHAR_PTR (here) - CHAR_PTR
768  // (myState.activeRAM) << std :: endl;
769  // set up the pointer to the object
770  OFFSET_TO_OBJECT = CHAR_PTR(here) - CHAR_PTR(myState.activeRAM);
771  return myState.activeRAM;
772  }
773 
774  // he's not, so see if he is from another block
775  auto i = std::lower_bound(allInactives.begin(), allInactives.end(), here);
776 
777  // see if we found him
778  if (i != allInactives.end() && !(*i > here)) {
779 
780  // set up the pointer to the object
781  OFFSET_TO_OBJECT_RELATIVE(i->start) = CHAR_PTR(here) - CHAR_PTR(i->start);
782  return i->start;
783  }
784 
785  // if we got here, we could not find this dude
786  return nullptr;
787 }
788 
789 // uses a specified block of memory for all allocations, until
790 // restoreAllocationBlock () is called.
791 template <typename FirstPolicy, typename... OtherPolicies>
792 inline AllocatorState
794  void* putMeHere, size_t numBytesAvailable) {
795 
796  // remember the old stuff
797  AllocatorState returnVal = myState;
798 
799  // mark this one as user-supplied so that it is remembered
800  myState.curBlockUserSupplied = false;
801 
802  // give the current alloction block a phantom reference count so it is not freed
804 
805  // and set up the new block
806  setupUserSuppliedBlock(putMeHere, numBytesAvailable, true);
807  return returnVal;
808 }
809 
810 // uses a specified block of memory for all allocations, until
811 // restoreAllocationBlock () is called.
812 template <typename FirstPolicy, typename... OtherPolicies>
813 inline AllocatorState
815  size_t numBytesAvailable) {
816 
817  // remember the old stuff
818  AllocatorState returnVal = myState;
819 
820  // mark this one as user-supplied so that it is remembered
821  myState.curBlockUserSupplied = false;
822 
823  // give the current alloction block a phantom reference count so it is not freed
825 
826 // and set up the new block
827 // JiaNote: we need initialize allocator block to make valgrind happy
828 #ifdef INITIALIZE_ALLOCATOR_BLOCK
829  void* putMeHere = calloc(numBytesAvailable, 1);
830 #else
831  void* putMeHere = malloc(numBytesAvailable);
832 #endif
833  // JiaNote: malloc check
834  if (putMeHere == nullptr) {
835  std::cout << "Fatal Error in temporarilyUseBlockForAllocations(): out of memory with size="
836  << numBytesAvailable << std::endl;
837  exit(-1);
838  }
839  setupBlock(putMeHere, numBytesAvailable, true);
840  return returnVal;
841 }
842 
843 // goes back to the old allocation block.. this should only
844 // by called after a call to temporarilyUseBlockForAllocations ()
845 template <typename FirstPolicy, typename... OtherPolicies>
847  AllocatorState& useMe) {
848 
849  // if this guy was not user-allocated, then remember him
850  if (!myState.curBlockUserSupplied) {
851  if (ALLOCATOR_REF_COUNT != 0) {
852  allInactives.emplace_back(myState.activeRAM, myState.numBytes);
853  std::sort(allInactives.begin(), allInactives.end());
854  } else {
855  free(myState.activeRAM);
856  }
857  }
858 
859  // restore the old one
860  myState = useMe;
861 
862  // remove the old allocation block from the list of inactive ones
863  for (int i = 0; i < allInactives.size(); i++) {
864  if (allInactives[i].start == myState.activeRAM) {
865  allInactives.erase(allInactives.begin() + i);
866  break;
867  }
868  }
869 
870  // remove the phantom reference count for the old block
872 }
873 
874 // added by Jia to facilitate debugging
875 template <typename FirstPolicy, typename... OtherPolicies>
877  std::string out = "Allocator: address= ";
878  std::stringstream stream;
879  stream << myState.activeRAM;
880  out = out + stream.str();
881  out = out + ", size=";
882  out = out + std::to_string(myState.numBytes);
883  PDB_COUT << out << std::endl;
884  return out;
885 }
886 
887 template <typename FirstPolicy, typename... OtherPolicies>
889 
890  int i;
891  std::string out = "Allocator: NumInactives=";
892  int numInactives = allInactives.size();
893  out = out + std::to_string(numInactives);
894  out = out + std::string("\n");
895 
896  for (i = 0; i < numInactives; i++) {
897  InactiveAllocationBlock curBlock = allInactives[i];
898  out = out + std::to_string(i);
899  out = out + std::string(":");
900  out = out + std::to_string(curBlock.getReferenceCount());
901  out = out + std::string(", size=");
902  out = out + std::to_string(curBlock.numBytes());
903  out = out + std::string(", start=");
904  std::stringstream stream;
905  stream << curBlock.getStart();
906  out = out + stream.str();
907  out = out + std::string("\n");
908  }
909 
910  PDB_COUT << out << std::endl;
911  return out;
912 }
913 
914 // Added by Jia
915 // this function should only be used for debugging purposes.
916 template <typename FirstPolicy, typename... OtherPolicies>
918  for (auto it = allInactives.begin(); it != allInactives.end();) {
919  it->freeBlock();
920  it = allInactives.erase(it);
921  }
922  return;
923 }
924 
925 template <typename FirstPolicy, typename... OtherPolicies>
927  for (auto it = allInactives.begin(); it != allInactives.end();) {
928  if (it->numBytes() == size) {
929  it->freeBlock();
930  it = allInactives.erase(it);
931  } else {
932  it++;
933  }
934  }
935  return;
936 }
937 
938 
939 extern void* stackBase;
940 extern void* stackEnd;
942 
944 
945  // this serves to gives us the location of our stack, which we use to map to an allocator
946  int i;
947 
948  // if we are not in one of the created worker threads, then we return the main allocator
949  // we know we are not in one of the worker threads if (a) there are no worker threads (stackBase
950  // is null)
951  // or the address of i is not within the valid range of the stack
952  if (stackBase == nullptr || !(((char*)&i) >= (char*)stackBase && ((char*)&i) < (char*)stackEnd))
953  return *mainAllocatorPtr;
954 
955  // chop off the last 22 bits of i to get the address of this thread's allocator... we chop off
956  // 22 bits
957  // because the size of the allocated region is 2^22 bytes
958  size_t temp = (size_t)&i;
959  return *((Allocator*)((temp >> 22) << 22));
960 }
961 }
962 
963 #endif
void defaultFreeRAM(bool isContained, void *here, std::vector< InactiveAllocationBlock > &allInactives, AllocatorState &myState)
Definition: Allocator.cc:118
std::string printCurrentBlock()
Definition: Allocator.cc:876
void * getRAM(size_t howMuch, AllocatorState &myState)
Definition: Allocator.cc:395
void * getRAM(size_t howMuch, AllocatorState &myState)
Definition: Allocator.cc:357
void * stackBase
AllocatorState temporarilyUseBlockForAllocations(void *putMeHere, size_t numBytesAvailable)
Definition: Allocator.cc:793
void * stackEnd
void setPolicy(AllocatorPolicy policy)
Definition: Allocator.cc:536
AllocatorPolicy
Definition: Allocator.h:130
bool operator<(const InactiveAllocationBlock &in, const void *compToMe)
Definition: Allocator.cc:54
void freeRAM(bool isContained, void *here, std::vector< InactiveAllocationBlock > &allInactives, AllocatorState &myState)
Definition: Allocator.cc:339
Allocator & getAllocator()
Definition: Allocator.cc:943
void setupBlock(void *where, size_t numBytesIn, bool throwExceptionOnFail)
Definition: Allocator.cc:712
#define GET_CHUNK_SIZE(ofMe)
Definition: Allocator.cc:107
void restoreAllocationBlock(AllocatorState &restoreMe)
Definition: Allocator.cc:846
void * getRAM(size_t howMuch, AllocatorState &myState)
Definition: Allocator.cc:429
NotEnoughSpace myException
std::vector< std::vector< void * > > chunks
Definition: Allocator.h:126
bool contains(void *whereIn)
Definition: Allocator.cc:543
bool isManaged(void *here)
Definition: Allocator.cc:577
void * getAllocationBlock(Handle< ObjType > &forMe)
Definition: Allocator.cc:760
#define CHAR_PTR(c)
Definition: Allocator.cc:33
LambdaTree< bool > operator==(LambdaTree< LeftType > lhs, LambdaTree< RightType > rhs)
size_t getBytesAvailableInCurrentAllocatorBlock()
Definition: Allocator.cc:661
#define OFFSET_TO_OBJECT
Definition: Allocator.cc:104
#define CHUNK_HEADER_SIZE
Definition: Allocator.cc:108
void * getRAM(size_t howMuch)
Definition: Allocator.cc:557
unsigned getNumObjectsInCurrentAllocatorBlock()
Definition: Allocator.cc:676
#define HEADER_SIZE
Definition: Allocator.cc:106
#define PDB_COUT
Definition: PDBDebug.h:31
unsigned getNumObjectsInAllocatorBlock(void *forMe)
void setupUserSuppliedBlock(void *where, size_t numBytesIn, bool throwExceptionOnFail)
Definition: Allocator.cc:653
void freeRAM(bool isContained, void *here, std::vector< InactiveAllocationBlock > &allInactives, AllocatorState &myState)
Definition: Allocator.cc:415
void freeRAM(bool isContained, void *here, std::vector< InactiveAllocationBlock > &allInactives, AllocatorState &myState)
Definition: Allocator.cc:376
void * defaultGetRAM(size_t howMuch, AllocatorState &myState)
Definition: Allocator.cc:196
void * fastGetRAM(size_t howMuch, AllocatorState &myState)
Definition: Allocator.cc:285
unsigned getNumObjectsInCurrentAllocatorBlock()
void emptyOutBlock(void *here)
Definition: Allocator.cc:596
#define ALLOCATOR_REF_COUNT
Definition: Allocator.cc:102
void freeRAM(void *here)
Definition: Allocator.cc:632
unsigned getNumObjectsInAllocatorBlock(void *forMe)
Definition: Allocator.cc:681
#define LAST_USED
Definition: Allocator.cc:103
Allocator * mainAllocatorPtr
#define OFFSET_TO_OBJECT_RELATIVE(fromWhere)
Definition: Allocator.cc:105
unsigned getNumObjectsInHomeAllocatorBlock(Handle< ObjType > &forMe)
Definition: Allocator.cc:704
bool operator>(const InactiveAllocationBlock &in, const void *compToMe)
Definition: Allocator.cc:64
std::string printInactiveBlocks()
Definition: Allocator.cc:888