PageRenderTime 51ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/llcommon/llmemory.h

https://bitbucket.org/lindenlab/viewer-beta/
C Header | 515 lines | 381 code | 80 blank | 54 comment | 12 complexity | ca116ddeddd7f2408f1016e31beaa265 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llmemory.h
  3. * @brief Memory allocation/deallocation header-stuff goes here.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #ifndef LLMEMORY_H
  27. #define LLMEMORY_H
  28. #include "llmemtype.h"
  29. #if LL_DEBUG
  30. inline void* ll_aligned_malloc( size_t size, int align )
  31. {
  32. void* mem = malloc( size + (align - 1) + sizeof(void*) );
  33. char* aligned = ((char*)mem) + sizeof(void*);
  34. aligned += align - ((uintptr_t)aligned & (align - 1));
  35. ((void**)aligned)[-1] = mem;
  36. return aligned;
  37. }
  38. inline void ll_aligned_free( void* ptr )
  39. {
  40. free( ((void**)ptr)[-1] );
  41. }
  42. inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
  43. {
  44. #if defined(LL_WINDOWS)
  45. return _mm_malloc(size, 16);
  46. #elif defined(LL_DARWIN)
  47. return malloc(size); // default osx malloc is 16 byte aligned.
  48. #else
  49. void *rtn;
  50. if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
  51. return rtn;
  52. else // bad alignment requested, or out of memory
  53. return NULL;
  54. #endif
  55. }
  56. inline void ll_aligned_free_16(void *p)
  57. {
  58. #if defined(LL_WINDOWS)
  59. _mm_free(p);
  60. #elif defined(LL_DARWIN)
  61. return free(p);
  62. #else
  63. free(p); // posix_memalign() is compatible with heap deallocator
  64. #endif
  65. }
  66. inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
  67. {
  68. #if defined(LL_WINDOWS)
  69. return _mm_malloc(size, 32);
  70. #elif defined(LL_DARWIN)
  71. return ll_aligned_malloc( size, 32 );
  72. #else
  73. void *rtn;
  74. if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
  75. return rtn;
  76. else // bad alignment requested, or out of memory
  77. return NULL;
  78. #endif
  79. }
  80. inline void ll_aligned_free_32(void *p)
  81. {
  82. #if defined(LL_WINDOWS)
  83. _mm_free(p);
  84. #elif defined(LL_DARWIN)
  85. ll_aligned_free( p );
  86. #else
  87. free(p); // posix_memalign() is compatible with heap deallocator
  88. #endif
  89. }
  90. #else // LL_DEBUG
  91. // ll_aligned_foo are noops now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals)
  92. #define ll_aligned_malloc( size, align ) malloc(size)
  93. #define ll_aligned_free( ptr ) free(ptr)
  94. #define ll_aligned_malloc_16 malloc
  95. #define ll_aligned_free_16 free
  96. #define ll_aligned_malloc_32 malloc
  97. #define ll_aligned_free_32 free
  98. #endif // LL_DEBUG
  99. #ifndef __DEBUG_PRIVATE_MEM__
  100. #define __DEBUG_PRIVATE_MEM__ 0
  101. #endif
  102. class LL_COMMON_API LLMemory
  103. {
  104. public:
  105. static void initClass();
  106. static void cleanupClass();
  107. static void freeReserve();
  108. // Return the resident set size of the current process, in bytes.
  109. // Return value is zero if not known.
  110. static U64 getCurrentRSS();
  111. static U32 getWorkingSetSize();
  112. static void* tryToAlloc(void* address, U32 size);
  113. static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure);
  114. static void updateMemoryInfo() ;
  115. static void logMemoryInfo(BOOL update = FALSE);
  116. static bool isMemoryPoolLow();
  117. static U32 getAvailableMemKB() ;
  118. static U32 getMaxMemKB() ;
  119. static U32 getAllocatedMemKB() ;
  120. private:
  121. static char* reserveMem;
  122. static U32 sAvailPhysicalMemInKB ;
  123. static U32 sMaxPhysicalMemInKB ;
  124. static U32 sAllocatedMemInKB;
  125. static U32 sAllocatedPageSizeInKB ;
  126. static U32 sMaxHeapSizeInKB;
  127. static BOOL sEnableMemoryFailurePrevention;
  128. };
  129. //----------------------------------------------------------------------------
  130. #if MEM_TRACK_MEM
  131. class LLMutex ;
  132. class LL_COMMON_API LLMemTracker
  133. {
  134. private:
  135. LLMemTracker() ;
  136. ~LLMemTracker() ;
  137. public:
  138. static void release() ;
  139. static LLMemTracker* getInstance() ;
  140. void track(const char* function, const int line) ;
  141. void preDraw(BOOL pause) ;
  142. void postDraw() ;
  143. const char* getNextLine() ;
  144. private:
  145. static LLMemTracker* sInstance ;
  146. char** mStringBuffer ;
  147. S32 mCapacity ;
  148. U32 mLastAllocatedMem ;
  149. S32 mCurIndex ;
  150. S32 mCounter;
  151. S32 mDrawnIndex;
  152. S32 mNumOfDrawn;
  153. BOOL mPaused;
  154. LLMutex* mMutexp ;
  155. };
  156. #define MEM_TRACK_RELEASE LLMemTracker::release() ;
  157. #define MEM_TRACK LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ;
  158. #else // MEM_TRACK_MEM
  159. #define MEM_TRACK_RELEASE
  160. #define MEM_TRACK
  161. #endif // MEM_TRACK_MEM
  162. //----------------------------------------------------------------------------
  163. //
  164. //class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not
  165. //need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster,
  166. //and reduces virtaul address space gragmentation problem.
  167. //Note: this class is thread-safe by passing true to the constructor function. However, you do not need to do this unless
  168. //you are sure the memory allocation and de-allocation will happen in different threads. To make the pool thread safe
  169. //increases allocation and deallocation cost.
  170. //
  171. class LL_COMMON_API LLPrivateMemoryPool
  172. {
  173. friend class LLPrivateMemoryPoolManager ;
  174. public:
  175. class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly
  176. {
  177. public:
  178. LLMemoryBlock() ;
  179. ~LLMemoryBlock() ;
  180. void init(char* buffer, U32 buffer_size, U32 slot_size) ;
  181. void setBuffer(char* buffer, U32 buffer_size) ;
  182. char* allocate() ;
  183. void freeMem(void* addr) ;
  184. bool empty() {return !mAllocatedSlots;}
  185. bool isFull() {return mAllocatedSlots == mTotalSlots;}
  186. bool isFree() {return !mTotalSlots;}
  187. U32 getSlotSize()const {return mSlotSize;}
  188. U32 getTotalSlots()const {return mTotalSlots;}
  189. U32 getBufferSize()const {return mBufferSize;}
  190. char* getBuffer() const {return mBuffer;}
  191. //debug use
  192. void resetBitMap() ;
  193. private:
  194. char* mBuffer;
  195. U32 mSlotSize ; //when the block is not initialized, it is the buffer size.
  196. U32 mBufferSize ;
  197. U32 mUsageBits ;
  198. U8 mTotalSlots ;
  199. U8 mAllocatedSlots ;
  200. U8 mDummySize ; //size of extra bytes reserved for mUsageBits.
  201. public:
  202. LLMemoryBlock* mPrev ;
  203. LLMemoryBlock* mNext ;
  204. LLMemoryBlock* mSelf ;
  205. struct CompareAddress
  206. {
  207. bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs)
  208. {
  209. return (U32)lhs->getBuffer() < (U32)rhs->getBuffer();
  210. }
  211. };
  212. };
  213. class LL_COMMON_API LLMemoryChunk //is divided into memory blocks.
  214. {
  215. public:
  216. LLMemoryChunk() ;
  217. ~LLMemoryChunk() ;
  218. void init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
  219. void setBuffer(char* buffer, U32 buffer_size) ;
  220. bool empty() ;
  221. char* allocate(U32 size) ;
  222. void freeMem(void* addr) ;
  223. char* getBuffer() const {return mBuffer;}
  224. U32 getBufferSize() const {return mBufferSize;}
  225. U32 getAllocatedSize() const {return mAlloatedSize;}
  226. bool containsAddress(const char* addr) const;
  227. static U32 getMaxOverhead(U32 data_buffer_size, U32 min_slot_size,
  228. U32 max_slot_size, U32 min_block_size, U32 max_block_size) ;
  229. void dump() ;
  230. private:
  231. U32 getPageIndex(U32 addr) ;
  232. U32 getBlockLevel(U32 size) ;
  233. U16 getPageLevel(U32 size) ;
  234. LLMemoryBlock* addBlock(U32 blk_idx) ;
  235. void popAvailBlockList(U32 blk_idx) ;
  236. void addToFreeSpace(LLMemoryBlock* blk) ;
  237. void removeFromFreeSpace(LLMemoryBlock* blk) ;
  238. void removeBlock(LLMemoryBlock* blk) ;
  239. void addToAvailBlockList(LLMemoryBlock* blk) ;
  240. U32 calcBlockSize(U32 slot_size);
  241. LLMemoryBlock* createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) ;
  242. private:
  243. LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize
  244. LLMemoryBlock** mFreeSpaceList;
  245. LLMemoryBlock* mBlocks ; //index of blocks by address.
  246. char* mBuffer ;
  247. U32 mBufferSize ;
  248. char* mDataBuffer ;
  249. char* mMetaBuffer ;
  250. U32 mMinBlockSize ;
  251. U32 mMinSlotSize ;
  252. U32 mMaxSlotSize ;
  253. U32 mAlloatedSize ;
  254. U16 mBlockLevels;
  255. U16 mPartitionLevels;
  256. public:
  257. //form a linked list
  258. LLMemoryChunk* mNext ;
  259. LLMemoryChunk* mPrev ;
  260. } ;
  261. private:
  262. LLPrivateMemoryPool(S32 type, U32 max_pool_size) ;
  263. ~LLPrivateMemoryPool() ;
  264. char *allocate(U32 size) ;
  265. void freeMem(void* addr) ;
  266. void dump() ;
  267. U32 getTotalAllocatedSize() ;
  268. U32 getTotalReservedSize() {return mReservedPoolSize;}
  269. S32 getType() const {return mType; }
  270. bool isEmpty() const {return !mNumOfChunks; }
  271. private:
  272. void lock() ;
  273. void unlock() ;
  274. S32 getChunkIndex(U32 size) ;
  275. LLMemoryChunk* addChunk(S32 chunk_index) ;
  276. bool checkSize(U32 asked_size) ;
  277. void removeChunk(LLMemoryChunk* chunk) ;
  278. U16 findHashKey(const char* addr);
  279. void addToHashTable(LLMemoryChunk* chunk) ;
  280. void removeFromHashTable(LLMemoryChunk* chunk) ;
  281. void rehash() ;
  282. bool fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) ;
  283. LLMemoryChunk* findChunk(const char* addr) ;
  284. void destroyPool() ;
  285. public:
  286. enum
  287. {
  288. SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB.
  289. MEDIUM_ALLOCATION, //from 2KB to 512KB(exclusive), page size 32KB, max chunk size 4MB
  290. LARGE_ALLOCATION, //from 512KB to 4MB(inclusive), page size 64KB, max chunk size 16MB
  291. SUPER_ALLOCATION //allocation larger than 4MB.
  292. };
  293. enum
  294. {
  295. STATIC = 0 , //static pool(each alllocation stays for a long time) without threading support
  296. VOLATILE, //Volatile pool(each allocation stays for a very short time) without threading support
  297. STATIC_THREADED, //static pool with threading support
  298. VOLATILE_THREADED, //volatile pool with threading support
  299. MAX_TYPES
  300. }; //pool types
  301. private:
  302. LLMutex* mMutexp ;
  303. U32 mMaxPoolSize;
  304. U32 mReservedPoolSize ;
  305. LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address
  306. U16 mNumOfChunks ;
  307. U16 mHashFactor ;
  308. S32 mType ;
  309. class LLChunkHashElement
  310. {
  311. public:
  312. LLChunkHashElement() {mFirst = NULL ; mSecond = NULL ;}
  313. bool add(LLMemoryChunk* chunk) ;
  314. void remove(LLMemoryChunk* chunk) ;
  315. LLMemoryChunk* findChunk(const char* addr) ;
  316. bool empty() {return !mFirst && !mSecond; }
  317. bool full() {return mFirst && mSecond; }
  318. bool hasElement(LLMemoryChunk* chunk) {return mFirst == chunk || mSecond == chunk;}
  319. private:
  320. LLMemoryChunk* mFirst ;
  321. LLMemoryChunk* mSecond ;
  322. };
  323. std::vector<LLChunkHashElement> mChunkHashList ;
  324. };
  325. class LL_COMMON_API LLPrivateMemoryPoolManager
  326. {
  327. private:
  328. LLPrivateMemoryPoolManager(BOOL enabled, U32 max_pool_size) ;
  329. ~LLPrivateMemoryPoolManager() ;
  330. public:
  331. static LLPrivateMemoryPoolManager* getInstance() ;
  332. static void initClass(BOOL enabled, U32 pool_size) ;
  333. static void destroyClass() ;
  334. LLPrivateMemoryPool* newPool(S32 type) ;
  335. void deletePool(LLPrivateMemoryPool* pool) ;
  336. private:
  337. std::vector<LLPrivateMemoryPool*> mPoolList ;
  338. U32 mMaxPrivatePoolSize;
  339. static LLPrivateMemoryPoolManager* sInstance ;
  340. static BOOL sPrivatePoolEnabled;
  341. static std::vector<LLPrivateMemoryPool*> sDanglingPoolList ;
  342. public:
  343. //debug and statistics info.
  344. void updateStatistics() ;
  345. U32 mTotalReservedSize ;
  346. U32 mTotalAllocatedSize ;
  347. public:
  348. #if __DEBUG_PRIVATE_MEM__
  349. static char* allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) ;
  350. typedef std::map<char*, std::string> mem_allocation_info_t ;
  351. static mem_allocation_info_t sMemAllocationTracker;
  352. #else
  353. static char* allocate(LLPrivateMemoryPool* poolp, U32 size) ;
  354. #endif
  355. static void freeMem(LLPrivateMemoryPool* poolp, void* addr) ;
  356. };
  357. //-------------------------------------------------------------------------------------
  358. #if __DEBUG_PRIVATE_MEM__
  359. #define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size), __FUNCTION__, __LINE__)
  360. #else
  361. #define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size))
  362. #endif
  363. #define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr))
  364. //-------------------------------------------------------------------------------------
  365. //
  366. //the below singleton is used to test the private memory pool.
  367. //
  368. #if 0
  369. class LL_COMMON_API LLPrivateMemoryPoolTester
  370. {
  371. private:
  372. LLPrivateMemoryPoolTester() ;
  373. ~LLPrivateMemoryPoolTester() ;
  374. public:
  375. static LLPrivateMemoryPoolTester* getInstance() ;
  376. static void destroy() ;
  377. void run(S32 type) ;
  378. private:
  379. void correctnessTest() ;
  380. void performanceTest() ;
  381. void fragmentationtest() ;
  382. void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ;
  383. void testAndTime(U32 size, U32 times) ;
  384. #if 0
  385. public:
  386. void* operator new(size_t size)
  387. {
  388. return (void*)sPool->allocate(size) ;
  389. }
  390. void operator delete(void* addr)
  391. {
  392. sPool->freeMem(addr) ;
  393. }
  394. void* operator new[](size_t size)
  395. {
  396. return (void*)sPool->allocate(size) ;
  397. }
  398. void operator delete[](void* addr)
  399. {
  400. sPool->freeMem(addr) ;
  401. }
  402. #endif
  403. private:
  404. static LLPrivateMemoryPoolTester* sInstance;
  405. static LLPrivateMemoryPool* sPool ;
  406. static LLPrivateMemoryPool* sThreadedPool ;
  407. };
  408. #if 0
  409. //static
  410. void* LLPrivateMemoryPoolTester::operator new(size_t size)
  411. {
  412. return (void*)sPool->allocate(size) ;
  413. }
  414. //static
  415. void LLPrivateMemoryPoolTester::operator delete(void* addr)
  416. {
  417. sPool->free(addr) ;
  418. }
  419. //static
  420. void* LLPrivateMemoryPoolTester::operator new[](size_t size)
  421. {
  422. return (void*)sPool->allocate(size) ;
  423. }
  424. //static
  425. void LLPrivateMemoryPoolTester::operator delete[](void* addr)
  426. {
  427. sPool->free(addr) ;
  428. }
  429. #endif
  430. #endif
  431. // LLRefCount moved to llrefcount.h
  432. // LLPointer moved to llpointer.h
  433. // LLSafeHandle moved to llsafehandle.h
  434. // LLSingleton moved to llsingleton.h
  435. #endif