Generated on Tue Apr 18 10:22:06 2017 for Gecode by doxygen 1.6.3

memory-manager.hpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Christian Schulte <schulte@gecode.org>
00005  *
00006  *  Contributing authors:
00007  *     Guido Tack <tack@gecode.org>
00008  *
00009  *  Bugfixes provided by:
00010  *     Zandra Norman
00011  *
00012  *  Copyright:
00013  *     Christian Schulte, 2002
00014  *     Guido Tack, 2004
00015  *
00016  *  Last modified:
00017  *     $Date: 2016-04-19 17:19:45 +0200 (Tue, 19 Apr 2016) $ by $Author: schulte $
00018  *     $Revision: 14967 $
00019  *
00020  *  This file is part of Gecode, the generic constraint
00021  *  development environment:
00022  *     http://www.gecode.org
00023  *
00024  *  Permission is hereby granted, free of charge, to any person obtaining
00025  *  a copy of this software and associated documentation files (the
00026  *  "Software"), to deal in the Software without restriction, including
00027  *  without limitation the rights to use, copy, modify, merge, publish,
00028  *  distribute, sublicense, and/or sell copies of the Software, and to
00029  *  permit persons to whom the Software is furnished to do so, subject to
00030  *  the following conditions:
00031  *
00032  *  The above copyright notice and this permission notice shall be
00033  *  included in all copies or substantial portions of the Software.
00034  *
00035  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00036  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00037  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00038  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00039  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00040  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00041  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00042  *
00043  */
00044 
00045 namespace Gecode {
00046 
00048   class MemoryChunk {
00049   public:
00051     MemoryChunk* next;
00053     size_t size;
00054   };
00055 
00057   class HeapChunk : public MemoryChunk {
00058   public:
00060     double area[1];
00061   };
00062 
00063   class Region;
00064 
00066   class SharedMemory {
00067     friend class Region;
00068   private:
00070     unsigned int use_cnt;
00072     struct {
00074       size_t free;
00076       double area[MemoryConfig::region_area_size / sizeof(double)];
00077     } region;
00079     struct {
00081       unsigned int n_hc;
00083       HeapChunk* hc;
00084     } heap;
00085   public:
00087     SharedMemory(void);
00089     void flush(void);
00091     ~SharedMemory(void);
00093     //@
00095     bool region_alloc(size_t s, void*& p);
00097 
00098     //@
00100     HeapChunk* heap_alloc(size_t s, size_t l);
00102     void heap_free(HeapChunk* hc);
00104 
00105     SharedMemory* copy(bool share);
00107     bool release(void);
00109     static void* operator new(size_t s);
00111     static void  operator delete(void* p);
00112   };
00113 
00114 
00123   class FreeList {
00124   protected:
00126     FreeList* _next;
00127   public:
00129     FreeList(void);
00131     FreeList(FreeList* n);
00133     FreeList* next(void) const;
00135     FreeList** nextRef(void);
00137     void next(FreeList* n);
00138   };
00139 
00141   class MemoryManager {
00142   public:
00144     MemoryManager(SharedMemory* sm);
00146     MemoryManager(SharedMemory* sm, MemoryManager& mm, size_t s_sub);
00148     void release(SharedMemory* sm);
00149 
00150   private:
00151     size_t     cur_hcsz;  
00152     HeapChunk* cur_hc;    
00153     size_t     requested; 
00154 
00155     char*  start; 
00156     size_t lsz;   
00157 
00159     GECODE_KERNEL_EXPORT
00160     void alloc_refill(SharedMemory* sm, size_t s);
00162     void alloc_fill(SharedMemory* sm, size_t s, bool first);
00163 
00164   public:
00166     void* alloc(SharedMemory* sm, size_t s);
00168     void* subscriptions(void) const;
00169 
00170   private:
00172     FreeList* fl[MemoryConfig::fl_size_max-MemoryConfig::fl_size_min+1];
00174     template<size_t> void fl_refill(SharedMemory* sm);
00176     static size_t sz2i(size_t);
00178     static size_t i2sz(size_t);
00179 
00180   public:
00182     template<size_t s>
00183     void* fl_alloc(SharedMemory* sm);
00185     template<size_t> void  fl_dispose(FreeList* f, FreeList* l);
00186 
00187   private:
00189     MemoryChunk* slack;
00190   public:
00192     void reuse(void* p, size_t s);
00193   };
00194 
00195 
00196   /*
00197    * Shared memory area
00198    *
00199    */
00200 
00201   forceinline void*
00202   SharedMemory::operator new(size_t s) {
00203     return Gecode::heap.ralloc(s);
00204   }
00205   forceinline void
00206   SharedMemory::operator delete(void* p) {
00207     Gecode::heap.rfree(p);
00208   }
00209   forceinline
00210   SharedMemory::SharedMemory(void)
00211     : use_cnt(1) {
00212     region.free = MemoryConfig::region_area_size;
00213     heap.n_hc = 0;
00214     heap.hc = NULL;
00215   }
00216   forceinline void
00217   SharedMemory::flush(void) {
00218     heap.n_hc = 0;
00219     while (heap.hc != NULL) {
00220       HeapChunk* hc = heap.hc;
00221       heap.hc = static_cast<HeapChunk*>(hc->next);
00222       Gecode::heap.rfree(hc);
00223     }
00224   }
00225   forceinline
00226   SharedMemory::~SharedMemory(void) {
00227     flush();
00228   }
00229   forceinline SharedMemory*
00230   SharedMemory::copy(bool share) {
00231     if (share) {
00232       use_cnt++;
00233       return this;
00234     } else {
00235       return new SharedMemory();
00236     }
00237   }
00238   forceinline bool
00239   SharedMemory::release(void) {
00240     return --use_cnt == 0;
00241   }
00242   forceinline bool
00243   SharedMemory::region_alloc(size_t s, void*& p) {
00244     MemoryConfig::align(s);
00245     if (s > region.free)
00246       return false;
00247     region.free -= s;
00248     p = ptr_cast<char*>(&region.area[0]) + region.free;
00249     return true;
00250   }
00251   forceinline HeapChunk*
00252   SharedMemory::heap_alloc(size_t s, size_t l) {
00253     while ((heap.hc != NULL) && (heap.hc->size < l)) {
00254       heap.n_hc--;
00255       HeapChunk* hc = heap.hc;
00256       heap.hc = static_cast<HeapChunk*>(hc->next);
00257       Gecode::heap.rfree(hc);
00258     }
00259     if (heap.hc == NULL) {
00260       assert(heap.n_hc == 0);
00261       HeapChunk* hc = static_cast<HeapChunk*>(Gecode::heap.ralloc(s));
00262       hc->size = s;
00263       return hc;
00264     } else {
00265       heap.n_hc--;
00266       HeapChunk* hc = heap.hc;
00267       heap.hc = static_cast<HeapChunk*>(hc->next);
00268       return hc;
00269     }
00270   }
00271   forceinline void
00272   SharedMemory::heap_free(HeapChunk* hc) {
00273     if (heap.n_hc == MemoryConfig::n_hc_cache) {
00274       Gecode::heap.rfree(hc);
00275     } else {
00276       heap.n_hc++;
00277       hc->next = heap.hc; heap.hc = hc;
00278     }
00279   }
00280 
00281 
00282   /*
00283    * Freelists
00284    *
00285    */
00286 
00287   forceinline
00288   FreeList::FreeList(void) {}
00289 
00290   forceinline
00291   FreeList::FreeList(FreeList* n)
00292     : _next(n) {}
00293 
00294   forceinline FreeList*
00295   FreeList::next(void) const {
00296     return _next;
00297   }
00298 
00299   forceinline FreeList**
00300   FreeList::nextRef(void) {
00301     return &_next;
00302   }
00303 
00304   forceinline void
00305   FreeList::next(FreeList* n) {
00306     _next = n;
00307   }
00308 
00309   forceinline size_t
00310   MemoryManager::sz2i(size_t s) {
00311     assert(s >= (MemoryConfig::fl_size_min << MemoryConfig::fl_unit_size));
00312     assert(s <= (MemoryConfig::fl_size_max << MemoryConfig::fl_unit_size));
00313     return (s >> MemoryConfig::fl_unit_size) - MemoryConfig::fl_size_min;
00314   }
00315 
00316   forceinline size_t
00317   MemoryManager::i2sz(size_t i) {
00318     return (i + MemoryConfig::fl_size_min) << MemoryConfig::fl_unit_size;
00319   }
00320 
00321 
00322   /*
00323    * The active memory manager
00324    *
00325    */
00326 
00327   forceinline void*
00328   MemoryManager::alloc(SharedMemory* sm, size_t sz) {
00329     assert(sz > 0);
00330     // Perform alignment
00331     MemoryConfig::align(sz);
00332     // Check whether sufficient memory left
00333     if (sz > lsz)
00334       alloc_refill(sm,sz);
00335     lsz -= sz;
00336     return start + lsz;
00337   }
00338 
00339   forceinline void*
00340   MemoryManager::subscriptions(void) const {
00341     return &cur_hc->area[0];
00342   }
00343 
00344   forceinline void
00345   MemoryManager::alloc_fill(SharedMemory* sm, size_t sz, bool first) {
00346     // Adjust current heap chunk size
00347     if (((requested > MemoryConfig::hcsz_inc_ratio*cur_hcsz) ||
00348          (sz > cur_hcsz)) &&
00349         (cur_hcsz < MemoryConfig::hcsz_max) &&
00350         !first) {
00351       cur_hcsz <<= 1;
00352     }
00353     // Increment the size that it caters for the initial overhead
00354     size_t overhead = sizeof(HeapChunk) - sizeof(double);
00355     sz += overhead;
00356     // Round size to next multiple of current heap chunk size
00357     size_t allocate = ((sz > cur_hcsz) ?
00358                        (((size_t) (sz / cur_hcsz)) + 1) * cur_hcsz : cur_hcsz);
00359     // Request a chunk of preferably size allocate, but at least size sz
00360     HeapChunk* hc = sm->heap_alloc(allocate,sz);
00361     start = ptr_cast<char*>(&hc->area[0]);
00362     lsz   = hc->size - overhead;
00363     // Link heap chunk, where the first heap chunk is kept in place
00364     if (first) {
00365       requested = hc->size;
00366       hc->next = NULL; cur_hc = hc;
00367     } else {
00368       requested += hc->size;
00369       hc->next = cur_hc->next; cur_hc->next = hc;
00370     }
00371 #ifdef GECODE_MEMORY_CHECK
00372     for (char* c = start; c < (start+lsz); c++)
00373       *c = 0;
00374 #endif
00375   }
00376 
00377   forceinline
00378   MemoryManager::MemoryManager(SharedMemory* sm)
00379     : cur_hcsz(MemoryConfig::hcsz_min), requested(0), slack(NULL) {
00380     alloc_fill(sm,cur_hcsz,true);
00381     for (size_t i = MemoryConfig::fl_size_max-MemoryConfig::fl_size_min+1;
00382          i--; )
00383       fl[i] = NULL;
00384   }
00385 
00386   forceinline
00387   MemoryManager::MemoryManager(SharedMemory* sm, MemoryManager& mm,
00388                                size_t s_sub)
00389     : cur_hcsz(mm.cur_hcsz), requested(0), slack(NULL) {
00390     MemoryConfig::align(s_sub);
00391     if ((mm.requested < MemoryConfig::hcsz_dec_ratio*mm.cur_hcsz) &&
00392         (cur_hcsz > MemoryConfig::hcsz_min) &&
00393         (s_sub*2 < cur_hcsz))
00394       cur_hcsz >>= 1;
00395     alloc_fill(sm,cur_hcsz+s_sub,true);
00396     // Skip the memory area at the beginning for subscriptions
00397     lsz   -= s_sub;
00398     start += s_sub;
00399     for (size_t i = MemoryConfig::fl_size_max-MemoryConfig::fl_size_min+1;
00400          i--; )
00401       fl[i] = NULL;
00402   }
00403 
00404   forceinline void
00405   MemoryManager::release(SharedMemory* sm) {
00406     // Release all allocated heap chunks
00407     HeapChunk* hc = cur_hc;
00408     do {
00409       HeapChunk* t = hc; hc = static_cast<HeapChunk*>(hc->next);
00410       sm->heap_free(t);
00411     } while (hc != NULL);
00412   }
00413 
00414 
00415 
00416   /*
00417    * Slack memory management
00418    *
00419    */
00420   forceinline void
00421   MemoryManager::reuse(void* p, size_t s) {
00422 #ifdef GECODE_MEMORY_CHECK
00423     {
00424       char* c = static_cast<char*>(p);
00425       char* e = c + s;
00426       while (c < e) {
00427         *c = 0; c++;
00428       }
00429     }
00430 #endif
00431     if (s < (MemoryConfig::fl_size_min<<MemoryConfig::fl_unit_size))
00432       return;
00433     if (s > (MemoryConfig::fl_size_max<<MemoryConfig::fl_unit_size)) {
00434       MemoryChunk* rc = static_cast<MemoryChunk*>(p);
00435       rc->next = slack;
00436       rc->size = s;
00437       slack = rc;
00438     } else {
00439       size_t i = sz2i(s);
00440       FreeList* f = static_cast<FreeList*>(p);
00441       f->next(fl[i]); fl[i]=f;
00442     }
00443   }
00444 
00445 
00446   /*
00447    * Freelist management
00448    *
00449    */
00450 
00451   template<size_t s>
00452   forceinline void*
00453   MemoryManager::fl_alloc(SharedMemory* sm) {
00454     size_t i = sz2i(s);
00455     FreeList* f = fl[i];
00456     if (f == NULL) {
00457       fl_refill<s>(sm); f = fl[i];
00458     }
00459     FreeList* n = f->next();
00460     fl[i] = n;
00461     return f;
00462   }
00463 
00464   template<size_t s>
00465   forceinline void
00466   MemoryManager::fl_dispose(FreeList* f, FreeList* l) {
00467     size_t i = sz2i(s);
00468 #ifdef GECODE_AUDIT
00469     FreeList* cur = f;
00470     while (cur != l) {
00471       assert(cur->next());
00472       cur = cur->next();
00473     }
00474 #endif
00475     l->next(fl[i]); fl[i] = f;
00476   }
00477 
00478   template<size_t sz>
00479   void
00480   MemoryManager::fl_refill(SharedMemory* sm) {
00481     // Try to acquire memory from slack
00482     if (slack != NULL) {
00483       MemoryChunk* m = slack;
00484       slack = NULL;
00485       do {
00486         char*  block = ptr_cast<char*>(m);
00487         size_t s     = m->size;
00488         assert(s >= sz);
00489         m = m->next;
00490         fl[sz2i(sz)] = ptr_cast<FreeList*>(block);
00491         while (s >= 2*sz) {
00492           ptr_cast<FreeList*>(block)->next(ptr_cast<FreeList*>(block+sz));
00493           block += sz;
00494           s     -= sz;
00495         }
00496         ptr_cast<FreeList*>(block)->next(NULL);
00497       } while (m != NULL);
00498     } else {
00499       char* block = static_cast<char*>(alloc(sm,MemoryConfig::fl_refill*sz));
00500       fl[sz2i(sz)] = ptr_cast<FreeList*>(block);
00501       int i = MemoryConfig::fl_refill-2;
00502       do {
00503         ptr_cast<FreeList*>(block+i*sz)->next(ptr_cast<FreeList*>(block+(i+1)*sz));
00504       } while (--i >= 0);
00505       ptr_cast<FreeList*>(block+
00506                           (MemoryConfig::fl_refill-1)*sz)->next
00507         (ptr_cast<FreeList*>(NULL));
00508     }
00509   }
00510 
00511 }
00512 
00513 // STATISTICS: kernel-memory