sc_mempool.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002 
00003   The following code is derived, directly or indirectly, from the SystemC
00004   source code Copyright (c) 1996-2006 by all Contributors.
00005   All Rights reserved.
00006 
00007   The contents of this file are subject to the restrictions and limitations
00008   set forth in the SystemC Open Source License Version 2.4 (the "License");
00009   You may not use this file except in compliance with such restrictions and
00010   limitations. You may obtain instructions on how to receive a copy of the
00011   License at http://www.systemc.org/. Software distributed by Contributors
00012   under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
00013   ANY KIND, either express or implied. See the License for the specific
00014   language governing rights and limitations under the License.
00015 
00016  *****************************************************************************/
00017 
00018 /*****************************************************************************
00019 
00020   sc_mempool.cpp - Memory pools for small objects.
00021 
00022   Original Author: Stan Y. Liao, Synopsys, Inc.
00023 
00024  *****************************************************************************/
00025 
00026 /*****************************************************************************
00027 
00028   MODIFICATION LOG - modifiers, enter your name, affiliation, date and
00029   changes you are making here.
00030 
00031       Name, Affiliation, Date:
00032   Description of Modification:
00033 
00034  *****************************************************************************/
00035 // $Log: sc_mempool.cpp,v $
00036 // Revision 1.1.1.1  2006/12/15 20:31:39  acg
00037 // SystemC 2.2
00038 //
00039 // Revision 1.3  2006/01/13 18:53:10  acg
00040 // Andy Goodrich: Added $Log command so that CVS comments are reproduced in
00041 // the source.
00042 //
00043 
00044 
00045 
00046 //  <sc_mempool> is a class that manages the memory for small objects,
00047 //  of sizes <increment>, 2 * <increment>, ..., <num_pools> *
00048 //  <increment>.  When a memory request of <k> bytes is made through
00049 //  the memory pool, the smallest pool <j> such that <j> * <increment>
00050 //  >= <k> is used.  The default values of <increment> and <num_pools>
00051 //  are 8 and 8, respectively.  Each pool has an allocator, that
00052 //  simply keeps a free list of cells, and allocate new blocks
00053 //  whenever necessary.  We are relying on malloc() to return a
00054 //  properly aligned memory blocks.  Note that the memory blocks
00055 //  allocated by the mempool are never freed.  Thus, if purify is
00056 //  used, we may get MIU (memory-in-use) warnings.  To disable this,
00057 //  set the environment variable SYSTEMC_MEMPOOL_DONT_USE to 1.
00058 
00059 
00060 static const char* dont_use_envstring = "SYSTEMC_MEMPOOL_DONT_USE";
00061 static bool use_default_new = false;
00062 
00063 
00064 #include <stdio.h>
00065 #include <cstdlib>
00066 #include "sysc/utils/sc_mempool.h"
00067 
00068 namespace sc_core {
00069 
00070 //  An allocator is one that handles a particular size.  It keeps a
00071 //  <free_list> from which a cell may be allocated quickly if there
00072 //  is one available.  If no cell is available from <free_list>, then
00073 //  the allocator tries to find whether space is available from the
00074 //  most-recently-allocated block, as pointed to by <next_avail>.  If
00075 //  so, then the cell pointed to by <next_avail> is returned, while
00076 //  <next_avail> is advanced.  If <next_avail> now points beyond
00077 //  the current block, then it's reset to 0.  On the other hand,
00078 //  if <next_avail> was 0 when a request to the block is made, then
00079 //  a new block is allocated by calling system malloc(), and the new
00080 //  block becomes the head of <block_list>.
00081 
00082 
00083 class sc_allocator {
00084     friend class sc_mempool;
00085 
00086 public:
00087     sc_allocator( int blksz, int cellsz );
00088     ~sc_allocator();
00089     void* allocate();
00090     void release(void* p);
00091     
00092     void display_statistics();
00093 
00094 private:
00095     union link {
00096         link* next;
00097         double align;          // alignment required.
00098     };
00099 
00100     int block_size;            // size of each block in bytes,
00101                                // including the link
00102     int cell_size;             // size of each cell in bytes
00103 
00104     char* block_list;
00105     link* free_list;
00106     char* next_avail;
00107 
00108     int total_alloc;
00109     int total_freed;
00110     int free_list_alloc;
00111 };
00112 
00113 sc_allocator::sc_allocator( int blksz, int cellsz )
00114 {
00115     cell_size = cellsz;
00116     block_size = sizeof(link) + (((blksz - 1) / cellsz) + 1) * cellsz;
00117     block_list = 0;
00118     free_list = 0;
00119     next_avail = 0;
00120 
00121     total_alloc = 0;
00122     total_freed = 0;
00123     free_list_alloc = 0;
00124 }
00125 
00126 sc_allocator::~sc_allocator()
00127 {
00128     // Shouldn't free the block_list, since global objects that use
00129     // the memory pool may not have been destroyed yet ...
00130     // Let it leak, let it leak, let it leak ...
00131 }
00132 
00133 void*
00134 sc_allocator::allocate()
00135 {
00136     void* result = 0;
00137     total_alloc++;
00138     if (free_list != 0) {
00139         free_list_alloc++;
00140         result = free_list;
00141         free_list = free_list->next;
00142         return result;
00143     }
00144     else if (next_avail != 0) {
00145         result = next_avail;
00146         next_avail += cell_size;
00147         // next_avail goes beyond the block
00148         if (next_avail >= block_list + block_size)
00149             next_avail = 0;
00150         return result;
00151     }
00152     else {  // (next_avail == 0)
00153         link* new_block = (link*) malloc(block_size);  // need alignment?
00154         new_block->next = (link*) block_list;
00155         block_list = (char*) new_block;
00156         result = (block_list + sizeof(link));
00157         // Assume that the block will hold more than one cell ... why
00158         // wouldn't it?
00159         next_avail = ((char*) result) + cell_size;
00160         return result;
00161     }
00162 }
00163 
00164 void
00165 sc_allocator::release(void* p)
00166 {
00167     total_freed++;
00168     ((link*) p)->next = free_list;
00169     free_list = (link*) p;
00170 }
00171 
00172 void
00173 sc_allocator::display_statistics()
00174 {
00175     int nblocks = 0;
00176     for (link* b = (link*) block_list; b != 0; b = b->next)
00177         nblocks++;
00178     printf("size %3d: %2d block(s), %3d requests (%3d from free list), %3d freed.\n",
00179            cell_size, nblocks, total_alloc, free_list_alloc, total_freed);
00180 }
00181 
00182 
00183 static const int cell_sizes[] = {
00184 /* 0 */   0,
00185 /* 1 */   8,
00186 /* 2 */  16,
00187 /* 3 */  24,
00188 /* 4 */  32,
00189 /* 5 */  48,
00190 /* 6 */  64,
00191 /* 7 */  80,
00192 /* 8 */  96,
00193 /* 9 */ 128
00194 };
00195 
00196 static const int cell_size_to_allocator[] = {
00197 /*  0 */    0,
00198 /*  1 */    1,
00199 /*  2 */    2,
00200 /*  3 */    3,
00201 /*  4 */    4,
00202 /*  5 */    5,
00203 /*  6 */    5,
00204 /*  7 */    6,
00205 /*  8 */    6,
00206 /*  9 */    7,
00207 /* 10 */    7,
00208 /* 11 */    8,
00209 /* 12 */    8,
00210 /* 13 */    9,
00211 /* 14 */    9,
00212 /* 15 */    9,
00213 /* 16 */    9
00214 };
00215 
00216 
00217 class sc_mempool_int {
00218     friend class sc_mempool;
00219 
00220 public:
00221     sc_mempool_int(int blksz, int npools, int incr);
00222     ~sc_mempool_int();
00223     void* do_allocate(std::size_t);
00224     void  do_release(void*, std::size_t);
00225 
00226     void display_statistics();
00227     
00228 private:
00229     sc_allocator** allocators;
00230     int num_pools;
00231     int increment;
00232     int max_size;
00233 };
00234 
00235 
00236 static bool
00237 compute_use_default_new()
00238 {
00239     const char* e = getenv(dont_use_envstring);
00240     return (e != 0) && (atoi(e) != 0);
00241 }
00242 
00243 sc_mempool_int::sc_mempool_int(int blksz, int npools, int incr)
00244 {
00245     use_default_new = compute_use_default_new();
00246     if (! use_default_new) {
00247         num_pools = npools;
00248         increment = incr;
00249         max_size = cell_sizes[sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1];
00250         allocators = new sc_allocator*[npools + 1];
00251         for (int i = 1; i <= npools; ++i)
00252             allocators[i] = new sc_allocator(blksz, cell_sizes[i]);
00253         allocators[0] = allocators[1];
00254     }
00255 }
00256 
00257 sc_mempool_int::~sc_mempool_int()
00258 {
00259     for (int i = 1; i <= num_pools; ++i)
00260         delete allocators[i];
00261     delete[] allocators;
00262 }
00263 
00264 static sc_mempool_int* the_mempool = 0;
00265 
00266 void*
00267 sc_mempool_int::do_allocate(std::size_t sz)
00268 {
00269     int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1];
00270     void* p = allocators[which_allocator]->allocate();
00271     return p;
00272 }
00273 
00274 void
00275 sc_mempool_int::do_release(void* p, std::size_t sz)
00276 {
00277     int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1];
00278     allocators[which_allocator]->release(p);
00279 }
00280 
00281 void
00282 sc_mempool_int::display_statistics()
00283 {
00284     printf("*** Memory Pool Statistics ***\n");
00285     for (int i = 1; i <= num_pools; ++i)
00286         allocators[i]->display_statistics();
00287 }
00288 
00289 /****************************************************************************/
00290 
00291 void*
00292 sc_mempool::allocate(std::size_t sz)
00293 {
00294     if (use_default_new)
00295         return ::operator new(sz);
00296 
00297     if (the_mempool == 0) {
00298         use_default_new = compute_use_default_new();
00299         if (use_default_new)
00300             return ::operator new(sz);
00301 
00302         // Note that the_mempool is never freed.  This is going to cause
00303         // memory leaks when the program exits.
00304         the_mempool = new sc_mempool_int( 1984, sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1, 8 );
00305     }
00306 
00307     if (sz > (unsigned) the_mempool->max_size)
00308         return ::operator new(sz);
00309 
00310     return the_mempool->do_allocate(sz);
00311 }
00312 
00313 void
00314 sc_mempool::release(void* p, std::size_t sz)
00315 {
00316     if (p) {
00317         
00318         if (use_default_new || sz > (unsigned) the_mempool->max_size) {
00319             ::operator delete(p);
00320             return;
00321         }
00322 
00323         the_mempool->do_release(p, sz);
00324     }
00325 }
00326 
00327 void
00328 sc_mempool::display_statistics()
00329 {
00330     if (the_mempool && !use_default_new) {
00331         the_mempool->display_statistics();
00332     } else {
00333         printf("SystemC info: no memory allocation was done through the memory pool.\n");
00334     }
00335 }
00336 
00337 } // namespace sc_core

Generated on Wed Jan 21 15:32:10 2009 for SystemC by  doxygen 1.5.5