Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

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-2004 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.3 (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 
00036 
00037 //  <sc_mempool> is a class that manages the memory for small objects,
00038 //  of sizes <increment>, 2 * <increment>, ..., <num_pools> *
00039 //  <increment>.  When a memory request of <k> bytes is made through
00040 //  the memory pool, the smallest pool <j> such that <j> * <increment>
00041 //  >= <k> is used.  The default values of <increment> and <num_pools>
00042 //  are 8 and 8, respectively.  Each pool has an allocator, that
00043 //  simply keeps a free list of cells, and allocate new blocks
00044 //  whenever necessary.  We are relying on malloc() to return a
00045 //  properly aligned memory blocks.  Note that the memory blocks
00046 //  allocated by the mempool are never freed.  Thus, if purify is
00047 //  used, we may get MIU (memory-in-use) warnings.  To disable this,
00048 //  set the environment variable SYSTEMC_MEMPOOL_DONT_USE to 1.
00049 
00050 
00051 static const char* dont_use_envstring = "SYSTEMC_MEMPOOL_DONT_USE";
00052 static bool use_default_new = false;
00053 
00054 
00055 #include <stdio.h>
00056 #include <stdlib.h>
00057 #include "systemc/utils/sc_mempool.h"
00058 
00059 
00060 //  An allocator is one that handles a particular size.  It keeps a
00061 //  <free_list> from which a cell may be allocated quickly if there
00062 //  is one available.  If no cell is available from <free_list>, then
00063 //  the allocator tries to find whether space is available from the
00064 //  most-recently-allocated block, as pointed to by <next_avail>.  If
00065 //  so, then the cell pointed to by <next_avail> is returned, while
00066 //  <next_avail> is advanced.  If <next_avail> now points beyond
00067 //  the current block, then it's reset to 0.  On the other hand,
00068 //  if <next_avail> was 0 when a request to the block is made, then
00069 //  a new block is allocated by calling system malloc(), and the new
00070 //  block becomes the head of <block_list>.
00071 
00072 
00073 class sc_allocator {
00074     friend class sc_mempool;
00075 
00076 public:
00077     sc_allocator( int blksz, int cellsz );
00078     ~sc_allocator();
00079     void* allocate();
00080     void release(void* p);
00081     
00082     void display_statistics();
00083 
00084 private:
00085     union link {
00086         link* next;
00087         double align;          // alignment required.
00088     };
00089 
00090     int block_size;            // size of each block in bytes,
00091                                // including the link
00092     int cell_size;             // size of each cell in bytes
00093 
00094     char* block_list;
00095     link* free_list;
00096     char* next_avail;
00097 
00098     int total_alloc;
00099     int total_freed;
00100     int free_list_alloc;
00101 };
00102 
00103 sc_allocator::sc_allocator( int blksz, int cellsz )
00104 {
00105     cell_size = cellsz;
00106     block_size = sizeof(link) + (((blksz - 1) / cellsz) + 1) * cellsz;
00107     block_list = 0;
00108     free_list = 0;
00109     next_avail = 0;
00110 
00111     total_alloc = 0;
00112     total_freed = 0;
00113     free_list_alloc = 0;
00114 }
00115 
00116 sc_allocator::~sc_allocator()
00117 {
00118     // Shouldn't free the block_list, since global objects that use
00119     // the memory pool may not have been destroyed yet ...
00120     // Let it leak, let it leak, let it leak ...
00121 }
00122 
00123 void*
00124 sc_allocator::allocate()
00125 {
00126     void* result = 0;
00127     total_alloc++;
00128     if (free_list != 0) {
00129         free_list_alloc++;
00130         result = free_list;
00131         free_list = free_list->next;
00132         return result;
00133     }
00134     else if (next_avail != 0) {
00135         result = next_avail;
00136         next_avail += cell_size;
00137         // next_avail goes beyond the block
00138         if (next_avail >= block_list + block_size)
00139             next_avail = 0;
00140         return result;
00141     }
00142     else {  // (next_avail == 0)
00143         link* new_block = (link*) malloc(block_size);  // need alignment?
00144         new_block->next = (link*) block_list;
00145         block_list = (char*) new_block;
00146         result = (block_list + sizeof(link));
00147         // Assume that the block will hold more than one cell ... why
00148         // wouldn't it?
00149         next_avail = ((char*) result) + cell_size;
00150         return result;
00151     }
00152 }
00153 
00154 void
00155 sc_allocator::release(void* p)
00156 {
00157     total_freed++;
00158     ((link*) p)->next = free_list;
00159     free_list = (link*) p;
00160 }
00161 
00162 void
00163 sc_allocator::display_statistics()
00164 {
00165     int nblocks = 0;
00166     for (link* b = (link*) block_list; b != 0; b = b->next)
00167         nblocks++;
00168     printf("size %3d: %2d block(s), %3d requests (%3d from free list), %3d freed.\n",
00169            cell_size, nblocks, total_alloc, free_list_alloc, total_freed);
00170 }
00171 
00172 
00173 static const int cell_sizes[] = {
00174 /* 0 */   0,
00175 /* 1 */   8,
00176 /* 2 */  16,
00177 /* 3 */  24,
00178 /* 4 */  32,
00179 /* 5 */  48,
00180 /* 6 */  64,
00181 /* 7 */  80,
00182 /* 8 */  96,
00183 /* 9 */ 128
00184 };
00185 
00186 static const int cell_size_to_allocator[] = {
00187 /*  0 */    0,
00188 /*  1 */    1,
00189 /*  2 */    2,
00190 /*  3 */    3,
00191 /*  4 */    4,
00192 /*  5 */    5,
00193 /*  6 */    5,
00194 /*  7 */    6,
00195 /*  8 */    6,
00196 /*  9 */    7,
00197 /* 10 */    7,
00198 /* 11 */    8,
00199 /* 12 */    8,
00200 /* 13 */    9,
00201 /* 14 */    9,
00202 /* 15 */    9,
00203 /* 16 */    9
00204 };
00205 
00206 
00207 class sc_mempool_int {
00208     friend class sc_mempool;
00209 
00210 public:
00211     sc_mempool_int(int blksz, int npools, int incr);
00212     ~sc_mempool_int();
00213     void* do_allocate(size_t);
00214     void  do_release(void*, size_t);
00215 
00216     void display_statistics();
00217     
00218 private:
00219     sc_allocator** allocators;
00220     int num_pools;
00221     int increment;
00222     int max_size;
00223 };
00224 
00225 
00226 static bool
00227 compute_use_default_new()
00228 {
00229     const char* e = getenv(dont_use_envstring);
00230     return (e != 0) && (atoi(e) != 0);
00231 }
00232 
00233 sc_mempool_int::sc_mempool_int(int blksz, int npools, int incr)
00234 {
00235     use_default_new = compute_use_default_new();
00236     if (! use_default_new) {
00237         num_pools = npools;
00238         increment = incr;
00239         max_size = cell_sizes[sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1];
00240         allocators = new sc_allocator*[npools + 1];
00241         for (int i = 1; i <= npools; ++i)
00242             allocators[i] = new sc_allocator(blksz, cell_sizes[i]);
00243         allocators[0] = allocators[1];
00244     }
00245 }
00246 
00247 sc_mempool_int::~sc_mempool_int()
00248 {
00249     for (int i = 1; i <= num_pools; ++i)
00250         delete allocators[i];
00251     delete[] allocators;
00252 }
00253 
00254 static sc_mempool_int* the_mempool = 0;
00255 
00256 void*
00257 sc_mempool_int::do_allocate(size_t sz)
00258 {
00259     int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1];
00260     void* p = allocators[which_allocator]->allocate();
00261     return p;
00262 }
00263 
00264 void
00265 sc_mempool_int::do_release(void* p, size_t sz)
00266 {
00267     int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1];
00268     allocators[which_allocator]->release(p);
00269 }
00270 
00271 void
00272 sc_mempool_int::display_statistics()
00273 {
00274     printf("*** Memory Pool Statistics ***\n");
00275     for (int i = 1; i <= num_pools; ++i)
00276         allocators[i]->display_statistics();
00277 }
00278 
00279 /****************************************************************************/
00280 
00281 void*
00282 sc_mempool::allocate(size_t sz)
00283 {
00284     if (use_default_new)
00285         return ::operator new(sz);
00286 
00287     if (the_mempool == 0) {
00288         use_default_new = compute_use_default_new();
00289         if (use_default_new)
00290             return ::operator new(sz);
00291 
00292         // Note that the_mempool is never freed.  This is going to cause
00293         // memory leaks when the program exits.
00294         the_mempool = new sc_mempool_int( 1984, sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1, 8 );
00295     }
00296 
00297     if (sz > (unsigned) the_mempool->max_size)
00298         return ::operator new(sz);
00299 
00300     return the_mempool->do_allocate(sz);
00301 }
00302 
00303 void
00304 sc_mempool::release(void* p, size_t sz)
00305 {
00306     if (p) {
00307         
00308         if (use_default_new || sz > (unsigned) the_mempool->max_size) {
00309             ::operator delete(p);
00310             return;
00311         }
00312 
00313         the_mempool->do_release(p, sz);
00314     }
00315 }
00316 
00317 void
00318 sc_mempool::display_statistics()
00319 {
00320     if (the_mempool && !use_default_new) {
00321         the_mempool->display_statistics();
00322     } else {
00323         printf("SystemC info: no memory allocation was done through the memory pool.\n");
00324     }
00325 }

Generated on Fri Jan 14 08:29:03 2005 for SystemC2.1beta11(excludingMSLib)(IncludingSCV)\nProvidedby:www.openverificationfoundation.org by doxygen1.2.18