TuttleOFX
1
|
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 }