112027Sjungma@eit.uni-kl.de/***************************************************************************** 212027Sjungma@eit.uni-kl.de 312027Sjungma@eit.uni-kl.de Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 412027Sjungma@eit.uni-kl.de more contributor license agreements. See the NOTICE file distributed 512027Sjungma@eit.uni-kl.de with this work for additional information regarding copyright ownership. 612027Sjungma@eit.uni-kl.de Accellera licenses this file to you under the Apache License, Version 2.0 712027Sjungma@eit.uni-kl.de (the "License"); you may not use this file except in compliance with the 812027Sjungma@eit.uni-kl.de License. You may obtain a copy of the License at 912027Sjungma@eit.uni-kl.de 1012027Sjungma@eit.uni-kl.de http://www.apache.org/licenses/LICENSE-2.0 1112027Sjungma@eit.uni-kl.de 1212027Sjungma@eit.uni-kl.de Unless required by applicable law or agreed to in writing, software 1312027Sjungma@eit.uni-kl.de distributed under the License is distributed on an "AS IS" BASIS, 1412027Sjungma@eit.uni-kl.de WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 1512027Sjungma@eit.uni-kl.de implied. See the License for the specific language governing 1612027Sjungma@eit.uni-kl.de permissions and limitations under the License. 1712027Sjungma@eit.uni-kl.de 1812027Sjungma@eit.uni-kl.de *****************************************************************************/ 1912027Sjungma@eit.uni-kl.de 2012027Sjungma@eit.uni-kl.de/***************************************************************************** 2112027Sjungma@eit.uni-kl.de 2212027Sjungma@eit.uni-kl.de sc_mempool.cpp - Memory pools for small objects. 2312027Sjungma@eit.uni-kl.de 2412027Sjungma@eit.uni-kl.de Original Author: Stan Y. Liao, Synopsys, Inc. 2512027Sjungma@eit.uni-kl.de 2612027Sjungma@eit.uni-kl.de CHANGE LOG AT END OF FILE 2712027Sjungma@eit.uni-kl.de *****************************************************************************/ 2812027Sjungma@eit.uni-kl.de 2912027Sjungma@eit.uni-kl.de 3012027Sjungma@eit.uni-kl.de 3112027Sjungma@eit.uni-kl.de 3212027Sjungma@eit.uni-kl.de// <sc_mempool> is a class that manages the memory for small objects, 3312027Sjungma@eit.uni-kl.de// of sizes <increment>, 2 * <increment>, ..., <num_pools> * 3412027Sjungma@eit.uni-kl.de// <increment>. When a memory request of <k> bytes is made through 3512027Sjungma@eit.uni-kl.de// the memory pool, the smallest pool <j> such that <j> * <increment> 3612027Sjungma@eit.uni-kl.de// >= <k> is used. The default values of <increment> and <num_pools> 3712027Sjungma@eit.uni-kl.de// are 8 and 8, respectively. Each pool has an allocator, that 3812027Sjungma@eit.uni-kl.de// simply keeps a free list of cells, and allocate new blocks 3912027Sjungma@eit.uni-kl.de// whenever necessary. We are relying on malloc() to return a 4012027Sjungma@eit.uni-kl.de// properly aligned memory blocks. Note that the memory blocks 4112027Sjungma@eit.uni-kl.de// allocated by the mempool are never freed. Thus, if purify is 4212027Sjungma@eit.uni-kl.de// used, we may get MIU (memory-in-use) warnings. To disable this, 4312027Sjungma@eit.uni-kl.de// set the environment variable SYSTEMC_MEMPOOL_DONT_USE to 1. 4412027Sjungma@eit.uni-kl.de 4512027Sjungma@eit.uni-kl.de 4612027Sjungma@eit.uni-kl.destatic const char* dont_use_envstring = "SYSTEMC_MEMPOOL_DONT_USE"; 4712027Sjungma@eit.uni-kl.destatic bool use_default_new = false; 4812027Sjungma@eit.uni-kl.de 4912027Sjungma@eit.uni-kl.de 5012027Sjungma@eit.uni-kl.de#include <stdio.h> 5112027Sjungma@eit.uni-kl.de#include <stdlib.h> // duplicate (c)stdlib.h headers for Solaris 5212027Sjungma@eit.uni-kl.de#include <cstdlib> 5312027Sjungma@eit.uni-kl.de#include "sysc/utils/sc_mempool.h" 5412027Sjungma@eit.uni-kl.de 5512027Sjungma@eit.uni-kl.denamespace sc_core { 5612027Sjungma@eit.uni-kl.de 5712027Sjungma@eit.uni-kl.de// An allocator is one that handles a particular size. It keeps a 5812027Sjungma@eit.uni-kl.de// <free_list> from which a cell may be allocated quickly if there 5912027Sjungma@eit.uni-kl.de// is one available. If no cell is available from <free_list>, then 6012027Sjungma@eit.uni-kl.de// the allocator tries to find whether space is available from the 6112027Sjungma@eit.uni-kl.de// most-recently-allocated block, as pointed to by <next_avail>. If 6212027Sjungma@eit.uni-kl.de// so, then the cell pointed to by <next_avail> is returned, while 6312027Sjungma@eit.uni-kl.de// <next_avail> is advanced. If <next_avail> now points beyond 6412027Sjungma@eit.uni-kl.de// the current block, then it's reset to 0. On the other hand, 6512027Sjungma@eit.uni-kl.de// if <next_avail> was 0 when a request to the block is made, then 6612027Sjungma@eit.uni-kl.de// a new block is allocated by calling system malloc(), and the new 6712027Sjungma@eit.uni-kl.de// block becomes the head of <block_list>. 6812027Sjungma@eit.uni-kl.de 6912027Sjungma@eit.uni-kl.de 7012027Sjungma@eit.uni-kl.declass sc_allocator { 7112027Sjungma@eit.uni-kl.de friend class sc_mempool; 7212027Sjungma@eit.uni-kl.de 7312027Sjungma@eit.uni-kl.depublic: 7412027Sjungma@eit.uni-kl.de sc_allocator( int blksz, int cellsz ); 7512027Sjungma@eit.uni-kl.de ~sc_allocator(); 7612027Sjungma@eit.uni-kl.de void* allocate(); 7712027Sjungma@eit.uni-kl.de void release(void* p); 7812027Sjungma@eit.uni-kl.de 7912027Sjungma@eit.uni-kl.de void display_statistics(); 8012027Sjungma@eit.uni-kl.de 8112027Sjungma@eit.uni-kl.deprivate: 8212027Sjungma@eit.uni-kl.de union link { 8312027Sjungma@eit.uni-kl.de link* next; 8412027Sjungma@eit.uni-kl.de double align; // alignment required. 8512027Sjungma@eit.uni-kl.de }; 8612027Sjungma@eit.uni-kl.de 8712027Sjungma@eit.uni-kl.de int block_size; // size of each block in bytes, 8812027Sjungma@eit.uni-kl.de // including the link 8912027Sjungma@eit.uni-kl.de int cell_size; // size of each cell in bytes 9012027Sjungma@eit.uni-kl.de 9112027Sjungma@eit.uni-kl.de char* block_list; 9212027Sjungma@eit.uni-kl.de link* free_list; 9312027Sjungma@eit.uni-kl.de char* next_avail; 9412027Sjungma@eit.uni-kl.de 9512027Sjungma@eit.uni-kl.de int total_alloc; 9612027Sjungma@eit.uni-kl.de int total_freed; 9712027Sjungma@eit.uni-kl.de int free_list_alloc; 9812027Sjungma@eit.uni-kl.de}; 9912027Sjungma@eit.uni-kl.de 10012027Sjungma@eit.uni-kl.desc_allocator::sc_allocator( int blksz, int cellsz ) 10112027Sjungma@eit.uni-kl.de : block_size(sizeof(link) + (((blksz - 1) / cellsz) + 1) * cellsz), 10212027Sjungma@eit.uni-kl.de cell_size(cellsz), block_list(0), free_list(0), next_avail(0), 10312027Sjungma@eit.uni-kl.de total_alloc(0), total_freed(0), free_list_alloc(0) 10412027Sjungma@eit.uni-kl.de{} 10512027Sjungma@eit.uni-kl.de 10612027Sjungma@eit.uni-kl.desc_allocator::~sc_allocator() 10712027Sjungma@eit.uni-kl.de{ 10812027Sjungma@eit.uni-kl.de // Shouldn't free the block_list, since global objects that use 10912027Sjungma@eit.uni-kl.de // the memory pool may not have been destroyed yet ... 11012027Sjungma@eit.uni-kl.de // Let it leak, let it leak, let it leak ... 11112027Sjungma@eit.uni-kl.de} 11212027Sjungma@eit.uni-kl.de 11312027Sjungma@eit.uni-kl.devoid* 11412027Sjungma@eit.uni-kl.desc_allocator::allocate() 11512027Sjungma@eit.uni-kl.de{ 11612027Sjungma@eit.uni-kl.de void* result = 0; 11712027Sjungma@eit.uni-kl.de total_alloc++; 11812027Sjungma@eit.uni-kl.de if (free_list != 0) { 11912027Sjungma@eit.uni-kl.de free_list_alloc++; 12012027Sjungma@eit.uni-kl.de result = free_list; 12112027Sjungma@eit.uni-kl.de free_list = free_list->next; 12212027Sjungma@eit.uni-kl.de return result; 12312027Sjungma@eit.uni-kl.de } 12412027Sjungma@eit.uni-kl.de else if (next_avail != 0) { 12512027Sjungma@eit.uni-kl.de result = next_avail; 12612027Sjungma@eit.uni-kl.de next_avail += cell_size; 12712027Sjungma@eit.uni-kl.de // next_avail goes beyond the block 12812027Sjungma@eit.uni-kl.de if (next_avail >= block_list + block_size) 12912027Sjungma@eit.uni-kl.de next_avail = 0; 13012027Sjungma@eit.uni-kl.de return result; 13112027Sjungma@eit.uni-kl.de } 13212027Sjungma@eit.uni-kl.de else { // (next_avail == 0) 13312027Sjungma@eit.uni-kl.de link* new_block = (link*) malloc(block_size); // need alignment? 13412027Sjungma@eit.uni-kl.de new_block->next = (link*) block_list; 13512027Sjungma@eit.uni-kl.de block_list = (char*) new_block; 13612027Sjungma@eit.uni-kl.de result = (block_list + sizeof(link)); 13712027Sjungma@eit.uni-kl.de // Assume that the block will hold more than one cell ... why 13812027Sjungma@eit.uni-kl.de // wouldn't it? 13912027Sjungma@eit.uni-kl.de next_avail = ((char*) result) + cell_size; 14012027Sjungma@eit.uni-kl.de return result; 14112027Sjungma@eit.uni-kl.de } 14212027Sjungma@eit.uni-kl.de} 14312027Sjungma@eit.uni-kl.de 14412027Sjungma@eit.uni-kl.devoid 14512027Sjungma@eit.uni-kl.desc_allocator::release(void* p) 14612027Sjungma@eit.uni-kl.de{ 14712027Sjungma@eit.uni-kl.de total_freed++; 14812027Sjungma@eit.uni-kl.de ((link*) p)->next = free_list; 14912027Sjungma@eit.uni-kl.de free_list = (link*) p; 15012027Sjungma@eit.uni-kl.de} 15112027Sjungma@eit.uni-kl.de 15212027Sjungma@eit.uni-kl.devoid 15312027Sjungma@eit.uni-kl.desc_allocator::display_statistics() 15412027Sjungma@eit.uni-kl.de{ 15512027Sjungma@eit.uni-kl.de int nblocks = 0; 15612027Sjungma@eit.uni-kl.de for (link* b = (link*) block_list; b != 0; b = b->next) 15712027Sjungma@eit.uni-kl.de nblocks++; 15812027Sjungma@eit.uni-kl.de printf("size %3d: %2d block(s), %3d requests (%3d from free list), %3d freed.\n", 15912027Sjungma@eit.uni-kl.de cell_size, nblocks, total_alloc, free_list_alloc, total_freed); 16012027Sjungma@eit.uni-kl.de} 16112027Sjungma@eit.uni-kl.de 16212027Sjungma@eit.uni-kl.de 16312027Sjungma@eit.uni-kl.destatic const int cell_sizes[] = { 16412027Sjungma@eit.uni-kl.de/* 0 */ 0, 16512027Sjungma@eit.uni-kl.de/* 1 */ 8, 16612027Sjungma@eit.uni-kl.de/* 2 */ 16, 16712027Sjungma@eit.uni-kl.de/* 3 */ 24, 16812027Sjungma@eit.uni-kl.de/* 4 */ 32, 16912027Sjungma@eit.uni-kl.de/* 5 */ 48, 17012027Sjungma@eit.uni-kl.de/* 6 */ 64, 17112027Sjungma@eit.uni-kl.de/* 7 */ 80, 17212027Sjungma@eit.uni-kl.de/* 8 */ 96, 17312027Sjungma@eit.uni-kl.de/* 9 */ 128 17412027Sjungma@eit.uni-kl.de}; 17512027Sjungma@eit.uni-kl.de 17612027Sjungma@eit.uni-kl.destatic const int cell_size_to_allocator[] = { 17712027Sjungma@eit.uni-kl.de/* 0 */ 0, 17812027Sjungma@eit.uni-kl.de/* 1 */ 1, 17912027Sjungma@eit.uni-kl.de/* 2 */ 2, 18012027Sjungma@eit.uni-kl.de/* 3 */ 3, 18112027Sjungma@eit.uni-kl.de/* 4 */ 4, 18212027Sjungma@eit.uni-kl.de/* 5 */ 5, 18312027Sjungma@eit.uni-kl.de/* 6 */ 5, 18412027Sjungma@eit.uni-kl.de/* 7 */ 6, 18512027Sjungma@eit.uni-kl.de/* 8 */ 6, 18612027Sjungma@eit.uni-kl.de/* 9 */ 7, 18712027Sjungma@eit.uni-kl.de/* 10 */ 7, 18812027Sjungma@eit.uni-kl.de/* 11 */ 8, 18912027Sjungma@eit.uni-kl.de/* 12 */ 8, 19012027Sjungma@eit.uni-kl.de/* 13 */ 9, 19112027Sjungma@eit.uni-kl.de/* 14 */ 9, 19212027Sjungma@eit.uni-kl.de/* 15 */ 9, 19312027Sjungma@eit.uni-kl.de/* 16 */ 9 19412027Sjungma@eit.uni-kl.de}; 19512027Sjungma@eit.uni-kl.de 19612027Sjungma@eit.uni-kl.de 19712027Sjungma@eit.uni-kl.declass sc_mempool_int { 19812027Sjungma@eit.uni-kl.de friend class sc_mempool; 19912027Sjungma@eit.uni-kl.de 20012027Sjungma@eit.uni-kl.depublic: 20112027Sjungma@eit.uni-kl.de sc_mempool_int(int blksz, int npools, int incr); 20212027Sjungma@eit.uni-kl.de ~sc_mempool_int(); 20312027Sjungma@eit.uni-kl.de void* do_allocate(std::size_t); 20412027Sjungma@eit.uni-kl.de void do_release(void*, std::size_t); 20512027Sjungma@eit.uni-kl.de 20612027Sjungma@eit.uni-kl.de void display_statistics(); 20712027Sjungma@eit.uni-kl.de 20812027Sjungma@eit.uni-kl.deprivate: 20912027Sjungma@eit.uni-kl.de sc_allocator** allocators; 21012027Sjungma@eit.uni-kl.de int num_pools; 21112027Sjungma@eit.uni-kl.de int increment; 21212027Sjungma@eit.uni-kl.de int max_size; 21312027Sjungma@eit.uni-kl.de}; 21412027Sjungma@eit.uni-kl.de 21512027Sjungma@eit.uni-kl.de 21612027Sjungma@eit.uni-kl.destatic bool 21712027Sjungma@eit.uni-kl.decompute_use_default_new() 21812027Sjungma@eit.uni-kl.de{ 21912027Sjungma@eit.uni-kl.de const char* e = getenv(dont_use_envstring); 22012027Sjungma@eit.uni-kl.de return (e != 0) && (atoi(e) != 0); 22112027Sjungma@eit.uni-kl.de} 22212027Sjungma@eit.uni-kl.de 22312027Sjungma@eit.uni-kl.desc_mempool_int::sc_mempool_int(int blksz, int npools, int incr) : 22412027Sjungma@eit.uni-kl.de allocators(0), num_pools(0), increment(0), max_size(0) 22512027Sjungma@eit.uni-kl.de{ 22612027Sjungma@eit.uni-kl.de use_default_new = compute_use_default_new(); 22712027Sjungma@eit.uni-kl.de if (! use_default_new) { 22812027Sjungma@eit.uni-kl.de num_pools = npools; 22912027Sjungma@eit.uni-kl.de increment = incr; 23012027Sjungma@eit.uni-kl.de max_size = cell_sizes[sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1]; 23112027Sjungma@eit.uni-kl.de allocators = new sc_allocator*[npools + 1]; 23212027Sjungma@eit.uni-kl.de for (int i = 1; i <= npools; ++i) 23312027Sjungma@eit.uni-kl.de allocators[i] = new sc_allocator(blksz, cell_sizes[i]); 23412027Sjungma@eit.uni-kl.de allocators[0] = allocators[1]; 23512027Sjungma@eit.uni-kl.de } 23612027Sjungma@eit.uni-kl.de} 23712027Sjungma@eit.uni-kl.de 23812027Sjungma@eit.uni-kl.desc_mempool_int::~sc_mempool_int() 23912027Sjungma@eit.uni-kl.de{ 24012027Sjungma@eit.uni-kl.de for (int i = 1; i <= num_pools; ++i) 24112027Sjungma@eit.uni-kl.de delete allocators[i]; 24212027Sjungma@eit.uni-kl.de delete[] allocators; 24312027Sjungma@eit.uni-kl.de} 24412027Sjungma@eit.uni-kl.de 24512027Sjungma@eit.uni-kl.destatic sc_mempool_int* the_mempool = 0; 24612027Sjungma@eit.uni-kl.de 24712027Sjungma@eit.uni-kl.devoid* 24812027Sjungma@eit.uni-kl.desc_mempool_int::do_allocate(std::size_t sz) 24912027Sjungma@eit.uni-kl.de{ 25012027Sjungma@eit.uni-kl.de int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1]; 25112027Sjungma@eit.uni-kl.de void* p = allocators[which_allocator]->allocate(); 25212027Sjungma@eit.uni-kl.de return p; 25312027Sjungma@eit.uni-kl.de} 25412027Sjungma@eit.uni-kl.de 25512027Sjungma@eit.uni-kl.devoid 25612027Sjungma@eit.uni-kl.desc_mempool_int::do_release(void* p, std::size_t sz) 25712027Sjungma@eit.uni-kl.de{ 25812027Sjungma@eit.uni-kl.de int which_allocator = cell_size_to_allocator[(sz - 1) / increment + 1]; 25912027Sjungma@eit.uni-kl.de allocators[which_allocator]->release(p); 26012027Sjungma@eit.uni-kl.de} 26112027Sjungma@eit.uni-kl.de 26212027Sjungma@eit.uni-kl.devoid 26312027Sjungma@eit.uni-kl.desc_mempool_int::display_statistics() 26412027Sjungma@eit.uni-kl.de{ 26512027Sjungma@eit.uni-kl.de printf("*** Memory Pool Statistics ***\n"); 26612027Sjungma@eit.uni-kl.de for (int i = 1; i <= num_pools; ++i) 26712027Sjungma@eit.uni-kl.de allocators[i]->display_statistics(); 26812027Sjungma@eit.uni-kl.de} 26912027Sjungma@eit.uni-kl.de 27012027Sjungma@eit.uni-kl.de/****************************************************************************/ 27112027Sjungma@eit.uni-kl.de 27212027Sjungma@eit.uni-kl.devoid* 27312027Sjungma@eit.uni-kl.desc_mempool::allocate(std::size_t sz) 27412027Sjungma@eit.uni-kl.de{ 27512027Sjungma@eit.uni-kl.de if (use_default_new) 27612027Sjungma@eit.uni-kl.de return ::operator new(sz); 27712027Sjungma@eit.uni-kl.de 27812027Sjungma@eit.uni-kl.de if (the_mempool == 0) { 27912027Sjungma@eit.uni-kl.de use_default_new = compute_use_default_new(); 28012027Sjungma@eit.uni-kl.de if (use_default_new) 28112027Sjungma@eit.uni-kl.de return ::operator new(sz); 28212027Sjungma@eit.uni-kl.de 28312027Sjungma@eit.uni-kl.de // Note that the_mempool is never freed. This is going to cause 28412027Sjungma@eit.uni-kl.de // memory leaks when the program exits. 28512027Sjungma@eit.uni-kl.de the_mempool = new sc_mempool_int( 1984, sizeof(cell_sizes)/sizeof(cell_sizes[0]) - 1, 8 ); 28612027Sjungma@eit.uni-kl.de } 28712027Sjungma@eit.uni-kl.de 28812027Sjungma@eit.uni-kl.de if (sz > (unsigned) the_mempool->max_size) 28912027Sjungma@eit.uni-kl.de return ::operator new(sz); 29012027Sjungma@eit.uni-kl.de 29112027Sjungma@eit.uni-kl.de return the_mempool->do_allocate(sz); 29212027Sjungma@eit.uni-kl.de} 29312027Sjungma@eit.uni-kl.de 29412027Sjungma@eit.uni-kl.devoid 29512027Sjungma@eit.uni-kl.desc_mempool::release(void* p, std::size_t sz) 29612027Sjungma@eit.uni-kl.de{ 29712027Sjungma@eit.uni-kl.de if (p) { 29812027Sjungma@eit.uni-kl.de 29912027Sjungma@eit.uni-kl.de if (use_default_new || sz > (unsigned) the_mempool->max_size) { 30012027Sjungma@eit.uni-kl.de ::operator delete(p); 30112027Sjungma@eit.uni-kl.de return; 30212027Sjungma@eit.uni-kl.de } 30312027Sjungma@eit.uni-kl.de 30412027Sjungma@eit.uni-kl.de the_mempool->do_release(p, sz); 30512027Sjungma@eit.uni-kl.de } 30612027Sjungma@eit.uni-kl.de} 30712027Sjungma@eit.uni-kl.de 30812027Sjungma@eit.uni-kl.devoid 30912027Sjungma@eit.uni-kl.desc_mempool::display_statistics() 31012027Sjungma@eit.uni-kl.de{ 31112027Sjungma@eit.uni-kl.de if (the_mempool && !use_default_new) { 31212027Sjungma@eit.uni-kl.de the_mempool->display_statistics(); 31312027Sjungma@eit.uni-kl.de } else { 31412027Sjungma@eit.uni-kl.de printf("SystemC info: no memory allocation was done through the memory pool.\n"); 31512027Sjungma@eit.uni-kl.de } 31612027Sjungma@eit.uni-kl.de} 31712027Sjungma@eit.uni-kl.de 31812027Sjungma@eit.uni-kl.de} // namespace sc_core 31912027Sjungma@eit.uni-kl.de 32012027Sjungma@eit.uni-kl.de// $Log: sc_mempool.cpp,v $ 32112027Sjungma@eit.uni-kl.de// Revision 1.4 2011/08/26 20:46:18 acg 32212027Sjungma@eit.uni-kl.de// Andy Goodrich: moved the modification log to the end of the file to 32312027Sjungma@eit.uni-kl.de// eliminate source line number skew when check-ins are done. 32412027Sjungma@eit.uni-kl.de// 32512027Sjungma@eit.uni-kl.de// Revision 1.3 2011/08/24 22:05:56 acg 32612027Sjungma@eit.uni-kl.de// Torsten Maehne: initialization changes to remove warnings. 32712027Sjungma@eit.uni-kl.de// 32812027Sjungma@eit.uni-kl.de// Revision 1.2 2011/02/18 20:38:44 acg 32912027Sjungma@eit.uni-kl.de// Andy Goodrich: Updated Copyright notice. 33012027Sjungma@eit.uni-kl.de// 33112027Sjungma@eit.uni-kl.de// Revision 1.1.1.1 2006/12/15 20:20:06 acg 33212027Sjungma@eit.uni-kl.de// SystemC 2.3 33312027Sjungma@eit.uni-kl.de// 33412027Sjungma@eit.uni-kl.de// Revision 1.3 2006/01/13 18:53:10 acg 33512027Sjungma@eit.uni-kl.de// Andy Goodrich: Added $Log command so that CVS comments are reproduced in 33612027Sjungma@eit.uni-kl.de// the source. 33712027Sjungma@eit.uni-kl.de 33812027Sjungma@eit.uni-kl.de// taf 339