PLearn 0.1
PMemPool.cc
Go to the documentation of this file.
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 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines