PLearn 0.1
|
00001 // -*- C++ -*- 00002 00003 // PMemPool.cc 00004 // 00005 // Copyright (C) 2005 Nicolas Chapados 00006 // 00007 // Redistribution and use in source and binary forms, with or without 00008 // modification, are permitted provided that the following conditions are met: 00009 // 00010 // 1. Redistributions of source code must retain the above copyright 00011 // notice, this list of conditions and the following disclaimer. 00012 // 00013 // 2. Redistributions in binary form must reproduce the above copyright 00014 // notice, this list of conditions and the following disclaimer in the 00015 // documentation and/or other materials provided with the distribution. 00016 // 00017 // 3. The name of the authors may not be used to endorse or promote 00018 // products derived from this software without specific prior written 00019 // permission. 00020 // 00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 // 00032 // This file is part of the PLearn library. For more information on the PLearn 00033 // library, go to the PLearn Web site at www.plearn.org 00034 00035 /* ******************************************************* 00036 * $Id: PMemPool.cc 9199 2008-07-03 15:00:12Z nouiz $ 00037 ******************************************************* */ 00038 00039 // Authors: Nicolas Chapados 00040 00043 // From C++ stdlib 00044 #include <assert.h> 00045 00046 // From PLearn 00047 #include "plerror.h" 00048 #include "PMemPool.h" 00049 00050 namespace PLearn { 00051 using namespace std; 00052 00053 00054 //##### PMemArena ########################################################### 00055 00056 PMemArena::PMemArena(size_t object_size_, size_t max_num_objects) 00057 : storage(0), end_of_storage(0), object_size(object_size_), 00058 allocated_objects(0), watermark(0), free_list(0) 00059 { 00060 if (object_size < sizeof(void*)) 00061 PLERROR("PMemArena::PMemArena: object_size must be at least %ld; passed size is %ld", 00062 long(sizeof(void*)), long(object_size)); 00063 size_t mem_size = object_size * max_num_objects; 00064 size_t num_align = mem_size / sizeof(Aligner); 00065 if (mem_size % sizeof(Aligner) != 0) 00066 num_align++; 00067 storage = new Aligner[num_align]; 00068 if (storage) { 00069 watermark = static_cast<char*>(storage) + object_size * max_num_objects; 00070 end_of_storage = watermark; 00071 } 00072 } 00073 00074 PMemArena::~PMemArena() 00075 { 00076 delete[] static_cast<Aligner*>(storage); 00077 } 00078 00079 void PMemArena::deallocate(void* p) 00080 { 00081 // If the freed object is exactly at the watermark location, add it back 00082 // to watermark 00083 if (p == watermark) 00084 watermark += object_size; 00085 else { 00086 // Otherwise, add p to free_list 00087 PLASSERT( belongsToArena(p) ); 00088 void** new_free_head = static_cast<void**>(p); 00089 *new_free_head = free_list; 00090 free_list = new_free_head; 00091 } 00092 allocated_objects--; 00093 } 00094 00095 00096 //##### PMemPool ############################################################ 00097 00098 PMemPool::PMemPool(size_t object_size_, size_t initial_size_, 00099 float growth_factor_, bool use_fast_deallocator) 00100 : last_arena(0), 00101 object_size(object_size_), 00102 initial_arena_size(initial_size_), 00103 cur_arena_size(initial_size_), 00104 arena_growth_factor(growth_factor_), 00105 fast_deallocate(use_fast_deallocator), 00106 free_list(0) 00107 { } 00108 00109 void* PMemPool::allocate() 00110 { 00111 // First try to allocate from last-used arena 00112 if (last_arena) { 00113 if (void* new_mem = last_arena->allocate()) 00114 return new_mem; 00115 } 00116 00117 // Otherwise, try to allocate from free list 00118 if (free_list) { 00119 void** to_return = static_cast<void**>(free_list); 00120 free_list = *to_return; 00121 return to_return; 00122 } 00123 00124 // Otherwise, try to allocate from an existing arena 00125 if (void* new_mem = allocateFromArenas()) 00126 return new_mem; 00127 00128 // Otherwise, create a new arena and allocate from it 00129 last_arena = newArena(); 00130 if (last_arena) 00131 if (void* new_mem = last_arena->allocate()) 00132 return new_mem; 00133 00134 // Last resort, throw bad_alloc... 00135 throw std::bad_alloc(); 00136 } 00137 00138 void PMemPool::deallocate(void* p) 00139 { 00140 // Fast deallocation :: append to free list 00141 if (fast_deallocate) { 00142 void** new_free_head = static_cast<void**>(p); 00143 *new_free_head = free_list; 00144 free_list = new_free_head; 00145 } 00146 // Traditional deallocator 00147 else { 00148 if (last_arena && last_arena->belongsToArena(p)) 00149 last_arena->deallocate(p); 00150 else { 00151 // Find arena from map 00152 map<void*,PMemArena*>::iterator arena_it = stormap.upper_bound(p); 00153 PLASSERT( arena_it != stormap.begin() ); 00154 --arena_it; 00155 PMemArena* arena = arena_it->second; 00156 PLASSERT( arena && arena->belongsToArena(p)); 00157 arena->deallocate(p); 00158 last_arena = arena; 00159 } 00160 00161 // Check to see if arena should be eliminated 00162 if (last_arena && last_arena->empty()) { 00163 map<void*,PMemArena*>::iterator arena_it = stormap.upper_bound(p); 00164 PLASSERT( arena_it != stormap.begin() ); 00165 --arena_it; 00166 PLASSERT( last_arena == arena_it->second ); 00167 stormap.erase(arena_it); 00168 arenas.remove(last_arena); 00169 last_arena = 0; 00170 } 00171 } 00172 } 00173 00174 void* PMemPool::allocateFromArenas() 00175 { 00176 for (list< PP<PMemArena> >::iterator it = arenas.begin(), end = arenas.end() 00177 ; it != end ; ++it) { 00178 if (void* newmem = (*it)->allocate()) { 00179 last_arena = *it; 00180 return newmem; 00181 } 00182 } 00183 return 0; 00184 } 00185 00186 PMemArena* PMemPool::newArena() 00187 { 00188 PP<PMemArena> new_arena = new PMemArena(object_size, cur_arena_size); 00189 cur_arena_size = size_t(cur_arena_size * arena_growth_factor); 00190 stormap[new_arena->storage] = (PMemArena*)new_arena; 00191 arenas.push_back(new_arena); 00192 return new_arena; 00193 } 00194 00195 void PMemPool::purge_memory() 00196 { 00197 arenas.clear(); 00198 stormap.clear(); 00199 last_arena = 0; 00200 free_list = 0; 00201 cur_arena_size = initial_arena_size; 00202 } 00203 00204 00205 } // end of namespace PLearn 00206 00207 00208 /* 00209 Local Variables: 00210 mode:c++ 00211 c-basic-offset:4 00212 c-file-style:"stroustrup" 00213 c-file-offsets:((innamespace . 0)(inline-open . 0)) 00214 indent-tabs-mode:nil 00215 fill-column:79 00216 End: 00217 */ 00218 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :