TuttleOFX  1
MemoryPool.cpp
Go to the documentation of this file.
00001 #include "MemoryPool.hpp"
00002 #include <tuttle/common/utils/global.hpp>
00003 #include <tuttle/common/system/memoryInfo.hpp>
00004 #include <boost/throw_exception.hpp>
00005 #include <algorithm>
00006 
00007 namespace tuttle {
00008 namespace host {
00009 namespace memory {
00010 
00011 IPool::~IPool() {}
00012 
00013 class PoolData : public IPoolData
00014 {
00015 private:
00016         PoolData(); ///< No default Ctor
00017         PoolData( const PoolData& ); ///< No copy Ctor
00018         friend class MemoryPool;
00019 
00020 public:
00021         PoolData( IPool& pool, const std::size_t size )
00022                 : _pool( pool )
00023                 , _id( _count++ )
00024                 , _reservedSize( size )
00025                 , _size( size )
00026                 , _pData( new char[size] )
00027                 , _refCount( 0 )
00028         {}
00029 
00030         ~PoolData()
00031         {
00032                 delete [] _pData;
00033         }
00034 
00035 public:
00036         bool operator==( const PoolData& other ) const
00037         {
00038                 return _id == other._id;
00039         }
00040 
00041         void addRef();
00042         void release();
00043 
00044         char*             data()               { return _pData; }
00045         const char*       data() const         { return _pData; }
00046         const std::size_t size() const         { return _size; }
00047         const std::size_t reservedSize() const { return _reservedSize; }
00048 
00049 private:
00050         static std::size_t _count; ///< unique id generator
00051         IPool& _pool; ///< ref to the owner pool
00052         const std::size_t _id; ///< unique id to identify one memory data
00053         const std::size_t _reservedSize; ///< memory allocated
00054         std::size_t _size; ///< memory requested
00055         char* const _pData; ///< own the data
00056         int _refCount; ///< counter on clients currently using this data
00057 };
00058 
00059 void intrusive_ptr_add_ref( IPoolData* pData )
00060 {
00061         pData->addRef();
00062 }
00063 
00064 void intrusive_ptr_release( IPoolData* pData )
00065 {
00066         pData->release();
00067 }
00068 
00069 std::size_t PoolData::_count = 0;
00070 
00071 void PoolData::addRef()
00072 {
00073         if( ++_refCount == 1 )
00074                 _pool.referenced( this );
00075 }
00076 
00077 void PoolData::release()
00078 {
00079         if( --_refCount == 0 )
00080                 _pool.released( this );
00081 }
00082 
00083 MemoryPool::MemoryPool( const std::size_t maxSize )
00084         : _memoryAuthorized( maxSize )
00085 {}
00086 
00087 MemoryPool::~MemoryPool()
00088 {
00089 /*      if( !_dataUsed.empty() )
00090         {
00091                 TUTTLE_LOG_WARNING( "[Memory Pool] Error inside memory pool. Some data always mark used at the destruction (nb elements:" << _dataUsed.size() << ")" );
00092         }
00093 */
00094 }
00095 
00096 void MemoryPool::referenced( PoolData* pData )
00097 {
00098         boost::mutex::scoped_lock locker( _mutex );
00099         DataList::iterator it = _dataUnused.find( pData );
00100 
00101         if( it != _dataUnused.end() )
00102         {
00103                 _dataUnused.erase( it );
00104         }
00105         else // a really new data
00106         {
00107                 _allDatas.push_back( pData );
00108                 _dataMap[pData->data()] = pData;
00109         }
00110         _dataUsed.insert( pData );
00111 }
00112 
00113 void MemoryPool::released( PoolData* pData )
00114 {
00115         boost::mutex::scoped_lock locker( _mutex );
00116         _dataUsed.erase( pData );
00117         _dataUnused.insert( pData );
00118 }
00119 
00120 namespace  {
00121 
00122 struct DataFitSize : public std::unary_function<PoolData*, void>
00123 {
00124         DataFitSize( std::size_t size )
00125                 : _size( size )
00126                 , _bestMatchDiff( ULONG_MAX )
00127                 , _pBestMatch( NULL )
00128         {}
00129 
00130         void operator()( PoolData* pData )
00131         {
00132                 const std::size_t dataSize = pData->reservedSize();
00133 
00134                 if( _size > dataSize )
00135                         return;
00136                 const std::size_t diff = dataSize - _size;
00137                 if( diff >= _bestMatchDiff )
00138                         return;
00139                 _bestMatchDiff = diff;
00140                 _pBestMatch    = pData;
00141         }
00142 
00143         PoolData* bestMatch()
00144         {
00145                 return _pBestMatch;
00146         }
00147 
00148         private:
00149                 const std::size_t _size;
00150                 std::size_t _bestMatchDiff;
00151                 PoolData* _pBestMatch;
00152 };
00153 
00154 }
00155 
00156 boost::intrusive_ptr<IPoolData> MemoryPool::allocate( const std::size_t size )
00157 {
00158         TUTTLE_TLOG( TUTTLE_TRACE, "[Memory Pool] allocate " << size << " bytes" );
00159         PoolData* pData = NULL;
00160 
00161         {
00162                 boost::mutex::scoped_lock locker( _mutex );
00163                 // checking within unused data
00164                 pData = std::for_each( _dataUnused.begin(), _dataUnused.end(), DataFitSize( size ) ).bestMatch();
00165         }
00166 
00167         if( pData != NULL )
00168         {
00169                 pData->_size = size;
00170                 return pData;
00171         }
00172 
00173         const std::size_t availableSize = getAvailableMemorySize();
00174         if( size > availableSize )
00175         {
00176                 std::stringstream s;
00177                 s << "[Memory Pool] can't allocate size:" << size << " because memory available is equal to " << availableSize << " bytes";
00178                 BOOST_THROW_EXCEPTION( std::length_error( s.str() ) );
00179         }
00180         return new PoolData( *this, size );
00181 }
00182 
00183 std::size_t MemoryPool::updateMemoryAuthorizedWithRAM()
00184 {
00185         _memoryAuthorized = /*getUsedMemorySize() +*/ getMemoryInfo()._totalRam;
00186         TUTTLE_LOG_DEBUG( TUTTLE_TRACE, "[Memory Pool] update memory authorized with RAM: " << _memoryAuthorized );
00187         return _memoryAuthorized;
00188 }
00189 
00190 namespace  {
00191 
00192 std::size_t accumulateReservedSize( const std::size_t& sum, const IPoolData* pData )
00193 {
00194         return sum + pData->reservedSize();
00195 }
00196 
00197 std::size_t accumulateWastedSize( const std::size_t& sum, const IPoolData* pData )
00198 {
00199         return sum + ( pData->reservedSize() - pData->size() );
00200 }
00201 
00202 }
00203 
00204 std::size_t MemoryPool::getUsedMemorySize() const
00205 {
00206         boost::mutex::scoped_lock locker( _mutex );
00207         return std::accumulate( _dataUsed.begin(), _dataUsed.end(), 0, &accumulateReservedSize );
00208 }
00209 
00210 std::size_t MemoryPool::getAllocatedAndUnusedMemorySize() const
00211 {
00212         boost::mutex::scoped_lock locker( _mutex );
00213         return std::accumulate( _dataUnused.begin(), _dataUnused.end(), 0, &accumulateReservedSize );
00214 }
00215 
00216 std::size_t MemoryPool::getAllocatedMemorySize() const
00217 {
00218         return getUsedMemorySize() + getAllocatedAndUnusedMemorySize();
00219 }
00220 
00221 std::size_t MemoryPool::getMaxMemorySize() const
00222 {
00223         return _memoryAuthorized;
00224 }
00225 
00226 std::size_t MemoryPool::getAvailableMemorySize() const
00227 {
00228         return getMaxMemorySize() - getUsedMemorySize();
00229 }
00230 
00231 std::size_t MemoryPool::getWastedMemorySize() const
00232 {
00233         boost::mutex::scoped_lock locker( _mutex );
00234         return std::accumulate( _dataUsed.begin(), _dataUsed.end(), 0, std::ptr_fun( &accumulateWastedSize ) );
00235 }
00236 
00237 std::size_t MemoryPool::getDataUsedSize() const
00238 {
00239         return _dataUsed.size();
00240 }
00241 
00242 std::size_t MemoryPool::getDataUnusedSize() const
00243 {
00244         return _dataUnused.size();
00245 }
00246 
00247 void MemoryPool::clear( std::size_t size )
00248 {
00249         /// @todo tuttle
00250 }
00251 
00252 void MemoryPool::clear()
00253 {
00254         /// @todo tuttle
00255         boost::mutex::scoped_lock locker( _mutex );
00256         _dataUnused.clear();
00257 }
00258 
00259 void MemoryPool::clearOne()
00260 {
00261         /// @todo tuttle
00262 }
00263 /*
00264 std::ostream& operator<<( std::ostream& os, const MemoryPool& memoryPool )
00265 {
00266         os << "[Memory Pool] Used data:             " << memoryPool._dataUsed.size() << " bytes";
00267         os << "[Memory Pool] Unused data:           " << memoryPool.getDataUnusedSize() << " bytes";
00268         os << "[Memory Pool] All datas:             " << memoryPool.getDataUsedSize() << " bytes";
00269         os << "[Memory Pool] Memory authorized:     " << memoryPool.updateMemoryAuthorizedWithRAM() << " bytes";
00270         os << "";
00271         os << "[Memory Pool] Used memory:           " << memoryPool.getUsedMemorySize() << " bytes";
00272         os << "[Memory Pool] Allocated memory:      " << memoryPool.getAllocatedMemorySize() << " bytes";
00273         os << "[Memory Pool] Max memory:            " << memoryPool.getMaxMemorySize() << " bytes";
00274         os << "[Memory Pool] Available memory size: " << memoryPool.getAvailableMemorySize() << " bytes";
00275         os << "[Memory Pool] Wasted memory:         " << memoryPool.getWastedMemorySize() << " bytes";
00276         return ostream;
00277 }*/
00278 
00279 }
00280 }
00281 }