00001
00030 #ifndef GALOIS_RUNTIME_MM_MEM_H
00031 #define GALOIS_RUNTIME_MM_MEM_H
00032
00033 #include "Galois/Runtime/SimpleLock.h"
00034 #include "Galois/Runtime/PerCPU.h"
00035 #include <boost/utility.hpp>
00036 #include <memory.h>
00037
00038
00039 #ifndef USEMALLOC
00040 #include <map>
00041 #endif
00042
00043 namespace GaloisRuntime {
00044 namespace MM {
00045
00047 class mmapWrapper {
00048 static void* _alloc();
00049 static void _free(void*);
00050 public:
00051 enum {AllocSize = 2*1024*1024,
00052 Alignment = 4*1024,
00053 AutoFree = 1};
00054
00055 mmapWrapper();
00056
00057 void* allocate(unsigned int size) {
00058 assert(size % AllocSize == 0);
00059 return _alloc();
00060 }
00061
00062 void deallocate(void* ptr) {
00063 _free(ptr);
00064 }
00065 };
00066
00067
00069 template<class LocalHeap>
00070 class ThreadAwarePrivateHeap {
00071 PerCPU<LocalHeap> heaps;
00072
00073 public:
00074 enum { AllocSize = LocalHeap::AllocSize };
00075
00076 ThreadAwarePrivateHeap() {}
00077
00078 inline void* allocate(unsigned int size) {
00079 return heaps.get().allocate(size);
00080 }
00081
00082 inline void deallocate(void* ptr) {
00083 heaps.get().deallocate(ptr);
00084 }
00085 };
00086
00088 template<class RealHeap>
00089 class LockedHeap : public RealHeap {
00090 SimpleLock<int, true> lock;
00091 public:
00092 enum { AllocSize = RealHeap::AllocSize };
00093
00094 inline void* allocate(unsigned int size) {
00095 lock.lock();
00096 void* retval = RealHeap::allocate(size);
00097 lock.unlock();
00098 return retval;
00099 }
00100
00101 inline void deallocate(void* ptr) {
00102 lock.lock();
00103 RealHeap::deallocate(ptr);
00104 lock.unlock();
00105 }
00106 };
00107
00108 template<typename SourceHeap>
00109 class ZeroOut : public SourceHeap {
00110 public:
00111 enum { AllocSize = SourceHeap::AllocSize } ;
00112 inline void* allocate(unsigned int size) {
00113 void* retval = SourceHeap::allocate(size);
00114 memset(retval, 0, size);
00115 return retval;
00116 }
00117
00118 inline void deallocate(void* ptr) {
00119 SourceHeap::deallocate(ptr);
00120 }
00121 };
00122
00124 template<typename Header, typename SourceHeap>
00125 class AddHeader : public SourceHeap {
00126 enum { offset = (sizeof(Header) + (sizeof(double) - 1)) & ~(sizeof(double) - 1) };
00127
00128 public:
00129 inline void* allocate(unsigned int size) {
00130
00131 void* ptr = SourceHeap::allocate(size + offset);
00132
00133 return (char*)ptr + offset;
00134 }
00135
00136 inline void deallocate(void* ptr) {
00137 SourceHeap::deallocate(getHeader(ptr));
00138 }
00139
00140 inline static Header* getHeader(void* ptr) {
00141 return (Header*)((char*)ptr - offset);
00142 }
00143 };
00144
00146 template<class SourceHeap>
00147 class OwnerTaggedHeap : public AddHeader<void*, SourceHeap> {
00148 typedef AddHeader<OwnerTaggedHeap*, SourceHeap> Src;
00149 public:
00150 inline void* allocate(unsigned int size) {
00151 void* retval = Src::allocate(size);
00152 *(Src::getHeader(retval)) = this;
00153 return retval;
00154 }
00155
00156 inline void deallocate(void* ptr) {
00157 assert(*(Src::getHeader(ptr)) == this);
00158 Src::deallocate(ptr);
00159 }
00160
00161 inline static OwnerTaggedHeap* owner(void* ptr) {
00162 return *(OwnerTaggedHeap**)Src::getHeader(ptr);
00163 }
00164 };
00165
00167 template<class SourceHeap>
00168 class FreeListHeap : public SourceHeap {
00169 struct FreeNode {
00170 FreeNode* next;
00171 };
00172 FreeNode* head;
00173
00174 public:
00175 enum { AllocSize = SourceHeap::AllocSize };
00176
00177 void clear() {
00178 while (head) {
00179 FreeNode* N = head;
00180 head = N->next;
00181 SourceHeap::deallocate(N);
00182 }
00183 }
00184
00185 FreeListHeap() : head(0) {}
00186 ~FreeListHeap() {
00187 clear();
00188 }
00189
00190 inline void* allocate(unsigned int size) {
00191 if (head) {
00192 void* ptr = head;
00193 head = head->next;
00194 return ptr;
00195 }
00196 return SourceHeap::allocate(size);
00197 }
00198
00199 inline void deallocate(void* ptr) {
00200 if (!ptr) return;
00201 assert((uintptr_t)ptr > 0x100);
00202 FreeNode* NH = (FreeNode*)ptr;
00203 NH->next = head;
00204 head = NH;
00205 }
00206
00207 };
00208
00210 template<class SourceHeap>
00211 class SelfLockFreeListHeap : public SourceHeap {
00212 struct FreeNode {
00213 FreeNode* next;
00214 };
00215 FreeNode* head;
00216
00217 public:
00218 enum { AllocSize = SourceHeap::AllocSize };
00219
00220 void clear() {
00221 FreeNode* h = 0;
00222 do {
00223 h = head;
00224 } while (!__sync_bool_compare_and_swap(&head, h, 0));
00225 while (h) {
00226 FreeNode* N = h;
00227 h = N->next;
00228 SourceHeap::deallocate(N);
00229 }
00230 }
00231
00232 SelfLockFreeListHeap() : head(0) {}
00233 ~SelfLockFreeListHeap() {
00234 clear();
00235 }
00236
00237 inline void* allocate(unsigned int size) {
00238 static SimpleLock<int, true> lock;
00239
00240 lock.lock();
00241 FreeNode* OH = 0;
00242 FreeNode* NH = 0;
00243 do {
00244 OH = head;
00245 if (!OH) {
00246 lock.unlock();
00247 return SourceHeap::allocate(size);
00248 }
00249 NH = OH->next;
00250 } while (!__sync_bool_compare_and_swap(&head, OH, NH));
00251 lock.unlock();
00252 assert(OH);
00253 return (void*)OH;
00254 }
00255
00256 inline void deallocate(void* ptr) {
00257 if (!ptr) return;
00258 FreeNode* OH;
00259 FreeNode* NH;
00260 do {
00261 OH = head;
00262 NH = (FreeNode*)ptr;
00263 NH->next = OH;
00264 } while (!__sync_bool_compare_and_swap(&head, OH, NH));
00265 }
00266
00267 };
00268
00269 template<unsigned ElemSize, typename SourceHeap>
00270 class BlockAlloc : public SourceHeap {
00271
00272 struct TyEq {
00273 double data[((ElemSize + sizeof(double) - 1) & ~(sizeof(double) - 1))/sizeof(double)];
00274 };
00275
00276 struct Block_basic {
00277 union {
00278 Block_basic* next;
00279 double dummy;
00280 };
00281 TyEq data[1];
00282 };
00283
00284 enum {BytesLeft = (SourceHeap::AllocSize - sizeof(Block_basic)),
00285 BytesLeftR = BytesLeft & ~(sizeof(double) - 1),
00286 FitLeft = BytesLeftR / sizeof(TyEq[1]),
00287 TotalFit = FitLeft + 1
00288 };
00289
00290 struct Block {
00291 union {
00292 Block* next;
00293 double dummy;
00294 };
00295 TyEq data[TotalFit];
00296 };
00297
00298 Block* head;
00299 int headIndex;
00300
00301 void refill() {
00302 void* P = SourceHeap::allocate(SourceHeap::AllocSize);
00303 Block* BP = (Block*)P;
00304 BP->next = head;
00305 head = BP;
00306 headIndex = 0;
00307 }
00308 public:
00309 enum { AllocSize = ElemSize };
00310
00311 void clear() {
00312 while(head) {
00313 Block* B = head;
00314 head = B->next;
00315 SourceHeap::deallocate(B);
00316 }
00317 }
00318
00319 BlockAlloc() :SourceHeap(), head(0), headIndex(0) {
00320
00321 assert(sizeof(Block) <= SourceHeap::AllocSize);
00322 }
00323
00324 ~BlockAlloc() {
00325 clear();
00326 }
00327
00328 inline void* allocate(unsigned int size) {
00329 assert(size == ElemSize);
00330 if (!head || headIndex == TotalFit)
00331 refill();
00332 return &head->data[headIndex++];
00333 }
00334
00335 inline void deallocate(void* ptr) {}
00336
00337 };
00338
00340 template<typename SourceHeap>
00341 class SimpleBumpPtr : public SourceHeap {
00342
00343 struct Block {
00344 union {
00345 Block* next;
00346 double dummy;
00347 };
00348 };
00349
00350 Block* head;
00351 int offset;
00352
00353 void refill() {
00354 void* P = SourceHeap::allocate(SourceHeap::AllocSize);
00355 Block* BP = (Block*)P;
00356 BP->next = head;
00357 head = BP;
00358 offset = sizeof(Block);
00359 }
00360 public:
00361 enum { AllocSize = 0 };
00362
00363 SimpleBumpPtr() :SourceHeap(), head(0), offset(0) {}
00364 ~SimpleBumpPtr() {
00365 clear();
00366 }
00367
00368 void clear() {
00369 while(head) {
00370 Block* B = head;
00371 head = B->next;
00372 SourceHeap::deallocate(B);
00373 }
00374 }
00375
00376 inline void* allocate(unsigned int size) {
00377
00378 size = (size + sizeof(double) - 1) & ~(sizeof(double) - 1);
00379
00380 if (!head || offset + size > SourceHeap::AllocSize)
00381 refill();
00382
00383 if (offset + size > SourceHeap::AllocSize) {
00384 assert(0 && "Too large");
00385 return 0;
00386 }
00387 char* retval = (char*)head;
00388 retval += offset;
00389 offset += size;
00390 return retval;
00391 }
00392
00393 inline void deallocate(void* ptr) {}
00394
00395 };
00396
00399 class SystemBaseAlloc {
00400 static SelfLockFreeListHeap<mmapWrapper> Source;
00401 public:
00402 enum { AllocSize = SelfLockFreeListHeap<mmapWrapper>::AllocSize };
00403
00404 SystemBaseAlloc();
00405 ~SystemBaseAlloc();
00406
00407 inline void* allocate(unsigned int size) {
00408 return Source.allocate(size);
00409 }
00410
00411 inline void deallocate(void* ptr) {
00412 Source.deallocate(ptr);
00413 }
00414 };
00415
00416 class MallocWrapper {
00417 public:
00418 inline void* allocate(unsigned int size) {
00419 return malloc(size);
00420 }
00421
00422 inline void deallocate(void* ptr) {
00423 free(ptr);
00424 }
00425 };
00426
00427 class SizedAllocatorFactory: private boost::noncopyable {
00428 public:
00429 #ifdef USEMALLOC
00430 typedef MallocWrapper SizedAlloc;
00431
00432 SizedAlloc* getAllocatorForSize(unsigned int) {
00433 return &MasterAlloc;
00434 }
00435 #else
00436 typedef ThreadAwarePrivateHeap<
00437 FreeListHeap<SimpleBumpPtr<SystemBaseAlloc> > > SizedAlloc;
00438 SizedAlloc* getAllocatorForSize(unsigned int);
00439 #endif
00440
00441 static SizedAllocatorFactory* getInstance() {
00442 SizedAllocatorFactory* f = instance.getValue();
00443 if (f)
00444 return f;
00445
00446 instance.lock();
00447 f = instance.getValue();
00448 if (f) {
00449 instance.unlock();
00450 } else {
00451 f = new SizedAllocatorFactory;
00452 instance.unlock_and_set(f);
00453 }
00454 return f;
00455 }
00456
00457 private:
00458 static PtrLock<SizedAllocatorFactory*, true> instance;
00459 #ifdef USEMALLOC
00460 MallocWrapper MasterAlloc;
00461 #else
00462 typedef std::map<unsigned int, SizedAlloc*> AllocatorsTy;
00463 AllocatorsTy allocators;
00464 SimpleLock<int, true> lock;
00465 ~SizedAllocatorFactory();
00466 #endif
00467 };
00468
00469 class FixedSizeAllocator {
00470 SizedAllocatorFactory::SizedAlloc* alloc;
00471 public:
00472 FixedSizeAllocator(unsigned int sz) {
00473 alloc = SizedAllocatorFactory::getInstance()->getAllocatorForSize(sz);
00474 }
00475
00476 inline void* allocate(unsigned int sz) {
00477 return alloc->allocate(sz);
00478 }
00479
00480 inline void deallocate(void* ptr) {
00481 alloc->deallocate(ptr);
00482 }
00483
00484 inline bool operator!=(const FixedSizeAllocator& rhs) const {
00485 return alloc != rhs.alloc;
00486 }
00487 };
00488
00490
00492
00493
00494 template<typename Ty>
00495 class FSBGaloisAllocator
00496 {
00497 FixedSizeAllocator Alloc;
00498
00499 public:
00500 typedef size_t size_type;
00501 typedef ptrdiff_t difference_type;
00502 typedef Ty *pointer;
00503 typedef const Ty *const_pointer;
00504 typedef Ty& reference;
00505 typedef const Ty& const_reference;
00506 typedef Ty value_type;
00507
00508 pointer address(reference val) const { return &val; }
00509 const_pointer address(const_reference val) const { return &val; }
00510
00511 template<class Other>
00512 struct rebind
00513 {
00514 typedef FSBGaloisAllocator<Other> other;
00515 };
00516
00517 template <class U>
00518 FSBGaloisAllocator ( const FSBGaloisAllocator<U>& ) throw()
00519 :Alloc(sizeof(Ty))
00520 {}
00521
00522 FSBGaloisAllocator() throw()
00523 :Alloc(sizeof(Ty))
00524 {}
00525
00526 pointer allocate(int x)
00527 {
00528 assert(x == 1);
00529 return static_cast<pointer>(Alloc.allocate(sizeof(Ty)));
00530 }
00531
00532 void deallocate(pointer ptr, size_type)
00533 {
00534 Alloc.deallocate(ptr);
00535 }
00536
00537 template<typename TyC>
00538 void construct(pointer ptr, const TyC& val)
00539 {
00540 new ((void *)ptr) Ty(val);
00541 }
00542
00543 void destroy(pointer ptr)
00544 {
00545 ptr->Ty::~Ty();
00546 }
00547
00548 size_type max_size() const throw() { return 1; }
00549
00550 bool operator!=(const FSBGaloisAllocator& rhs) const {
00551 return Alloc != rhs.Alloc;
00552 }
00553 };
00554
00555
00556 template<typename Ty, typename AllocTy>
00557 class ExternRefGaloisAllocator
00558 {
00559 public:
00560 AllocTy* Alloc;
00561
00562 typedef size_t size_type;
00563 typedef ptrdiff_t difference_type;
00564 typedef Ty *pointer;
00565 typedef const Ty *const_pointer;
00566 typedef Ty& reference;
00567 typedef const Ty& const_reference;
00568 typedef Ty value_type;
00569
00570 pointer address(reference val) const { return &val; }
00571 const_pointer address(const_reference val) const { return &val; }
00572
00573 template<class Other>
00574 struct rebind
00575 {
00576 typedef ExternRefGaloisAllocator<Other, AllocTy> other;
00577 };
00578
00579 template <class U>
00580 ExternRefGaloisAllocator ( const ExternRefGaloisAllocator<U,AllocTy>& rhs)
00581 throw() {
00582 Alloc = rhs.Alloc;
00583 }
00584
00585 explicit ExternRefGaloisAllocator(AllocTy* a) throw()
00586 :Alloc(a)
00587 {}
00588
00589 pointer allocate(int x)
00590 {
00591 return static_cast<pointer>(Alloc->allocate(x*sizeof(Ty)));
00592 }
00593
00594 void deallocate(pointer ptr, size_type x)
00595 {
00596 Alloc->deallocate(ptr);
00597 }
00598
00599 template<typename TyC>
00600 void construct(pointer ptr, const TyC& val)
00601 {
00602 new ((void *)ptr) Ty(val);
00603 }
00604
00605 void destroy(pointer ptr)
00606 {
00607 ptr->Ty::~Ty();
00608 }
00609
00610 size_type max_size() const throw() { return 1024*1024; }
00611 };
00612
00613 }
00614 }
00615
00616 #endif