diff options
Diffstat (limited to 'ext/systemc/src/sysc/utils/sc_mempool.cpp')
-rw-r--r-- | ext/systemc/src/sysc/utils/sc_mempool.cpp | 338 |
1 files changed, 338 insertions, 0 deletions
diff --git a/ext/systemc/src/sysc/utils/sc_mempool.cpp b/ext/systemc/src/sysc/utils/sc_mempool.cpp new file mode 100644 index 000000000..7369c12a0 --- /dev/null +++ b/ext/systemc/src/sysc/utils/sc_mempool.cpp @@ -0,0 +1,338 @@ +/***************************************************************************** + + Licensed to Accellera Systems Initiative Inc. (Accellera) under one or + more contributor license agreements. See the NOTICE file distributed + with this work for additional information regarding copyright ownership. + Accellera licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with the + License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + *****************************************************************************/ + +/***************************************************************************** + + sc_mempool.cpp - Memory pools for small objects. + + Original Author: Stan Y. Liao, Synopsys, Inc. + + CHANGE LOG AT END OF FILE + *****************************************************************************/ + + + + +// <sc_mempool> is a class that manages the memory for small objects, +// of sizes <increment>, 2 * <increment>, ..., <num_pools> * +// <increment>. When a memory request of <k> bytes is made through +// the memory pool, the smallest pool <j> such that <j> * <increment> +// >= <k> is used. The default values of <increment> and <num_pools> +// are 8 and 8, respectively. Each pool has an allocator, that +// simply keeps a free list of cells, and allocate new blocks +// whenever necessary. We are relying on malloc() to return a +// properly aligned memory blocks. Note that the memory blocks +// allocated by the mempool are never freed. Thus, if purify is +// used, we may get MIU (memory-in-use) warnings. To disable this, +// set the environment variable SYSTEMC_MEMPOOL_DONT_USE to 1. + + +static const char* dont_use_envstring = "SYSTEMC_MEMPOOL_DONT_USE"; +static bool use_default_new = false; + + +#include <stdio.h> +#include <stdlib.h> // duplicate (c)stdlib.h headers for Solaris +#include <cstdlib> +#include "sysc/utils/sc_mempool.h" + +namespace sc_core { + +// An allocator is one that handles a particular size. It keeps a +// <free_list> from which a cell may be allocated quickly if there +// is one available. If no cell is available from <free_list>, then +// the allocator tries to find whether space is available from the +// most-recently-allocated block, as pointed to by <next_avail>. If +// so, then the cell pointed to by <next_avail> is returned, while +// <next_avail> is advanced. If <next_avail> now points beyond +// the current block, then it's reset to 0. On the other hand, +// if <next_avail> was 0 when a request to the block is made, then +// a new block is allocated by calling system malloc(), and the new +// block becomes the head of <block_list>. + + +class sc_allocator { + friend class sc_mempool; + +public: + sc_allocator( int blksz, int cellsz ); + ~sc_allocator(); + void* allocate(); + void release(void* p); + + void display_statistics(); + +private: + union link { + link* next; + double align; // alignment required. + }; + + int block_size; // size of each block in bytes, + // including the link + int cell_size; // size of each cell in bytes + + char* block_list; + link* free_list; + char* next_avail; + + int total_alloc; + int total_freed; + int free_list_alloc; +}; + +sc_allocator::sc_allocator( int blksz, int cellsz ) + : block_size(sizeof(link) + (((blksz - 1) / cellsz) + 1) * cellsz), + cell_size(cellsz), block_list(0), free_list(0), next_avail(0), + total_alloc(0), total_freed(0), free_list_alloc(0) +{} + +sc_allocator::~sc_allocator() +{ + // Shouldn't free the block_list, since global objects that use + // the memory pool may not have been destroyed yet ... + // Let it leak, let it leak, let it leak ... +} + +void* +sc_allocator::allocate() +{ + void* result = 0; + total_alloc++; + if (free_list != 0) { + free_list_alloc++; + result = free_list; + free_list = free_list->next; + return result; + } + else if (next_avail != 0) { + result = next_avail; + next_avail += cell_size; + // next_avail goes beyond the block + if (next_avail >= block_list + block_size) + next_avail = 0; + return result; + } + else { // (next_avail == 0) + link* new_block = (link*) malloc(block_size); // need alignment? + new_block->next = (link*) block_list; + block_list = (char*) new_block; + result = (block_list + sizeof(link)); + // Assume that the block will hold more than one cell ... why + // wouldn't it? + next_avail = ((char*) result) + cell_size; + return result; + } +} + +void +sc_allocator::release(void* p) +{ + total_freed++; + ((link*) p)->next = free_list; + free_list = (link*) p; +} + +void +sc_allocator::display_statistics() +{ + int nblocks = 0; + for (link* b = (link*) block_list; b != 0; b = b->next) + nblocks++; + printf("size %3d: %2d block(s), %3d requests (%3d from free list), %3d freed.\n", + cell_size, nblocks, total_alloc, free_list_alloc, total_freed); +} + + +static const int cell_sizes[] = { +/* 0 */ 0, +/* 1 */ 8, +/* 2 */ 16, +/* 3 */ 24, +/* 4 */ 32, +/* 5 */ 48, +/* 6 */ 64, +/* 7 */ 80, +/* 8 */ 96, +/* 9 */ 128 +}; + +static const int cell_size_to_allocator[] = { +/* 0 */ 0, +/* 1 */ 1, +/* 2 */ 2, +/* 3 */ 3, +/* 4 */ 4, +/* 5 */ 5, +/* 6 */ 5, +/* 7 */ 6, +/* 8 */ 6, +/* 9 */ 7, +/* 10 */ 7, +/* 11 */ 8, +/* 12 */ 8, +/* 13 */ 9, +/* 14 */ 9, +/* 15 */ 9, +/* 16 */ 9 +}; + + +class sc_mempool_int { + friend class sc_mempool; + +public: + sc_mempool_int(int blksz, int npools, int incr); + ~sc_mempool_int(); + void* do_allocate(std::size_t); + void do_release(void*, std::size_t); + + void display_statistics(); + +private: + sc_allocator** allocators; + int num_pools; + int increment; + int max_size; +}; + + +static bool +compute_use_default_new() +{ + const char* e = getenv(dont_use_envstring); + return (e != 0) && (atoi(e) != 0); +} + +sc_mempool_int::sc_mempool_int(int blksz, int npools, int incr) : + allocators(0), num_pools(0), increment(0), max_size(0) +{ + use_default_new = compute_use_default_new(); + if (! use_default_new) { + num_pools = npools; + increment = incr; + max_size = cell_sizes[sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1]; + allocators = new sc_allocator*[npools + 1]; + for (int i = 1; i <= npools; ++i) + allocators[i] = new sc_allocator(blksz, cell_sizes[i]); + allocators[0] = allocators[1]; + } +} + +sc_mempool_int::~sc_mempool_int() +{ + for (int i = 1; i <= num_pools; ++i) + delete allocators[i]; + delete[] allocators; +} + +static sc_mempool_int* the_mempool = 0; + +void* +sc_mempool_int::do_allocate(std::size_t sz) +{ + int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1]; + void* p = allocators[which_allocator]->allocate(); + return p; +} + +void +sc_mempool_int::do_release(void* p, std::size_t sz) +{ + int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1]; + allocators[which_allocator]->release(p); +} + +void +sc_mempool_int::display_statistics() +{ + printf("*** Memory Pool Statistics ***\n"); + for (int i = 1; i <= num_pools; ++i) + allocators[i]->display_statistics(); +} + +/****************************************************************************/ + +void* +sc_mempool::allocate(std::size_t sz) +{ + if (use_default_new) + return ::operator new(sz); + + if (the_mempool == 0) { + use_default_new = compute_use_default_new(); + if (use_default_new) + return ::operator new(sz); + + // Note that the_mempool is never freed. This is going to cause + // memory leaks when the program exits. + the_mempool = new sc_mempool_int( 1984, sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1, 8 ); + } + + if (sz > (unsigned) the_mempool->max_size) + return ::operator new(sz); + + return the_mempool->do_allocate(sz); +} + +void +sc_mempool::release(void* p, std::size_t sz) +{ + if (p) { + + if (use_default_new || sz > (unsigned) the_mempool->max_size) { + ::operator delete(p); + return; + } + + the_mempool->do_release(p, sz); + } +} + +void +sc_mempool::display_statistics() +{ + if (the_mempool && !use_default_new) { + the_mempool->display_statistics(); + } else { + printf("SystemC info: no memory allocation was done through the memory pool.\n"); + } +} + +} // namespace sc_core + +// $Log: sc_mempool.cpp,v $ +// Revision 1.4 2011/08/26 20:46:18 acg +// Andy Goodrich: moved the modification log to the end of the file to +// eliminate source line number skew when check-ins are done. +// +// Revision 1.3 2011/08/24 22:05:56 acg +// Torsten Maehne: initialization changes to remove warnings. +// +// Revision 1.2 2011/02/18 20:38:44 acg +// Andy Goodrich: Updated Copyright notice. +// +// Revision 1.1.1.1 2006/12/15 20:20:06 acg +// SystemC 2.3 +// +// Revision 1.3 2006/01/13 18:53:10 acg +// Andy Goodrich: Added $Log command so that CVS comments are reproduced in +// the source. + +// taf |