SegmentedPool.cpp

Go to the documentation of this file.
00001 /*
00002 Copyright (C) 2003-2006 The Pentagram team
00003 
00004 This program is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU General Public License
00006 as published by the Free Software Foundation; either version 2
00007 of the License, or (at your option) any later version.
00008 
00009 This program is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU General Public License for more details.
00013 
00014 You should have received a copy of the GNU General Public License
00015 along with this program; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 */
00018 #include "pent_include.h"
00019 
00020 #include "SegmentedPool.h"
00021 
00022 DEFINE_RUNTIME_CLASSTYPE_CODE(SegmentedPool,Pool);
00023 
00024 //      Memory is aligned to the next largest multiple of sizeof(x) from
00025 //  the base address plus the size. Although, this may not be very helpful
00026 //  if the base address is not a multiple of sizeof(X).
00027 //      example: sizeof(x) = 0x8, object size = 0xFFE2:
00028 //                      0xFFE2 + 0x8 - 1 = 0xFFE9;
00029 //                      0xFFE9 & ~(0x8 - 0x1) -> 0xFFE9 & 0xFFF8 = 0xFFE8
00030 
00031 #define OFFSET_ALIGN(X) ( (X + sizeof(uintptr) - 1) & ~(sizeof(uintptr) - 1) )
00032 
00033 #ifdef USE_VALGRIND
00034 const int redzoneSize = 8;
00035 #else
00036 const int redzoneSize = 0;
00037 #endif
00038 
00039 struct SegmentedPoolNode
00040 {
00041         SegmentedPool * pool;
00042         SegmentedPoolNode * nextFree;
00043 #ifdef USE_VALGRIND
00044         int valgrind_handle;
00045 #endif
00046         size_t size;
00047 };
00048 
00049 
00050 // We pad both the PoolNode and the memory to align it.
00051 
00052 SegmentedPool::SegmentedPool(size_t nodeCapacity_, uint32 nodes_) 
00053         : Pool(), nodes(nodes_), freeNodeCount(nodes_)
00054 {
00055         uint32 i;
00056 
00057         // Give it its real capacity.
00058         // One redzone is added after the memory block.
00059         nodeCapacity = OFFSET_ALIGN(nodeCapacity_ + redzoneSize);
00060         nodes = nodes_;
00061         
00062         // Node offsets are aligned to the next uintptr offset after the real size.
00063         // Another redzone is added between the node and the memory block.
00064         nodeOffset = OFFSET_ALIGN(sizeof(SegmentedPoolNode) + redzoneSize)
00065                 + nodeCapacity;
00066 
00067         startOfPool = new uint8[nodeOffset * nodes_];
00068         endOfPool = startOfPool + (nodeOffset * nodes_);
00069 
00070         VALGRIND_CREATE_MEMPOOL(startOfPool, redzoneSize, 0);
00071 
00072         firstFree = reinterpret_cast<SegmentedPoolNode*>(startOfPool);
00073         firstFree->pool = this;
00074         firstFree->size = 0;
00075 
00076         lastFree = firstFree;
00077 
00078         for (i = 1; i < nodes_; ++i)
00079         {
00080                 lastFree->nextFree = reinterpret_cast<SegmentedPoolNode*>(startOfPool + i * nodeOffset);
00081                 lastFree = lastFree->nextFree;
00082 
00083                 lastFree->pool = this;
00084                 lastFree->size = 0;
00085         }
00086 
00087         lastFree->nextFree = 0;
00088 }
00089 
00090 SegmentedPool::~SegmentedPool()
00091 {
00092         assert(isEmpty());
00093 
00094         VALGRIND_DESTROY_MEMPOOL(startOfPool);
00095 
00096         delete [] startOfPool;
00097 }
00098 
00099 void * SegmentedPool::allocate(size_t size)
00100 {
00101         SegmentedPoolNode* node;
00102 
00103         if (isFull() || size > nodeCapacity)
00104                 return 0;
00105 
00106         --freeNodeCount;
00107         node = firstFree;
00108         node->size = size;
00109 
00110         if (isFull())
00111         {
00112                 firstFree = 0;
00113                 lastFree = 0;
00114         }
00115         else
00116         {
00117                 firstFree = firstFree->nextFree;
00118         }
00119 
00120         node->nextFree = 0;
00121 
00122 //      con.Printf("Allocating Node 0x%08X\n", node);
00123         uint8* p = reinterpret_cast<uint8 *>(node) +
00124                 OFFSET_ALIGN(sizeof(SegmentedPoolNode) + redzoneSize);
00125 
00126         VALGRIND_MEMPOOL_ALLOC(startOfPool, p, size);
00127 #ifdef USE_VALGRIND
00128         node->valgrind_handle = VALGRIND_CREATE_BLOCK(p, size,
00129                                                                                                   "SegmentedPoolBlock");
00130 #endif
00131 
00132         return p;
00133 }
00134 
00135 void SegmentedPool::deallocate(void * ptr)
00136 {
00137         SegmentedPoolNode* node;
00138 
00139         if (inPool(ptr))
00140         {
00141                 node = getPoolNode(ptr);
00142                 node->size = 0;
00143                 assert(node->pool == this);
00144 
00145                 VALGRIND_MEMPOOL_FREE(startOfPool, ptr);
00146                 VALGRIND_DISCARD(node->valgrind_handle);
00147 
00148 //      con.Printf("Free Node 0x%08X\n", node);
00149                 if (isFull())
00150                 {
00151                         firstFree = node;
00152                         lastFree = node;
00153                 }
00154                 else
00155                 {
00156                         lastFree->nextFree = node;
00157                         lastFree = lastFree->nextFree;
00158                 }
00159                 ++freeNodeCount;
00160         }
00161 }
00162 
00163 void SegmentedPool::printInfo()
00164 {
00165         uint16 i;
00166         size_t max, min, total;
00167         SegmentedPoolNode * node;
00168 
00169         con.Printf("   start address 0x%X\tend address 0x%X\tnodeOffset 0x%X\n",
00170                         startOfPool, endOfPool, nodeOffset);
00171         con.Printf("   nodeCapacity %d b\n   total nodes %d\tfree nodes %d\n",
00172                         nodeCapacity, nodes, freeNodeCount);
00173         con.Printf("   total memory: %d\tfree memory: %d\n",
00174                         nodeCapacity * nodes, nodeCapacity * freeNodeCount);
00175 
00176         max = 0;
00177         min = nodeCapacity;
00178         total = 0;
00179 
00180         for (i = 0; i < nodes; ++i)
00181         {
00182                 node = reinterpret_cast<SegmentedPoolNode*>(startOfPool + i * nodeOffset);
00183                 if (node->size > 0)
00184                 {
00185                         max = node->size > max ? node->size : max;
00186                         min = node->size < min ? node->size : min;
00187                         total += node->size;
00188                 }
00189         }
00190 
00191         if (nodes > freeNodeCount)
00192         {
00193                 con.Printf("   smallest node: %d b\tlargest node: %d b\taverage size: %d b\n",
00194                                 min, max, total / (nodes - freeNodeCount));
00195         }
00196         else
00197         {
00198                 con.Printf("   Empty pool!!!\n");
00199         }
00200 }
00201 
00202 SegmentedPoolNode* SegmentedPool::getPoolNode(void * ptr)
00203 {
00204         uint32 pos = (reinterpret_cast<uint8 *>(ptr) - startOfPool) / nodeOffset;
00205         return reinterpret_cast<SegmentedPoolNode*>(startOfPool + pos*nodeOffset);
00206 }
00207 

Generated on Fri Jul 27 22:27:35 2007 for pentagram by  doxygen 1.4.7