summaryrefslogtreecommitdiff
path: root/ext/systemc/src/sysc/utils/sc_mempool.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ext/systemc/src/sysc/utils/sc_mempool.cpp')
-rw-r--r--ext/systemc/src/sysc/utils/sc_mempool.cpp338
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