From f4ff1430f0d6ae7dd5a6be0bd665678b30a63aca Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 3 Dec 2010 22:16:16 -0700 Subject: first iteration of memory pool code --- indra/llcommon/llmemory.h | 174 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 2 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 9bf4248bb7..d9e93d0e96 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -26,8 +26,6 @@ #ifndef LLMEMORY_H #define LLMEMORY_H - - extern S32 gTotalDAlloc; extern S32 gTotalDAUse; extern S32 gDACount; @@ -44,8 +42,180 @@ public: // Return the resident set size of the current process, in bytes. // Return value is zero if not known. static U64 getCurrentRSS(); + + static void* tryToAlloc(void* address, U32 size); + static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure); + static void updateMemoryInfo() ; + static void logMemoryInfo(BOOL update = FALSE); + static S32 isMemoryPoolLow(); + + static U32 getAvailableMemKB() ; + static U32 getMaxMemKB() ; + static U32 getAllocatedMemKB() ; private: static char* reserveMem; + static U32 sAvailPhysicalMemInKB ; + static U32 sMaxPhysicalMemInKB ; + static U32 sAllocatedMemInKB; + static U32 sAllocatedPageSizeInKB ; + + static U32 sMaxHeapSizeInKB; + static BOOL sEnableMemoryFailurePrevention; +}; + +class LL_COMMON_API LLPrivateMemoryPool +{ +public: + class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly + { + public: + LLMemoryBlock() ; + ~LLMemoryBlock() ; + + void init(char* buffer, U32 buffer_size, U32 slot_size) ; + void setBuffer(char* buffer, U32 buffer_size) ; + + char* allocate() ; + void free(void* addr) ; + + bool empty() {return !mAllocatedSlots;} + bool isFull() {return mAllocatedSlots == mTotalSlots;} + bool isFree() {return !mTotalSlots;} + + U32 getSlotSize()const {return mSlotSize;} + U32 getTotalSlots()const {return mTotalSlots;} + U32 getBufferSize()const {return mBufferSize;} + char* getBuffer() const {return mBuffer;} + + private: + char* mBuffer; + U32 mSlotSize ; //when the block is not initialized, it is the buffer size. + U32 mBufferSize ; + U32 mUsageBits ; + U8 mTotalSlots ; + U8 mAllocatedSlots ; + U8 mDummySize ; //size of extra U32 reserved for mUsageBits. + + public: + LLMemoryBlock* mPrev ; + LLMemoryBlock* mNext ; + LLMemoryBlock* mSelf ; + }; + + class LL_COMMON_API LLMemoryChunk //is divided into memory blocks. + { + public: + LLMemoryChunk() ; + ~LLMemoryChunk() ; + + void init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) ; + void setBuffer(char* buffer, U32 buffer_size) ; + + bool empty() ; + + char* allocate(U32 size) ; + void free(void* addr) ; + + const char* getBuffer() const {return mBuffer;} + U32 getBufferSize() const {return mBufferSize;} + + static U32 getMaxOverhead(U32 data_buffer_size, U32 min_page_size) ; + + private: + LLMemoryBlock* addBlock(U32 blk_idx) ; + void popAvailBlockList(U32 blk_idx) ; + void addToFreeSpace(LLMemoryBlock* blk) ; + void removeFromFreeSpace(LLMemoryBlock* blk) ; + void removeBlock(LLMemoryBlock* blk) ; + void addToAvailBlockList(LLMemoryBlock* blk) ; + LLMemoryBlock* createNewBlock(LLMemoryBlock** cur_idxp, U32 buffer_size, U32 slot_size, U32 blk_idx) ; + + private: + LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize + LLMemoryBlock** mFreeSpaceList; + LLMemoryBlock* mBlocks ; //index of blocks by address. + + char* mBuffer ; + U32 mBufferSize ; + char* mDataBuffer ; + char* mMetaBuffer ; + U32 mMinBlockSize ; + U32 mMaxBlockSize; + U32 mMinSlotSize ; + U16 mBlockLevels; + U16 mPartitionLevels; + + public: + //form a linked list + LLMemoryChunk* mNext ; + LLMemoryChunk* mPrev ; + + U32 mKey ; //= mBuffer + } ; + +public: + LLPrivateMemoryPool(U32 max_size, bool threaded) ; + ~LLPrivateMemoryPool() ; + + char *allocate(U32 size) ; + void free(void* addr) ; + void dump() ; + +private: + void lock() ; + void unlock() ; + S32 getChunkIndex(U32 size) ; + LLMemoryChunk* addChunk(S32 chunk_index) ; + void removeChunk(LLMemoryChunk* chunk) ; + U16 findChunk(const char* addr) ; + void destroyPool() ; + +private: + LLMutex* mMutexp ; + U32 mMaxPoolSize; + U32 mReservedPoolSize ; + + enum + { + SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB. + MEDIUM_ALLOCATION, //from 2KB to 512KB(exclusive), page size 32KB, max chunk size 4MB + LARGE_ALLOCATION, //from 512KB to 4MB(inclusive), page size 64KB, max chunk size 16MB + SUPER_ALLOCATION //allocation larger than 4MB. + }; + + LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address + std::vector mChunks ; + U16 mNumOfChunks ; + U16 mChunkVectorCapacity ; +}; + +// +//the below singleton is used to test the private memory pool. +// +class LLPrivateMemoryPoolTester +{ +private: + LLPrivateMemoryPoolTester() ; + ~LLPrivateMemoryPoolTester() ; + +public: + static LLPrivateMemoryPoolTester* getInstance() ; + static void destroy() ; + + void run() ; + +private: + void correctnessTest() ; + void reliabilityTest() ; + void performanceTest() ; + void fragmentationtest() ; + + void* operator new(size_t); + void operator delete(void*); + +private: + static LLPrivateMemoryPoolTester* sInstance; + static LLPrivateMemoryPool* sPool ; }; // LLRefCount moved to llrefcount.h -- cgit v1.3 From 43f4429363e63484f35663c10ca993d0d812e855 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 8 Dec 2010 20:50:39 -0700 Subject: test code and some code change --- indra/llcommon/llmemory.cpp | 251 +++++++++++++++++++++++++++++++++++------- indra/llcommon/llmemory.h | 62 ++++++++++- indra/newview/llappviewer.cpp | 4 + 3 files changed, 273 insertions(+), 44 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index ca06589611..a659e84309 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -40,7 +40,7 @@ #include "llmemory.h" #include "llsys.h" - +#include "llframetimer.h" //---------------------------------------------------------------------------- @@ -505,6 +505,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 { mBuffer = buffer ; mBufferSize = buffer_size ; + mAlloatedSize = 0 ; mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ; @@ -552,18 +553,16 @@ U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) { char* p = NULL ; - U32 blk_idx = size / mMinSlotSize ; - if(mMinSlotSize * blk_idx < size) - { - blk_idx++ ; - } + U32 blk_idx = getBlockLevel(size); + + LLMemoryBlock* blk = NULL ; //check if there is free block available if(mAvailBlockList[blk_idx]) { - LLMemoryBlock* blk = mAvailBlockList[blk_idx] ; + blk = mAvailBlockList[blk_idx] ; p = blk->allocate() ; - + if(blk->isFull()) { //removeFromFreelist @@ -574,7 +573,7 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) //ask for a new block if(!p) { - LLMemoryBlock* blk = addBlock(blk_idx) ; + blk = addBlock(blk_idx) ; if(blk) { p = blk->allocate() ; @@ -594,7 +593,7 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) { if(mAvailBlockList[i]) { - LLMemoryBlock* blk = mAvailBlockList[i] ; + blk = mAvailBlockList[i] ; p = blk->allocate() ; if(blk->isFull()) @@ -607,16 +606,23 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) } } + if(p && blk) + { + mAlloatedSize += blk->getSlotSize() ; + } return p ; } void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) { - LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + (((char*)addr - mDataBuffer) / mMinBlockSize) * sizeof(LLMemoryBlock)) ; + U32 blk_idx = ((U32)addr - (U32)mDataBuffer) / mMinBlockSize ; + if(blk_idx > 0) blk_idx-- ; + LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; blk = blk->mSelf ; bool was_full = blk->isFull() ; blk->free(addr) ; + mAlloatedSize -= blk->getSlotSize() ; if(blk->empty()) { @@ -628,13 +634,18 @@ void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) } } +bool LLPrivateMemoryPool::LLMemoryChunk::empty() +{ + return !mAlloatedSize ; +} + LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx) { U32 slot_size = mMinSlotSize * (blk_idx + 1) ; U32 preferred_block_size = llmax(mMinBlockSize, slot_size * 32) ; preferred_block_size = llmin(preferred_block_size, mMaxBlockSize) ; - U32 idx = preferred_block_size / mMinBlockSize ; + U32 idx = preferred_block_size / mMinBlockSize - 1; preferred_block_size = idx * mMinBlockSize ; //round to integer times of mMinBlockSize. LLMemoryBlock* blk = NULL ; @@ -710,7 +721,10 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe else { *cur_idxp = blk->mNext ; //move to the next slot - (*cur_idxp)->mPrev = NULL ; + if(*cur_idxp) + { + (*cur_idxp)->mPrev = NULL ; + } addToFreeSpace(next_blk) ; } @@ -718,7 +732,10 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe else //move to the next block { *cur_idxp = blk->mNext ; - (*cur_idxp)->mPrev = NULL ; + if(*cur_idxp) + { + (*cur_idxp)->mPrev = NULL ; + } } //insert to the available block list... @@ -791,7 +808,9 @@ void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx) void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) { - U16 free_idx = blk->getBufferSize() / mMinBlockSize ; + U16 free_idx = blk->getBufferSize() / mMinBlockSize; + if(free_idx > 0) free_idx--; + (blk + free_idx)->mSelf = blk ; //mark the end pointing back to the head. free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; @@ -809,7 +828,8 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) { - U16 free_idx = blk->getBufferSize() / mMinBlockSize ; + U16 free_idx = blk->getBufferSize() / mMinBlockSize; + if(free_idx > 0) free_idx-- ; free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; if(mFreeSpaceList[free_idx] == blk) @@ -830,7 +850,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) { - U32 blk_idx = blk->getSlotSize() / mMinSlotSize ; + U32 blk_idx = getBlockLevel(blk->getSlotSize()); blk->mNext = mAvailBlockList[blk_idx] ; if(blk->mNext) @@ -842,6 +862,16 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) return ; } +U32 LLPrivateMemoryPool::LLMemoryChunk::getBlockLevel(U32 size) +{ + return (size + mMinSlotSize - 1) / mMinSlotSize - 1 ; +} + +U32 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) +{ + return (size + mMinBlockSize - 1) / mMinBlockSize - 1 ; +} + //------------------------------------------------------------------- //class LLPrivateMemoryPool //-------------------------------------------------------------------- @@ -875,6 +905,11 @@ char* LLPrivateMemoryPool::allocate(U32 size) { const static U32 MAX_BLOCK_SIZE = 4 * 1024 * 1024 ; //4MB + if(!size) + { + return NULL ; + } + //if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it if(size >= MAX_BLOCK_SIZE) { @@ -902,7 +937,10 @@ char* LLPrivateMemoryPool::allocate(U32 size) if(!p) { chunk = addChunk(chunk_idx) ; - p = chunk->allocate(size) ; + if(chunk) + { + p = chunk->allocate(size) ; + } } unlock() ; @@ -912,6 +950,11 @@ char* LLPrivateMemoryPool::allocate(U32 size) void LLPrivateMemoryPool::free(void* addr) { + if(!addr) + { + return ; + } + lock() ; LLMemoryChunk* chunk = mChunks[findChunk((char*)addr)] ; @@ -1116,7 +1159,7 @@ LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::getInstance() { if(!sInstance) { - sInstance = new LLPrivateMemoryPoolTester() ; + sInstance = ::new LLPrivateMemoryPoolTester() ; } return sInstance ; } @@ -1126,51 +1169,181 @@ void LLPrivateMemoryPoolTester::destroy() { if(sInstance) { - delete sInstance ; + ::delete sInstance ; sInstance = NULL ; } if(sPool) { - delete sPool ; + ::delete sPool ; sPool = NULL ; } } -void LLPrivateMemoryPoolTester::run() +void LLPrivateMemoryPoolTester::run(bool threaded) { const U32 max_pool_size = 16 << 20 ; - const bool threaded = false ; - if(!sPool) + + if(sPool) { - sPool = new LLPrivateMemoryPool(max_pool_size, threaded) ; + ::delete sPool ; } + sPool = ::new LLPrivateMemoryPool(max_pool_size, threaded) ; //run the test correctnessTest() ; - reliabilityTest() ; performanceTest() ; fragmentationtest() ; + + //release pool. + ::delete sPool ; + sPool = NULL ; +} + +void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 times, + bool random_deletion, bool output_statistics) +{ + U32 levels = (max_size - min_size) / stride + 1 ; + char*** p ; + U32 i, j ; + + //allocate space for p ; + if(!(p = ::new char**[times]) || !(*p = ::new char*[times * levels])) + { + llerrs << "memory initialization for p failed" << llendl ; + } + + //init + for(i = 0 ; i < times; i++) + { + p[i] = *p + i * levels ; + for(j = 0 ; j < levels; j++) + { + p[i][j] = NULL ; + } + } + + //allocation + U32 size ; + for(i = 0 ; i < times ; i++) + { + for(j = 0 ; j < levels; j++) + { + size = min_size + j * stride ; + p[i][j] = sPool->allocate(size) ; + p[i][j][size - 1] = '\0' ; //access the last element to verify the success of the allocation. + + //randomly release memory + if(random_deletion) + { + S32 k = rand() % levels ; + sPool->free(p[i][k]) ; + p[i][k] = NULL ; + } + } + } + + //output pool allocation statistics + if(output_statistics) + { + } + + //release all memory allocations + for(i = 0 ; i < times; i++) + { + for(j = 0 ; j < levels; j++) + { + sPool->free(p[i][j]) ; + p[i][j] = NULL ; + } + } + + ::delete[] *p ; + ::delete[] p ; } void LLPrivateMemoryPoolTester::correctnessTest() { - //try many different sized allocation, fill the memory fully to see if allocation is right. + //try many different sized allocation, and all kinds of edge cases, access the allocated memory + //to see if allocation is right. + + //edge case + char* p = sPool->allocate(0) ; + sPool->free(p) ; + + //small sized + // [8 bytes, 2KB), each asks for 256 allocations and deallocations + test(8, 2040, 8, 256, true, true) ; + + //medium sized + //[2KB, 512KB), each asks for 16 allocations and deallocations + test(2048, 512 * 1024 - 2048, 2048, 16, true, true) ; + //large sized + //[512KB, 4MB], each asks for 8 allocations and deallocations + test(512 * 1024, 4 * 1024 * 1024, 64 * 1024, 8, true, true) ; } -void LLPrivateMemoryPoolTester::reliabilityTest() void LLPrivateMemoryPoolTester::performanceTest() +{ + U32 test_size[3] = {768, 3* 1024, 3* 1024 * 1024}; + + S32 i ; + LLFrameTimer timer ; + + //do 1024 various-sized allocations / deallocations, compare the performance with the normal ones. + + //small sized + { + timer.reset() ; + char* p[1024] = {NULL} ; + for(i = 0 ; i < 1024; i++) + { + p[i] = sPool->allocate(test_size[0]) ; + if(!p[i]) + { + llerrs << "allocation failed" << llendl ; + } + } + + for(i = 0 ; i < 1024; i++) + { + sPool->free(p[i]) ; + p[i] = NULL ; + } + llinfos << "time spent on 1024 small allocations: %f " << timer.getElapsedTimeF32() << llendl ; + + timer.reset() ; + + //using the standard allocator/de-allocator: + for(i = 0 ; i < 1024; i++) + { + p[i] = ::new char[test_size[0]] ; + if(!p[i]) + { + llerrs << "allocation failed" << llendl ; + } + } + + for(i = 0 ; i < 1024; i++) + { + ::delete[] p[i] ; + p[i] = NULL ; + } + llinfos << "time spent on 1024 small allocations: %f using standard allocator/de-allocator." << timer.getElapsedTimeF32() << llendl ; + + timer.reset() ; + } + //medium sized + + //large sized +} + void LLPrivateMemoryPoolTester::fragmentationtest() +{ + //for internal fragmentation statistics: + //every time when asking for a new chunk during correctness test, and performance test, + //print out the chunk usage statistices. +} -void* LLPrivateMemoryPoolTester::operator new(size_t size) -{ - return (void*)sPool->allocate(size) ; -} - -void LLPrivateMemoryPoolTester::operator delete(void* addr) -{ - sPool->free(addr) ; -} - -//-------------------------------------------------------------------- +//-------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index d9e93d0e96..128e7aefe6 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -63,6 +63,14 @@ private: static BOOL sEnableMemoryFailurePrevention; }; +// +//class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not +//need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster, +//and reduces virtaul address space gragmentation problem. +//Note: this class is thread-safe by passing true to the constructor function. However, you do not need to do this unless +//you are sure the memory allocation and de-allocation will happen in different threads. To make the pool thread safe +//increases allocation and deallocation cost. +// class LL_COMMON_API LLPrivateMemoryPool { public: @@ -122,6 +130,8 @@ public: static U32 getMaxOverhead(U32 data_buffer_size, U32 min_page_size) ; private: + U32 getBlockLevel(U32 size) ; + U32 getPageLevel(U32 size) ; LLMemoryBlock* addBlock(U32 blk_idx) ; void popAvailBlockList(U32 blk_idx) ; void addToFreeSpace(LLMemoryBlock* blk) ; @@ -142,6 +152,7 @@ public: U32 mMinBlockSize ; U32 mMaxBlockSize; U32 mMinSlotSize ; + U32 mAlloatedSize ; U16 mBlockLevels; U16 mPartitionLevels; @@ -192,7 +203,7 @@ private: // //the below singleton is used to test the private memory pool. // -class LLPrivateMemoryPoolTester +class LL_COMMON_API LLPrivateMemoryPoolTester { private: LLPrivateMemoryPoolTester() ; @@ -202,22 +213,63 @@ public: static LLPrivateMemoryPoolTester* getInstance() ; static void destroy() ; - void run() ; + void run(bool threaded) ; private: void correctnessTest() ; - void reliabilityTest() ; void performanceTest() ; void fragmentationtest() ; - void* operator new(size_t); - void operator delete(void*); + void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ; + +public: + void* operator new(size_t size) + { + return (void*)sPool->allocate(size) ; + } + void operator delete(void* addr) + { + sPool->free(addr) ; + } + void* operator new[](size_t size) + { + return (void*)sPool->allocate(size) ; + } + void operator delete[](void* addr) + { + sPool->free(addr) ; + } private: static LLPrivateMemoryPoolTester* sInstance; static LLPrivateMemoryPool* sPool ; + static LLPrivateMemoryPool* sThreadedPool ; }; +#if 0 +//static +void* LLPrivateMemoryPoolTester::operator new(size_t size) +{ + return (void*)sPool->allocate(size) ; +} + +//static +void LLPrivateMemoryPoolTester::operator delete(void* addr) +{ + sPool->free(addr) ; +} +//static +void* LLPrivateMemoryPoolTester::operator new[](size_t size) +{ + return (void*)sPool->allocate(size) ; +} + +//static +void LLPrivateMemoryPoolTester::operator delete[](void* addr) +{ + sPool->free(addr) ; +} +#endif // LLRefCount moved to llrefcount.h // LLPointer moved to llpointer.h diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 84e36ac3c7..fd7e1eda7f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1087,6 +1087,10 @@ bool LLAppViewer::mainLoop() // point of posting. LLSD newFrame; + LLPrivateMemoryPoolTester::getInstance()->run(false) ; + LLPrivateMemoryPoolTester::getInstance()->run(true) ; + LLPrivateMemoryPoolTester::destroy() ; + // Handle messages while (!LLApp::isExiting()) { -- cgit v1.3 From 5654abd50d834c3a7d0efb5dde393ff34f09be17 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 4 Jan 2011 13:14:36 -0700 Subject: a wroking version with a lot of debugging code (to be removed). --- indra/llcommon/llmemory.cpp | 770 ++++++++++++++++++++++++++++++++++---------- indra/llcommon/llmemory.h | 50 ++- 2 files changed, 636 insertions(+), 184 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index a659e84309..00ef09d7a2 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -356,6 +356,22 @@ U64 LLMemory::getCurrentRSS() #endif +//------------------------------------------------------------- +//minimum block sizes (page size) for small allocation, medium allocation, large allocation +const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 << 10, 16 << 10} ; // + +//maximum block sizes for small allocation, medium allocation, large allocation +const U32 MAX_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ; + +//minimum slot sizes for small allocation, medium allocation, large allocation +const U32 MIN_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {8, 2 << 10, 512 << 10}; + +//maximum slot sizes for small allocation, medium allocation, large allocation +const U32 MAX_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {(2 << 10) - 8, (512 - 2) << 10, 4 << 20}; + +//size of a block with multiple slots can not exceed CUT_OFF_SIZE +const U32 CUT_OFF_SIZE = (64 << 10) ; //64 KB + //------------------------------------------------------------- //class LLPrivateMemoryPool::LLMemoryBlock //------------------------------------------------------------- @@ -375,6 +391,8 @@ LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock() void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size) { + llassert_always(buffer_size >= slot_size) ; + mBuffer = buffer ; mBufferSize = buffer_size ; mSlotSize = slot_size ; @@ -414,14 +432,20 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 } } - mSelf = NULL ; + mSelf = this ; mNext = NULL ; + mPrev = NULL ; + + llassert_always(mTotalSlots > 0) ; } void LLPrivateMemoryPool::LLMemoryBlock::setBuffer(char* buffer, U32 buffer_size) { + llassert_always(buffer_size <= (16 << 20)) ; + mBuffer = buffer ; mBufferSize = buffer_size ; + mSelf = NULL ; mTotalSlots = 0 ; //set the block is free. } @@ -455,27 +479,47 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() //set the slot reserved if(!idx) { + llassert_always(!(*bits & 1)); *bits |= 1 ; } else { + llassert_always(!(*bits & (1 << idx))) ; *bits |= (1 << idx) ; } mAllocatedSlots++ ; + + //return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; - return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; + char* p = mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; + llassert_always(mBuffer != p || !mDummySize) ; + llassert_always(*(U32*)p == 0 && *((U32*)p + 1) == 0) ; + + return p ; } +U32 col = 0, row = 0 ; void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) { - U32 idx = ((char*) addr - mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; + llassert_always((U32)addr >= (U32)mBuffer + mDummySize * sizeof(U32) && + (U32)addr < (U32)mBuffer + mBufferSize) ; + + U32 idx = ((U32)addr - (U32)mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; + + llassert_always(idx < mTotalSlots) ; + llassert_always(addr == mBuffer + mDummySize * sizeof(U32) + idx * mSlotSize) ; + llassert_always(*(U32*)addr == col && *((U32*)addr + 1) == row) ; + + *(U32*)addr = 0 ; + *((U32*)addr + 1) = 0 ; U32* bits = &mUsageBits ; - if(idx > 32) + if(idx >= 32) { bits = (U32*)mBuffer + (idx - 32) / 32 ; } + if(idx & 31) { *bits &= ~(1 << (idx & 31)) ; @@ -488,6 +532,15 @@ void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) mAllocatedSlots-- ; } +//for debug use +void LLPrivateMemoryPool::LLMemoryBlock::resetBitMap() +{ + for(S32 i = 0 ; i < mDummySize ; i++) + { + *((U32*)mBuffer + i) = 0 ; + } + mUsageBits = 0 ; +} //------------------------------------------------------------------- //class LLMemoryChunk //-------------------------------------------------------------------- @@ -510,10 +563,10 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ; mMinBlockSize = min_block_size; - mMaxBlockSize = max_block_size; mMinSlotSize = min_slot_size; - mBlockLevels = max_block_size / min_block_size ; - mPartitionLevels = mMaxBlockSize / mMinBlockSize + 1 ; + mMaxSlotSize = max_slot_size ; + mBlockLevels = mMaxSlotSize / mMinSlotSize ; + mPartitionLevels = max_block_size / mMinBlockSize + 1 ; S32 max_num_blocks = (buffer_size - sizeof(LLMemoryChunk) - mBlockLevels * sizeof(LLMemoryBlock*) - mPartitionLevels * sizeof(LLMemoryBlock*)) / (mMinBlockSize + sizeof(LLMemoryBlock)) ; @@ -535,10 +588,20 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 mFreeSpaceList[i] = NULL ; } + mBlocks[0].mPrev = NULL ; + mBlocks[0].mNext = NULL ; mBlocks[0].setBuffer(mDataBuffer, buffer_size - (mDataBuffer - mBuffer)) ; + + //debug + U32 end = (mBlocks[0].getBufferSize() / mMinBlockSize) ; + for(U32 i = 1 ; i < end ; i++) + { + mBlocks[i].mSelf = NULL ; + } + addToFreeSpace(&mBlocks[0]) ; - mKey = (U32)mBuffer ; + mHashNext = NULL ; mNext = NULL ; mPrev = NULL ; } @@ -546,8 +609,14 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 //static U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_page_size) { - return 2048 + - sizeof(LLMemoryBlock) * (data_buffer_size / min_page_size) ; + if(data_buffer_size / min_page_size < 64) //large allocations + { + return 4096 ; //4KB + } + else + { + return 0 ; //do not reserve extra overhead if for small allocations + } } char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) @@ -565,7 +634,6 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) if(blk->isFull()) { - //removeFromFreelist popAvailBlockList(blk_idx) ; } } @@ -580,7 +648,6 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) if(blk->isFull()) { - //removeFromFreelist popAvailBlockList(blk_idx) ; } } @@ -598,7 +665,6 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) if(blk->isFull()) { - //removeFromFreelist popAvailBlockList(i) ; } break ; @@ -606,8 +672,18 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) } } + llassert_always(!p || blk) ; + if(p && blk) { + if(blk->getTotalSlots() == 1) + { + llassert_always(blk->getBuffer() == (char*)p) ; + } + U32 blk_idx = getPageIndex((U32)p) ; + LLMemoryBlock* b = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; + llassert_always(blk == b || b->mSelf == blk) ; + mAlloatedSize += blk->getSlotSize() ; } return p ; @@ -615,23 +691,34 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) { - U32 blk_idx = ((U32)addr - (U32)mDataBuffer) / mMinBlockSize ; - if(blk_idx > 0) blk_idx-- ; + U32 blk_idx = getPageIndex((U32)addr) ; LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; + llassert_always(blk->mSelf) ; blk = blk->mSelf ; + llassert_always(addr >= blk->getBuffer() && addr < blk->getBuffer() + blk->getBufferSize()) ; + if(blk->getTotalSlots() == 1) + { + llassert_always(blk->getBuffer() == (char*)addr) ; + } + bool was_full = blk->isFull() ; blk->free(addr) ; mAlloatedSize -= blk->getSlotSize() ; if(blk->empty()) { + blk->resetBitMap() ; //debug use removeBlock(blk) ; + + dump(); } else if(was_full) { addToAvailBlockList(blk) ; - } + + dump(); + } } bool LLPrivateMemoryPool::LLMemoryChunk::empty() @@ -639,35 +726,170 @@ bool LLPrivateMemoryPool::LLMemoryChunk::empty() return !mAlloatedSize ; } +bool LLPrivateMemoryPool::LLMemoryChunk::containsAddress(const char* addr) const +{ + return (U32)mBuffer <= (U32)addr && (U32)mBuffer + mBufferSize > (U32)addr ; +} + +void LLPrivateMemoryPool::LLMemoryChunk::dump() +{ + //sanity check + std::vector< LLMemoryBlock* > blk_list ; + for(std::set::iterator iter = mActiveBlockList.begin() ; iter != mActiveBlockList.end(); ++iter) + { + blk_list.push_back(*iter) ; + } + //for(S32 i = 0 ; i < mBlockLevels ; i++) + //{ + // LLMemoryBlock* blk = mAvailBlockList[i] ; + // while(blk) + // { + // blk_list.push_back(blk) ; + // blk = blk->mNext ; + // } + //} + for(S32 i = 0 ; i < mPartitionLevels ; i++) + { + LLMemoryBlock* blk = mFreeSpaceList[i] ; + while(blk) + { + blk_list.push_back(blk) ; + blk = blk->mNext ; + } + } + + std::sort(blk_list.begin(), blk_list.end(), LLMemoryBlock::CompareAddress()); + + U32 total_size = blk_list[0]->getBufferSize() ; + for(U32 i = 1 ; i < blk_list.size(); i++) + { + total_size += blk_list[i]->getBufferSize() ; + if((U32)blk_list[i]->getBuffer() < (U32)blk_list[i-1]->getBuffer() + blk_list[i-1]->getBufferSize()) + { + llerrs << "buffer corrupted." << llendl ; + } + } + + llassert_always(total_size + mMinBlockSize >= mBufferSize - ((U32)mDataBuffer - (U32)mBuffer)) ; + + U32 blk_num = (mBufferSize - (mDataBuffer - mBuffer)) / mMinBlockSize ; + for(U32 i = 0 ; i < blk_num ; ) + { + LLMemoryBlock* blk = &mBlocks[i] ; + if(blk->mSelf) + { + U32 end = blk->getBufferSize() / mMinBlockSize ; + for(U32 j = 0 ; j < end ; j++) + { + llassert_always(blk->mSelf == blk || !blk->mSelf) ; + } + i += end ; + } + else + { + llerrs << "gap happens" << llendl ; + } + } +#if 0 + llinfos << "---------------------------" << llendl ; + llinfos << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << llendl ; + + llinfos << "available blocks ... " << llendl ; + for(S32 i = 0 ; i < mBlockLevels ; i++) + { + LLMemoryBlock* blk = mAvailBlockList[i] ; + while(blk) + { + llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; + blk = blk->mNext ; + } + } + + llinfos << "free blocks ... " << llendl ; + for(S32 i = 0 ; i < mPartitionLevels ; i++) + { + LLMemoryBlock* blk = mFreeSpaceList[i] ; + while(blk) + { + llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; + blk = blk->mNext ; + } + } +#endif +} + +U32 LLPrivateMemoryPool::LLMemoryChunk::calcBlockSize(U32 slot_size) +{ + // + //Note: we try to make a block to have 32 slots if the size is not over 32 pages + //32 is the number of bits of an integer in a 32-bit system + // + + U32 block_size; + U32 cut_off_size = llmin(CUT_OFF_SIZE, (U32)(mMinBlockSize << 5)) ; + + if((slot_size << 5) <= mMinBlockSize)//for small allocations, return one page + { + block_size = mMinBlockSize ; + } + else if(slot_size >= cut_off_size)//for large allocations, return one-slot block + { + block_size = (slot_size / mMinBlockSize) * mMinBlockSize ; + if(block_size < slot_size) + { + block_size += mMinBlockSize ; + } + } + else //medium allocations + { + if((slot_size << 5) >= cut_off_size) + { + block_size = cut_off_size ; + } + else + { + block_size = ((slot_size << 5) / mMinBlockSize) * mMinBlockSize ; + } + } + + llassert_always(block_size >= slot_size) ; + + return block_size ; +} + LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx) { U32 slot_size = mMinSlotSize * (blk_idx + 1) ; - U32 preferred_block_size = llmax(mMinBlockSize, slot_size * 32) ; - preferred_block_size = llmin(preferred_block_size, mMaxBlockSize) ; - - U32 idx = preferred_block_size / mMinBlockSize - 1; - preferred_block_size = idx * mMinBlockSize ; //round to integer times of mMinBlockSize. + U32 preferred_block_size = calcBlockSize(slot_size) ; + + U16 idx = getPageLevel(preferred_block_size); + llassert_always(idx < mPartitionLevels - 1) ; + llassert_always(preferred_block_size == (idx + 1) * mMinBlockSize) ; //round to integer times of mMinBlockSize. LLMemoryBlock* blk = NULL ; if(mFreeSpaceList[idx])//if there is free slot for blk_idx { - blk = createNewBlock(&mFreeSpaceList[idx], preferred_block_size, slot_size, blk_idx) ; + blk = createNewBlock(mFreeSpaceList[idx], preferred_block_size, slot_size, blk_idx) ; } else if(mFreeSpaceList[mPartitionLevels - 1]) //search free pool { - blk = createNewBlock(&mFreeSpaceList[mPartitionLevels - 1], preferred_block_size, slot_size, blk_idx) ; + blk = createNewBlock(mFreeSpaceList[mPartitionLevels - 1], preferred_block_size, slot_size, blk_idx) ; } else //search for other non-preferred but enough space slot. { - for(U32 i = idx - 1 ; i >= 0 ; i--) //search the small slots first + for(S32 i = (S32)idx - 1 ; i >= 0 ; i--) //search the small slots first { if(mFreeSpaceList[i]) { + U32 new_preferred_block_size = mFreeSpaceList[i]->getBufferSize(); + new_preferred_block_size = (new_preferred_block_size / mMinBlockSize) * mMinBlockSize ; //round to integer times of mMinBlockSize. + //create a NEW BLOCK THERE. - if(mFreeSpaceList[i]->getBufferSize() >= slot_size) //at least there is space for one slot. + if(new_preferred_block_size >= slot_size) //at least there is space for one slot. { - blk = createNewBlock(&mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; + + blk = createNewBlock(mFreeSpaceList[i], new_preferred_block_size, slot_size, blk_idx) ; } break ; } @@ -680,70 +902,72 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock if(mFreeSpaceList[i]) { //create a NEW BLOCK THERE. - blk = createNewBlock(&mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; + blk = createNewBlock(mFreeSpaceList[i], preferred_block_size, slot_size, blk_idx) ; break ; } } } } + dump() ; + return blk ; } -LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock** cur_idxp, U32 buffer_size, U32 slot_size, U32 blk_idx) +char* _prev = NULL ; +LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) { - LLMemoryBlock* blk = *cur_idxp ; - - buffer_size = llmin(buffer_size, blk->getBufferSize()) ; - U32 new_free_blk_size = blk->getBufferSize() - buffer_size ; - if(new_free_blk_size < mMinBlockSize) //can not partition the memory into size smaller than mMinBlockSize + llassert_always(blk->getBufferSize() >= buffer_size) ; + + //debug { - buffer_size += new_free_blk_size ; - new_free_blk_size = 0 ; + { + U32 blk_idx = getPageIndex((U32)blk->getBuffer()) ; + llassert_always(blk == (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock))) ; + } + U32 end = (blk->getBufferSize() / mMinBlockSize) ; + llassert_always(blk->mSelf == blk && blk->isFree()) ; + llassert_always((blk + end - 1)->mSelf == blk) ; + for(U32 i = 1 ; i < end - 1; i++) + { + llassert_always(!(blk + i)->mSelf) ; + } } - blk->init(blk->getBuffer(), buffer_size, slot_size) ; - - if(new_free_blk_size > 0) //cur_idx still has free space + + //unlink from the free space + removeFromFreeSpace(blk) ; + + //check the rest space + U32 new_free_blk_size = blk->getBufferSize() - buffer_size ; + if(new_free_blk_size < mMinBlockSize) //can not partition the memory into size smaller than mMinBlockSize + { + new_free_blk_size = 0 ; //discard the last small extra space. + } + + //add the rest space back to the free list + if(new_free_blk_size > 0) //blk still has free space { LLMemoryBlock* next_blk = blk + (buffer_size / mMinBlockSize) ; next_blk->setBuffer(blk->getBuffer() + buffer_size, new_free_blk_size) ; - - if(new_free_blk_size > mMaxBlockSize) //stays in the free pool - { - next_blk->mPrev = NULL ; - next_blk->mNext = blk->mNext ; - if(next_blk->mNext) - { - next_blk->mNext->mPrev = next_blk ; - } - *cur_idxp = next_blk ; - } - else - { - *cur_idxp = blk->mNext ; //move to the next slot - if(*cur_idxp) - { - (*cur_idxp)->mPrev = NULL ; - } - addToFreeSpace(next_blk) ; - } - } - else //move to the next block - { - *cur_idxp = blk->mNext ; - if(*cur_idxp) { - (*cur_idxp)->mPrev = NULL ; + U32 blk_idx = getPageIndex((U32)next_blk->getBuffer()) ; + llassert_always(next_blk == (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock))) ; } + llassert_always(buffer_size == (buffer_size / mMinBlockSize) * mMinBlockSize) ; + llassert_always(((U32)next_blk->getBuffer() - (U32)mDataBuffer) == ((U32)next_blk->getBuffer() - (U32)mDataBuffer) / mMinBlockSize * mMinBlockSize) ; + addToFreeSpace(next_blk) ; } + blk->init(blk->getBuffer(), buffer_size, slot_size) ; //insert to the available block list... - blk->mNext = NULL ; - blk->mPrev = NULL ; - blk->mSelf = blk ; + llassert_always(!mAvailBlockList[blk_idx]) ; mAvailBlockList[blk_idx] = blk ; + llassert_always(blk->getTotalSlots() > 0) ; + llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; + llassert_always(buffer_size == (buffer_size / mMinBlockSize) * mMinBlockSize) ; + //mark the address map U32 end = (buffer_size / mMinBlockSize) ; for(U32 i = 1 ; i < end ; i++) @@ -751,6 +975,12 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe (blk + i)->mSelf = blk ; } + llassert_always(blk->getBuffer() != _prev) ; + + llassert_always(mActiveBlockList.find(blk) == mActiveBlockList.end()) ; + + mActiveBlockList.insert(blk) ; + return blk ; } @@ -765,29 +995,54 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) { blk->mNext->mPrev = blk->mPrev ; } + U32 blk_idx = getBlockLevel(blk->getSlotSize()); + if(mAvailBlockList[blk_idx] == blk) + { + mAvailBlockList[blk_idx] = blk->mNext ; + } + + blk->mNext = NULL ; + blk->mPrev = NULL ; + + std::set::iterator iter = mActiveBlockList.find(blk) ; + llassert_always(iter != mActiveBlockList.end()) ; + mActiveBlockList.erase(iter) ; //mark it free blk->setBuffer(blk->getBuffer(), blk->getBufferSize()) ; + //debug + U32 end = (blk->getBufferSize() / mMinBlockSize) ; + for(U32 i = 1 ; i < end ; i++) + { + llassert_always((blk + i)->mSelf == blk) ; + (blk + i)->mSelf = NULL ; + } +#if 0 //merge blk with neighbors if possible if(blk->getBuffer() > mDataBuffer) //has the left neighbor { if((blk - 1)->mSelf->isFree()) { + LLMemoryBlock* left_blk = (blk - 1)->mSelf ; removeFromFreeSpace((blk - 1)->mSelf); - (blk - 1)->mSelf->setBuffer((blk-1)->mSelf->getBuffer(), (blk-1)->mSelf->getBufferSize() + blk->getBufferSize()) ; - blk = (blk - 1)->mSelf ; + left_blk->setBuffer(left_blk->getBuffer(), left_blk->getBufferSize() + blk->getBufferSize()) ; + blk = left_blk ; } } - if(blk->getBuffer() + blk->getBufferSize() < mBuffer + mBufferSize) //has the right neighbor + if(blk->getBuffer() + blk->getBufferSize() <= mBuffer + mBufferSize - mMinBlockSize) //has the right neighbor { U32 d = blk->getBufferSize() / mMinBlockSize ; if((blk + d)->isFree()) { + LLMemoryBlock* right_blk = blk + d ; removeFromFreeSpace(blk + d) ; - blk->setBuffer(blk->getBuffer(), blk->getBufferSize() + (blk + d)->getBufferSize()) ; + blk->setBuffer(blk->getBuffer(), blk->getBufferSize() + right_blk->getBufferSize()) ; } } +#endif + llassert_always(blk->getBuffer() != _prev) ; + llassert_always(mActiveBlockList.find(blk) == mActiveBlockList.end()) ; addToFreeSpace(blk) ; @@ -800,16 +1055,29 @@ void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx) if(mAvailBlockList[blk_idx]) { LLMemoryBlock* next = mAvailBlockList[blk_idx]->mNext ; - next->mPrev = NULL ; + if(next) + { + next->mPrev = NULL ; + } + mAvailBlockList[blk_idx]->mPrev = NULL ; mAvailBlockList[blk_idx]->mNext = NULL ; mAvailBlockList[blk_idx] = next ; + if(next) + { + llassert_always(mAvailBlockList[blk_idx]->getTotalSlots() > 0) ; + llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; + } + + dump() ; } } void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) { - U16 free_idx = blk->getBufferSize() / mMinBlockSize; - if(free_idx > 0) free_idx--; + llassert_always(!blk->mPrev) ; + llassert_always(!blk->mNext) ; + + U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1; (blk + free_idx)->mSelf = blk ; //mark the end pointing back to the head. free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; @@ -828,8 +1096,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) { - U16 free_idx = blk->getBufferSize() / mMinBlockSize; - if(free_idx > 0) free_idx-- ; + U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1; free_idx = llmin(free_idx, (U16)(mPartitionLevels - 1)) ; if(mFreeSpaceList[free_idx] == blk) @@ -844,37 +1111,70 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) { blk->mNext->mPrev = blk->mPrev ; } - + blk->mNext = NULL ; + blk->mPrev = NULL ; + blk->mSelf = NULL ; + return ; } void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) { + llassert_always(!blk->mPrev) ; + llassert_always(!blk->mNext) ; + U32 blk_idx = getBlockLevel(blk->getSlotSize()); + llassert_always(blk->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; + blk->mNext = mAvailBlockList[blk_idx] ; if(blk->mNext) { blk->mNext->mPrev = blk ; } blk->mPrev = NULL ; - + mAvailBlockList[blk_idx] = blk ; + + llassert_always(mAvailBlockList[blk_idx]->getTotalSlots() > 0) ; + llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; + return ; } +U32 LLPrivateMemoryPool::LLMemoryChunk::getPageIndex(U32 addr) +{ + return (addr - (U32)mDataBuffer) / mMinBlockSize ; +} + +//for mAvailBlockList U32 LLPrivateMemoryPool::LLMemoryChunk::getBlockLevel(U32 size) { + llassert(size >= mMinSlotSize && size <= mMaxSlotSize) ; + + //start from 0 return (size + mMinSlotSize - 1) / mMinSlotSize - 1 ; } -U32 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) +//for mFreeSpaceList +U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) { - return (size + mMinBlockSize - 1) / mMinBlockSize - 1 ; + llassert_always(size >= mMinBlockSize); + llassert_always(!(size % mMinBlockSize)) ; + + //start from 0 + U16 level = size / mMinBlockSize - 1 ; + if(level >= mPartitionLevels) + { + level = mPartitionLevels - 1 ; + } + return level ; } //------------------------------------------------------------------- //class LLPrivateMemoryPool //-------------------------------------------------------------------- +const U32 CHUNK_SIZE = 4 << 20 ; //4 MB +const U32 HASH_FACTOR = 255 ; LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : mMutexp(NULL), mMaxPoolSize(max_size), @@ -890,8 +1190,12 @@ LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : mChunkList[i] = NULL ; } - mChunkVectorCapacity = 128 ; - mChunks.resize(mChunkVectorCapacity) ; //at most 128 chunks + mChunkHashList.resize(HASH_FACTOR + 1) ; + for(U32 i = 0 ; i <= HASH_FACTOR ; i++) + { + mChunkHashList[i] = NULL ; + } + mNumOfChunks = 0 ; } @@ -903,15 +1207,13 @@ LLPrivateMemoryPool::~LLPrivateMemoryPool() char* LLPrivateMemoryPool::allocate(U32 size) { - const static U32 MAX_BLOCK_SIZE = 4 * 1024 * 1024 ; //4MB - if(!size) { return NULL ; } //if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it - if(size >= MAX_BLOCK_SIZE) + if(size >= CHUNK_SIZE) { return new char[size] ; } @@ -936,6 +1238,19 @@ char* LLPrivateMemoryPool::allocate(U32 size) //fetch new memory chunk if(!p) { + if(mReservedPoolSize + CHUNK_SIZE > mMaxPoolSize) + { + chunk = mChunkList[chunk_idx]; + while(chunk) + { + if(p = chunk->allocate(size)) + { + break ; + } + chunk = chunk->mNext ; + } + } + chunk = addChunk(chunk_idx) ; if(chunk) { @@ -957,28 +1272,92 @@ void LLPrivateMemoryPool::free(void* addr) lock() ; - LLMemoryChunk* chunk = mChunks[findChunk((char*)addr)] ; + U16 key ; + LLMemoryChunk* chunk =findChunk((char*)addr, key) ; + if(!chunk) { delete[] (char*)addr ; //release from heap } else { + llassert_always((U32)addr >= (U32)chunk->getBuffer() && (U32)addr < (U32)chunk->getBuffer() + chunk->getBufferSize()) ; + chunk->free(addr) ; if(chunk->empty()) { - removeChunk(chunk) ; + removeChunk(chunk, key) ; } } unlock() ; } +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr, U16& key) +{ + key = findHashKey(addr) ; + + //check the hash value "key" + LLMemoryChunk* chunk = mChunkHashList[key] ; + while(chunk && !chunk->containsAddress(addr)) + { + chunk = chunk->mHashNext ; + } + + if(!chunk && key > 0) //check the "key - 1" + { + chunk = mChunkHashList[key - 1] ; + while(chunk && !chunk->containsAddress(addr)) + { + chunk = chunk->mHashNext ; + } + + if(chunk) + { + key-- ; + } + } + + if(!chunk && key < HASH_FACTOR) //check the "key + 1" + { + chunk = mChunkHashList[key + 1] ; + while(chunk && !chunk->containsAddress(addr)) + { + chunk = chunk->mHashNext ; + } + + if(chunk) + { + key++ ; + } + } + + return chunk ; +} + void LLPrivateMemoryPool::dump() { } +U32 LLPrivateMemoryPool::getTotalAllocatedSize() +{ + U32 total_allocated = 0 ; + + LLMemoryChunk* chunk ; + for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) + { + chunk = mChunkList[i]; + while(chunk) + { + total_allocated += chunk->getAllocatedSize() ; + chunk = chunk->mNext ; + } + } + + return total_allocated ; +} + void LLPrivateMemoryPool::lock() { if(mMutexp) @@ -997,58 +1376,72 @@ void LLPrivateMemoryPool::unlock() S32 LLPrivateMemoryPool::getChunkIndex(U32 size) { - if(size < 2048) - { - return 0 ; - } - else if(size < (512 << 10)) - { - return 1 ; - } - else - { - return 2 ; - } + S32 i ; + for(i = 0 ; size > MAX_SLOT_SIZES[i]; i++); + + llassert_always(i < SUPER_ALLOCATION); + + return i ; } //destroy the entire pool void LLPrivateMemoryPool::destroyPool() { - for(U16 i = 0 ; i < mNumOfChunks ; i++) + lock() ; + for(U32 i = 0 ; i <= HASH_FACTOR; i++) { - delete[] mChunks[i]->getBuffer() ; + while(mChunkHashList[i]) + { + removeChunk(mChunkHashList[i], i) ; + } } - mNumOfChunks = 0 ; + llassert_always(mNumOfChunks == 0) ; + llassert_always(mReservedPoolSize == 0) ; + for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) { mChunkList[i] = NULL ; } + + unlock() ; } -LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_index) +void LLPrivateMemoryPool::checkSize(U32 asked_size) { - static const U32 MIN_BLOCK_SIZES[SUPER_ALLOCATION] = {2 << 10, 32 << 10, 64 << 10} ; - static const U32 MAX_BLOCK_SIZES[SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ; - static const U32 MIN_SLOT_SIZES[SUPER_ALLOCATION] = {8, 2 << 10, 512 << 10}; - static const U32 MAX_SLOT_SIZES[SUPER_ALLOCATION] = {(2 << 10) - 8, (512 - 2) << 10, 4 << 20}; + if(mReservedPoolSize + asked_size > mMaxPoolSize) + { + llinfos << "Max pool size: " << mMaxPoolSize << llendl ; + llinfos << "Total reserved size: " << mReservedPoolSize + asked_size << llendl ; + llinfos << "Total_allocated Size: " << getTotalAllocatedSize() << llendl ; + + llerrs << "The pool is overflowing..." << llendl ; + } +} +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_index) +{ U32 preferred_size ; U32 overhead ; if(chunk_index < LARGE_ALLOCATION) { - preferred_size = (4 << 20) ; //4MB + preferred_size = CHUNK_SIZE ; //4MB overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; } else { - preferred_size = (16 << 20) ; //16MB + preferred_size = 4 * CHUNK_SIZE ; //16MB overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; } + + checkSize(preferred_size + overhead) ; + mReservedPoolSize += preferred_size + overhead ; + char* buffer = new(std::nothrow) char[preferred_size + overhead] ; if(!buffer) { return NULL ; } + memset(buffer, 0, preferred_size + overhead) ; LLMemoryChunk* chunk = new (buffer) LLMemoryChunk() ; chunk->init(buffer, preferred_size + overhead, MIN_SLOT_SIZES[chunk_index], @@ -1063,37 +1456,35 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde chunk->mPrev = NULL ; mChunkList[chunk_index] = chunk ; - //insert into the array - llassert_always(mNumOfChunks + 1 < mChunkVectorCapacity) ; - if(!mNumOfChunks) - { - mChunks[0] = chunk ; - } - else - { - U16 k ; - if(mChunks[0]->getBuffer() > chunk->getBuffer()) - { - k = 0 ; - } - else - { - k = findChunk(chunk->getBuffer()) + 1 ; - } - for(U16 i = mNumOfChunks ; i > k ; i++) - { - mChunks[i] = mChunks[i-1] ; - } - mChunks[k] = chunk ; - } + //insert into the hash table + U16 key = findHashKey(chunk->getBuffer()) ; + chunk->mHashNext = mChunkHashList[key] ; + mChunkHashList[key] = chunk ; + mNumOfChunks++; return chunk ; } -void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) +char*** _p = NULL ; +U32 _times; +U32 _levels; +void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk, U16 key) { + if(!chunk) + { + return ; + } + //remove from the linked list + for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) + { + if(mChunkList[i] == chunk) + { + mChunkList[i] = chunk->mNext ; + } + } + if(chunk->mPrev) { chunk->mPrev->mNext = chunk->mNext ; @@ -1103,43 +1494,47 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) chunk->mNext->mPrev = chunk->mPrev ; } - //remove from the array - U16 k = findChunk(chunk->getBuffer()) ; - mNumOfChunks--; - for(U16 i = k ; i < mNumOfChunks ; i++) + //remove from the hash table + if(mChunkHashList[key] == chunk) { - mChunks[i] = mChunks[i+1] ; + mChunkHashList[key] = chunk->mHashNext ; } - - //release memory - delete[] chunk->getBuffer() ; -} - -U16 LLPrivateMemoryPool::findChunk(const char* addr) -{ - llassert_always(mNumOfChunks > 0) ; - - U16 s = 0, e = mNumOfChunks; - U16 k = (s + e) / 2 ; - while(s < e) + else { - if(mChunks[k]->mKey > (U32)addr) + LLMemoryChunk* prev = mChunkHashList[key] ; + while(prev->mHashNext && prev->mHashNext != chunk) { - e = k ; + prev = prev->mHashNext ; } - else if(k < mNumOfChunks - 1 && mChunks[k+1]->mKey < (U32)addr) - { - s = k ; - } - else + llassert_always(prev->mHashNext == chunk) ; + + prev->mHashNext = chunk->mHashNext ; + } + mNumOfChunks--; + mReservedPoolSize -= chunk->getBufferSize() ; + + //debug check + if(_p) + { + for(U32 i = 0 ; i < _times; i++) { - break ; + for(U32 j = 0 ; j < _levels ;j++) + { + if( i == col && j == row) + { + continue ; + } + llassert_always(!_p[i][j] || !chunk->containsAddress(_p[i][j])) ; + } } - - k = (s + e) / 2 ; } + //release memory + delete[] chunk->getBuffer() ; +} - return k ; +U16 LLPrivateMemoryPool::findHashKey(const char* addr) +{ + return (((U32)addr) / CHUNK_SIZE) % HASH_FACTOR ; } //-------------------------------------------------------------------- @@ -1182,7 +1577,7 @@ void LLPrivateMemoryPoolTester::destroy() void LLPrivateMemoryPoolTester::run(bool threaded) { - const U32 max_pool_size = 16 << 20 ; + const U32 max_pool_size = 1024 << 20 ; if(sPool) { @@ -1192,8 +1587,8 @@ void LLPrivateMemoryPoolTester::run(bool threaded) //run the test correctnessTest() ; - performanceTest() ; - fragmentationtest() ; + //performanceTest() ; + //fragmentationtest() ; //release pool. ::delete sPool ; @@ -1206,6 +1601,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 U32 levels = (max_size - min_size) / stride + 1 ; char*** p ; U32 i, j ; + U32 total_allocated_size = 0 ; //allocate space for p ; if(!(p = ::new char**[times]) || !(*p = ::new char*[times * levels])) @@ -1223,6 +1619,10 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 } } + _p = p ; + _times = times; + _levels = levels ; + //allocation U32 size ; for(i = 0 ; i < times ; i++) @@ -1230,15 +1630,33 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 for(j = 0 ; j < levels; j++) { size = min_size + j * stride ; - p[i][j] = sPool->allocate(size) ; - p[i][j][size - 1] = '\0' ; //access the last element to verify the success of the allocation. + _prev = p[i][j] = sPool->allocate(size) ; + + total_allocated_size+= size ; + + *(U32*)p[i][j] = i ; + *((U32*)p[i][j] + 1) = j ; + //p[i][j][size - 1] = '\0' ; //access the last element to verify the success of the allocation. //randomly release memory if(random_deletion) { S32 k = rand() % levels ; - sPool->free(p[i][k]) ; - p[i][k] = NULL ; + + col = i ; + row = k ; + + if(p[i][k]) + { + if(_prev == p[i][k]) + { + _prev = NULL ; + } + llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; + sPool->free(p[i][k]) ; + total_allocated_size -= min_size + k * stride ; + p[i][k] = NULL ; + } } } } @@ -1248,18 +1666,28 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 { } + _prev = NULL ; //release all memory allocations for(i = 0 ; i < times; i++) { for(j = 0 ; j < levels; j++) { - sPool->free(p[i][j]) ; - p[i][j] = NULL ; + col = i ; + row = j ; + + if(p[i][j]) + { + llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; + sPool->free(p[i][j]) ; + total_allocated_size -= min_size + j * stride ; + p[i][j] = NULL ; + } } } ::delete[] *p ; ::delete[] p ; + _p = NULL ; } void LLPrivateMemoryPoolTester::correctnessTest() @@ -1281,7 +1709,7 @@ void LLPrivateMemoryPoolTester::correctnessTest() //large sized //[512KB, 4MB], each asks for 8 allocations and deallocations - test(512 * 1024, 4 * 1024 * 1024, 64 * 1024, 8, true, true) ; + test(512 * 1024, 4 * 1024 * 1024, 64 * 1024, 6, true, true) ; } void LLPrivateMemoryPoolTester::performanceTest() diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 128e7aefe6..f0e26d6b2f 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -95,6 +95,8 @@ public: U32 getBufferSize()const {return mBufferSize;} char* getBuffer() const {return mBuffer;} + //debug use + void resetBitMap() ; private: char* mBuffer; U32 mSlotSize ; //when the block is not initialized, it is the buffer size. @@ -108,6 +110,14 @@ public: LLMemoryBlock* mPrev ; LLMemoryBlock* mNext ; LLMemoryBlock* mSelf ; + + struct CompareAddress + { + bool operator()(const LLMemoryBlock* const& lhs, const LLMemoryBlock* const& rhs) + { + return (U32)lhs->getBuffer() < (U32)rhs->getBuffer(); + } + }; }; class LL_COMMON_API LLMemoryChunk //is divided into memory blocks. @@ -126,19 +136,26 @@ public: const char* getBuffer() const {return mBuffer;} U32 getBufferSize() const {return mBufferSize;} + U32 getAllocatedSize() const {return mAlloatedSize;} + + bool containsAddress(const char* addr) const; static U32 getMaxOverhead(U32 data_buffer_size, U32 min_page_size) ; + void dump() ; + private: + U32 getPageIndex(U32 addr) ; U32 getBlockLevel(U32 size) ; - U32 getPageLevel(U32 size) ; + U16 getPageLevel(U32 size) ; LLMemoryBlock* addBlock(U32 blk_idx) ; void popAvailBlockList(U32 blk_idx) ; void addToFreeSpace(LLMemoryBlock* blk) ; void removeFromFreeSpace(LLMemoryBlock* blk) ; void removeBlock(LLMemoryBlock* blk) ; void addToAvailBlockList(LLMemoryBlock* blk) ; - LLMemoryBlock* createNewBlock(LLMemoryBlock** cur_idxp, U32 buffer_size, U32 slot_size, U32 blk_idx) ; + U32 calcBlockSize(U32 slot_size); + LLMemoryBlock* createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) ; private: LLMemoryBlock** mAvailBlockList ;//256 by mMinSlotSize @@ -150,18 +167,21 @@ public: char* mDataBuffer ; char* mMetaBuffer ; U32 mMinBlockSize ; - U32 mMaxBlockSize; U32 mMinSlotSize ; + U32 mMaxSlotSize ; U32 mAlloatedSize ; U16 mBlockLevels; U16 mPartitionLevels; + //debug use + std::set mActiveBlockList ; + public: //form a linked list LLMemoryChunk* mNext ; LLMemoryChunk* mPrev ; - U32 mKey ; //= mBuffer + LLMemoryChunk* mHashNext ; } ; public: @@ -170,22 +190,22 @@ public: char *allocate(U32 size) ; void free(void* addr) ; + void dump() ; + U32 getTotalAllocatedSize() ; private: void lock() ; void unlock() ; S32 getChunkIndex(U32 size) ; LLMemoryChunk* addChunk(S32 chunk_index) ; - void removeChunk(LLMemoryChunk* chunk) ; - U16 findChunk(const char* addr) ; + void checkSize(U32 asked_size) ; + void removeChunk(LLMemoryChunk* chunk, U16 key) ; + U16 findHashKey(const char* addr); + LLMemoryChunk* findChunk(const char* addr, U16& key) ; void destroyPool() ; -private: - LLMutex* mMutexp ; - U32 mMaxPoolSize; - U32 mReservedPoolSize ; - +public: enum { SMALL_ALLOCATION = 0, //from 8 bytes to 2KB(exclusive), page size 2KB, max chunk size is 4MB. @@ -194,10 +214,14 @@ private: SUPER_ALLOCATION //allocation larger than 4MB. }; +private: + LLMutex* mMutexp ; + U32 mMaxPoolSize; + U32 mReservedPoolSize ; + LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address - std::vector mChunks ; + std::vector mChunkHashList ; U16 mNumOfChunks ; - U16 mChunkVectorCapacity ; }; // -- cgit v1.3 From f4a8027feb2bbeafe7b0cfb3b05fd27f3cf243d3 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 6 Jan 2011 12:36:44 -0700 Subject: removed some debug code, redesigned the hash function, fixed bugs --- indra/llcommon/llmemory.cpp | 605 +++++++++++++++++++++--------------------- indra/llcommon/llmemory.h | 13 +- indra/newview/llappviewer.cpp | 6 +- 3 files changed, 320 insertions(+), 304 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 00ef09d7a2..f9a2770691 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -356,7 +356,8 @@ U64 LLMemory::getCurrentRSS() #endif -//------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- //minimum block sizes (page size) for small allocation, medium allocation, large allocation const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 << 10, 16 << 10} ; // @@ -389,6 +390,7 @@ LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock() //empty } +//create and initialize a memory block void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size) { llassert_always(buffer_size >= slot_size) ; @@ -397,17 +399,20 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 mBufferSize = buffer_size ; mSlotSize = slot_size ; mTotalSlots = buffer_size / mSlotSize ; + llassert_always(mTotalSlots < 256) ; //max number is 256 + mAllocatedSlots = 0 ; + //init the bit map. //mark free bits S32 usage_bit_len = (mTotalSlots + 31) / 32 ; - mDummySize = usage_bit_len - 1 ; - if(mDummySize > 0) //extra space to store mUsageBits + mDummySize = usage_bit_len - 1 ; //if the mTotalSlots more than 32, needs extra space for bit map + if(mDummySize > 0) //reserve extra space from mBuffer to store bitmap if needed. { mTotalSlots -= (mDummySize * sizeof(mUsageBits) + mSlotSize - 1) / mSlotSize ; usage_bit_len = (mTotalSlots + 31) / 32 ; - mDummySize = usage_bit_len - 1 ; + mDummySize = usage_bit_len - 1 ;//number of 32bits reserved from mBuffer for bitmap if(mDummySize > 0) { @@ -423,7 +428,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 } } - if(mDummySize < 1) + if(mDummySize < 1)//no extra bitmap space reserved { mUsageBits = 0 ; if(mTotalSlots & 31) @@ -439,16 +444,16 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 llassert_always(mTotalSlots > 0) ; } +//mark this block to be free with the memory [mBuffer, mBuffer + mBufferSize). void LLPrivateMemoryPool::LLMemoryBlock::setBuffer(char* buffer, U32 buffer_size) { - llassert_always(buffer_size <= (16 << 20)) ; - mBuffer = buffer ; mBufferSize = buffer_size ; mSelf = NULL ; mTotalSlots = 0 ; //set the block is free. } +//reserve a slot char* LLPrivateMemoryPool::LLMemoryBlock::allocate() { llassert_always(mAllocatedSlots < mTotalSlots) ; @@ -479,47 +484,31 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() //set the slot reserved if(!idx) { - llassert_always(!(*bits & 1)); *bits |= 1 ; } else { - llassert_always(!(*bits & (1 << idx))) ; *bits |= (1 << idx) ; } mAllocatedSlots++ ; - //return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; - - char* p = mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; - llassert_always(mBuffer != p || !mDummySize) ; - llassert_always(*(U32*)p == 0 && *((U32*)p + 1) == 0) ; - - return p ; + return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; } -U32 col = 0, row = 0 ; +//free a slot void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) { - llassert_always((U32)addr >= (U32)mBuffer + mDummySize * sizeof(U32) && - (U32)addr < (U32)mBuffer + mBufferSize) ; - + //bit index U32 idx = ((U32)addr - (U32)mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; - llassert_always(idx < mTotalSlots) ; - llassert_always(addr == mBuffer + mDummySize * sizeof(U32) + idx * mSlotSize) ; - llassert_always(*(U32*)addr == col && *((U32*)addr + 1) == row) ; - - *(U32*)addr = 0 ; - *((U32*)addr + 1) = 0 ; - U32* bits = &mUsageBits ; if(idx >= 32) { bits = (U32*)mBuffer + (idx - 32) / 32 ; } + //reset the bit if(idx & 31) { *bits &= ~(1 << (idx & 31)) ; @@ -532,7 +521,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) mAllocatedSlots-- ; } -//for debug use +//for debug use: reset the entire bitmap. void LLPrivateMemoryPool::LLMemoryBlock::resetBitMap() { for(S32 i = 0 ; i < mDummySize ; i++) @@ -554,6 +543,7 @@ LLPrivateMemoryPool::LLMemoryChunk::~LLMemoryChunk() //empty } +//create and init a memory chunk void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 min_slot_size, U32 max_slot_size, U32 min_block_size, U32 max_block_size) { mBuffer = buffer ; @@ -562,7 +552,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 mMetaBuffer = mBuffer + sizeof(LLMemoryChunk) ; - mMinBlockSize = min_block_size; + mMinBlockSize = min_block_size; //page size mMinSlotSize = min_slot_size; mMaxSlotSize = max_slot_size ; mBlockLevels = mMaxSlotSize / mMinSlotSize ; @@ -571,11 +561,11 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 S32 max_num_blocks = (buffer_size - sizeof(LLMemoryChunk) - mBlockLevels * sizeof(LLMemoryBlock*) - mPartitionLevels * sizeof(LLMemoryBlock*)) / (mMinBlockSize + sizeof(LLMemoryBlock)) ; //meta data space - mBlocks = (LLMemoryBlock*)mMetaBuffer ; + mBlocks = (LLMemoryBlock*)mMetaBuffer ; //space reserved for all memory blocks. mAvailBlockList = (LLMemoryBlock**)((char*)mBlocks + sizeof(LLMemoryBlock) * max_num_blocks) ; mFreeSpaceList = (LLMemoryBlock**)((char*)mAvailBlockList + sizeof(LLMemoryBlock*) * mBlockLevels) ; - //data buffer + //data buffer, which can be used for allocation mDataBuffer = (char*)mFreeSpaceList + sizeof(LLMemoryBlock*) * mPartitionLevels ; //init @@ -588,17 +578,10 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 mFreeSpaceList[i] = NULL ; } + //assign the entire chunk to the first block mBlocks[0].mPrev = NULL ; mBlocks[0].mNext = NULL ; mBlocks[0].setBuffer(mDataBuffer, buffer_size - (mDataBuffer - mBuffer)) ; - - //debug - U32 end = (mBlocks[0].getBufferSize() / mMinBlockSize) ; - for(U32 i = 1 ; i < end ; i++) - { - mBlocks[i].mSelf = NULL ; - } - addToFreeSpace(&mBlocks[0]) ; mHashNext = NULL ; @@ -609,6 +592,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 //static U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_page_size) { + //for large allocations, reserve some extra memory for meta data to avoid wasting much if(data_buffer_size / min_page_size < 64) //large allocations { return 4096 ; //4KB @@ -621,6 +605,15 @@ U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) { + if(mMinSlotSize > size) + { + size = mMinSlotSize ; + } + if(mAlloatedSize + size > mBufferSize - (mDataBuffer - mBuffer)) + { + return NULL ; //no enough space in this chunk. + } + char* p = NULL ; U32 blk_idx = getBlockLevel(size); @@ -653,7 +646,7 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) } } - //ask for space from higher level blocks + //ask for space from larger blocks if(!p) { for(S32 i = blk_idx + 1 ; i < mBlockLevels; i++) @@ -672,18 +665,8 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) } } - llassert_always(!p || blk) ; - if(p && blk) - { - if(blk->getTotalSlots() == 1) - { - llassert_always(blk->getBuffer() == (char*)p) ; - } - U32 blk_idx = getPageIndex((U32)p) ; - LLMemoryBlock* b = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; - llassert_always(blk == b || b->mSelf == blk) ; - + { mAlloatedSize += blk->getSlotSize() ; } return p ; @@ -693,31 +676,19 @@ void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) { U32 blk_idx = getPageIndex((U32)addr) ; LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; - llassert_always(blk->mSelf) ; blk = blk->mSelf ; - llassert_always(addr >= blk->getBuffer() && addr < blk->getBuffer() + blk->getBufferSize()) ; - if(blk->getTotalSlots() == 1) - { - llassert_always(blk->getBuffer() == (char*)addr) ; - } - bool was_full = blk->isFull() ; blk->free(addr) ; mAlloatedSize -= blk->getSlotSize() ; if(blk->empty()) { - blk->resetBitMap() ; //debug use removeBlock(blk) ; - - dump(); } else if(was_full) { addToAvailBlockList(blk) ; - - dump(); } } @@ -731,14 +702,11 @@ bool LLPrivateMemoryPool::LLMemoryChunk::containsAddress(const char* addr) const return (U32)mBuffer <= (U32)addr && (U32)mBuffer + mBufferSize > (U32)addr ; } +//debug use void LLPrivateMemoryPool::LLMemoryChunk::dump() { +#if 0 //sanity check - std::vector< LLMemoryBlock* > blk_list ; - for(std::set::iterator iter = mActiveBlockList.begin() ; iter != mActiveBlockList.end(); ++iter) - { - blk_list.push_back(*iter) ; - } //for(S32 i = 0 ; i < mBlockLevels ; i++) //{ // LLMemoryBlock* blk = mAvailBlockList[i] ; @@ -790,6 +758,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump() llerrs << "gap happens" << llendl ; } } +#endif #if 0 llinfos << "---------------------------" << llendl ; llinfos << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << llendl ; @@ -818,6 +787,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump() #endif } +//compute the size for a block, the size is round to integer times of mMinBlockSize. U32 LLPrivateMemoryPool::LLMemoryChunk::calcBlockSize(U32 slot_size) { // @@ -857,15 +827,12 @@ U32 LLPrivateMemoryPool::LLMemoryChunk::calcBlockSize(U32 slot_size) return block_size ; } +//create a new block in the chunk LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock(U32 blk_idx) { U32 slot_size = mMinSlotSize * (blk_idx + 1) ; - U32 preferred_block_size = calcBlockSize(slot_size) ; - + U32 preferred_block_size = calcBlockSize(slot_size) ; U16 idx = getPageLevel(preferred_block_size); - llassert_always(idx < mPartitionLevels - 1) ; - llassert_always(preferred_block_size == (idx + 1) * mMinBlockSize) ; //round to integer times of mMinBlockSize. - LLMemoryBlock* blk = NULL ; if(mFreeSpaceList[idx])//if there is free slot for blk_idx @@ -878,7 +845,12 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock } else //search for other non-preferred but enough space slot. { - for(S32 i = (S32)idx - 1 ; i >= 0 ; i--) //search the small slots first + S32 min_idx = 0 ; + if(slot_size > mMinBlockSize) + { + min_idx = getPageLevel(slot_size) ; + } + for(S32 i = (S32)idx - 1 ; i >= min_idx ; i--) //search the small slots first { if(mFreeSpaceList[i]) { @@ -909,31 +881,12 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::addBlock } } - dump() ; - return blk ; } -char* _prev = NULL ; +//create a new block at the designed location LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNewBlock(LLMemoryBlock* blk, U32 buffer_size, U32 slot_size, U32 blk_idx) { - llassert_always(blk->getBufferSize() >= buffer_size) ; - - //debug - { - { - U32 blk_idx = getPageIndex((U32)blk->getBuffer()) ; - llassert_always(blk == (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock))) ; - } - U32 end = (blk->getBufferSize() / mMinBlockSize) ; - llassert_always(blk->mSelf == blk && blk->isFree()) ; - llassert_always((blk + end - 1)->mSelf == blk) ; - for(U32 i = 1 ; i < end - 1; i++) - { - llassert_always(!(blk + i)->mSelf) ; - } - } - //unlink from the free space removeFromFreeSpace(blk) ; @@ -949,41 +902,24 @@ LLPrivateMemoryPool::LLMemoryBlock* LLPrivateMemoryPool::LLMemoryChunk::createNe { LLMemoryBlock* next_blk = blk + (buffer_size / mMinBlockSize) ; next_blk->setBuffer(blk->getBuffer() + buffer_size, new_free_blk_size) ; - - { - U32 blk_idx = getPageIndex((U32)next_blk->getBuffer()) ; - llassert_always(next_blk == (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock))) ; - } - llassert_always(buffer_size == (buffer_size / mMinBlockSize) * mMinBlockSize) ; - llassert_always(((U32)next_blk->getBuffer() - (U32)mDataBuffer) == ((U32)next_blk->getBuffer() - (U32)mDataBuffer) / mMinBlockSize * mMinBlockSize) ; addToFreeSpace(next_blk) ; } blk->init(blk->getBuffer(), buffer_size, slot_size) ; //insert to the available block list... - llassert_always(!mAvailBlockList[blk_idx]) ; mAvailBlockList[blk_idx] = blk ; - llassert_always(blk->getTotalSlots() > 0) ; - llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; - llassert_always(buffer_size == (buffer_size / mMinBlockSize) * mMinBlockSize) ; - - //mark the address map + //mark the address map: all blocks covered by this block space pointing back to this block. U32 end = (buffer_size / mMinBlockSize) ; for(U32 i = 1 ; i < end ; i++) { (blk + i)->mSelf = blk ; } - llassert_always(blk->getBuffer() != _prev) ; - - llassert_always(mActiveBlockList.find(blk) == mActiveBlockList.end()) ; - - mActiveBlockList.insert(blk) ; - return blk ; } +//delete a block, release the block to the free pool. void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) { //remove from the available block list @@ -1003,22 +939,11 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) blk->mNext = NULL ; blk->mPrev = NULL ; - - std::set::iterator iter = mActiveBlockList.find(blk) ; - llassert_always(iter != mActiveBlockList.end()) ; - mActiveBlockList.erase(iter) ; //mark it free blk->setBuffer(blk->getBuffer(), blk->getBufferSize()) ; - //debug - U32 end = (blk->getBufferSize() / mMinBlockSize) ; - for(U32 i = 1 ; i < end ; i++) - { - llassert_always((blk + i)->mSelf == blk) ; - (blk + i)->mSelf = NULL ; - } -#if 0 +#if 1 //merge blk with neighbors if possible if(blk->getBuffer() > mDataBuffer) //has the left neighbor { @@ -1041,9 +966,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::removeBlock(LLMemoryBlock* blk) } } #endif - llassert_always(blk->getBuffer() != _prev) ; - llassert_always(mActiveBlockList.find(blk) == mActiveBlockList.end()) ; - + addToFreeSpace(blk) ; return ; @@ -1062,16 +985,10 @@ void LLPrivateMemoryPool::LLMemoryChunk::popAvailBlockList(U32 blk_idx) mAvailBlockList[blk_idx]->mPrev = NULL ; mAvailBlockList[blk_idx]->mNext = NULL ; mAvailBlockList[blk_idx] = next ; - if(next) - { - llassert_always(mAvailBlockList[blk_idx]->getTotalSlots() > 0) ; - llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; - } - - dump() ; } } +//add the block back to the free pool void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) { llassert_always(!blk->mPrev) ; @@ -1094,6 +1011,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToFreeSpace(LLMemoryBlock* blk) return ; } +//remove the space from the free pool void LLPrivateMemoryPool::LLMemoryChunk::removeFromFreeSpace(LLMemoryBlock* blk) { U16 free_idx = blk->getBufferSize() / mMinBlockSize - 1; @@ -1125,8 +1043,6 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) U32 blk_idx = getBlockLevel(blk->getSlotSize()); - llassert_always(blk->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; - blk->mNext = mAvailBlockList[blk_idx] ; if(blk->mNext) { @@ -1135,9 +1051,6 @@ void LLPrivateMemoryPool::LLMemoryChunk::addToAvailBlockList(LLMemoryBlock* blk) blk->mPrev = NULL ; mAvailBlockList[blk_idx] = blk ; - llassert_always(mAvailBlockList[blk_idx]->getTotalSlots() > 0) ; - llassert_always(mAvailBlockList[blk_idx]->getSlotSize() == (blk_idx + 1) * mMinSlotSize) ; - return ; } @@ -1158,9 +1071,6 @@ U32 LLPrivateMemoryPool::LLMemoryChunk::getBlockLevel(U32 size) //for mFreeSpaceList U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) { - llassert_always(size >= mMinBlockSize); - llassert_always(!(size % mMinBlockSize)) ; - //start from 0 U16 level = size / mMinBlockSize - 1 ; if(level >= mPartitionLevels) @@ -1174,11 +1084,12 @@ U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) //class LLPrivateMemoryPool //-------------------------------------------------------------------- const U32 CHUNK_SIZE = 4 << 20 ; //4 MB -const U32 HASH_FACTOR = 255 ; +const U32 LARGE_CHUNK_SIZE = 4 * CHUNK_SIZE ; //16 MB LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : mMutexp(NULL), mMaxPoolSize(max_size), - mReservedPoolSize(0) + mReservedPoolSize(0), + mHashFactor(1) { if(threaded) { @@ -1188,13 +1099,7 @@ LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) { mChunkList[i] = NULL ; - } - - mChunkHashList.resize(HASH_FACTOR + 1) ; - for(U32 i = 0 ; i <= HASH_FACTOR ; i++) - { - mChunkHashList[i] = NULL ; - } + } mNumOfChunks = 0 ; } @@ -1272,70 +1177,25 @@ void LLPrivateMemoryPool::free(void* addr) lock() ; - U16 key ; - LLMemoryChunk* chunk =findChunk((char*)addr, key) ; + LLMemoryChunk* chunk = findChunk((char*)addr) ; if(!chunk) { - delete[] (char*)addr ; //release from heap + delete[] addr ; //release from heap } else { - llassert_always((U32)addr >= (U32)chunk->getBuffer() && (U32)addr < (U32)chunk->getBuffer() + chunk->getBufferSize()) ; - chunk->free(addr) ; if(chunk->empty()) { - removeChunk(chunk, key) ; + removeChunk(chunk) ; } } unlock() ; } -LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr, U16& key) -{ - key = findHashKey(addr) ; - - //check the hash value "key" - LLMemoryChunk* chunk = mChunkHashList[key] ; - while(chunk && !chunk->containsAddress(addr)) - { - chunk = chunk->mHashNext ; - } - - if(!chunk && key > 0) //check the "key - 1" - { - chunk = mChunkHashList[key - 1] ; - while(chunk && !chunk->containsAddress(addr)) - { - chunk = chunk->mHashNext ; - } - - if(chunk) - { - key-- ; - } - } - - if(!chunk && key < HASH_FACTOR) //check the "key + 1" - { - chunk = mChunkHashList[key + 1] ; - while(chunk && !chunk->containsAddress(addr)) - { - chunk = chunk->mHashNext ; - } - - if(chunk) - { - key++ ; - } - } - - return chunk ; -} - void LLPrivateMemoryPool::dump() { } @@ -1388,11 +1248,11 @@ S32 LLPrivateMemoryPool::getChunkIndex(U32 size) void LLPrivateMemoryPool::destroyPool() { lock() ; - for(U32 i = 0 ; i <= HASH_FACTOR; i++) + for(U32 i = 0 ; i < mHashFactor; i++) { while(mChunkHashList[i]) { - removeChunk(mChunkHashList[i], i) ; + removeChunk(mChunkHashList[i]) ; } } llassert_always(mNumOfChunks == 0) ; @@ -1429,7 +1289,7 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde } else { - preferred_size = 4 * CHUNK_SIZE ; //16MB + preferred_size = LARGE_CHUNK_SIZE ; //16MB overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; } @@ -1457,19 +1317,14 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde mChunkList[chunk_index] = chunk ; //insert into the hash table - U16 key = findHashKey(chunk->getBuffer()) ; - chunk->mHashNext = mChunkHashList[key] ; - mChunkHashList[key] = chunk ; + addToHashTable(chunk) ; mNumOfChunks++; return chunk ; } -char*** _p = NULL ; -U32 _times; -U32 _levels; -void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk, U16 key) +void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) { if(!chunk) { @@ -1495,46 +1350,210 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk, U16 key) } //remove from the hash table - if(mChunkHashList[key] == chunk) + removeFromHashTable(chunk) ; + + mNumOfChunks--; + mReservedPoolSize -= chunk->getBufferSize() ; + + //release memory + delete[] chunk->getBuffer() ; +} + +U16 LLPrivateMemoryPool::findHashKey(const char* addr) +{ + return (((U32)addr) / CHUNK_SIZE) % mHashFactor ; +} + +LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::findChunk(const char* addr) +{ + U16 key = findHashKey(addr) ; + if(mChunkHashList.size() <= key) { - mChunkHashList[key] = chunk->mHashNext ; + return NULL ; } - else + + //check the hash value "key" + LLMemoryChunk* chunk = mChunkHashList[key] ; + while(chunk && !chunk->containsAddress(addr)) + { + chunk = chunk->mHashNext ; + } + + return chunk ; +} + +void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) +{ + static const U16 HASH_FACTORS[] = {41, 83, 193, 317, 419, 523, 0xFFFF}; + + U16 i ; + if(mChunkHashList.empty()) + { + mHashFactor = HASH_FACTORS[0] ; + rehash() ; + } + + U16 start_key = findHashKey(chunk->getBuffer()) ; + U16 end_key = findHashKey(chunk->getBuffer() + chunk->getBufferSize() - 1) ; + bool need_rehash = false ; + + if(mChunkHashList[start_key]) { - LLMemoryChunk* prev = mChunkHashList[key] ; - while(prev->mHashNext && prev->mHashNext != chunk) + if(mChunkHashList[start_key] == chunk) { - prev = prev->mHashNext ; + return; //already inserted. } - llassert_always(prev->mHashNext == chunk) ; + + need_rehash = mChunkHashList[start_key]->mHashNext != NULL ; + if(!need_rehash) + { + llassert_always(!chunk->mHashNext) ; - prev->mHashNext = chunk->mHashNext ; + chunk->mHashNext = mChunkHashList[start_key] ; + mChunkHashList[start_key] = chunk ; + } } - mNumOfChunks--; - mReservedPoolSize -= chunk->getBufferSize() ; - - //debug check - if(_p) + else + { + mChunkHashList[start_key] = chunk ; + } + + if(!need_rehash) + { + if(mChunkHashList[end_key]) + { + llassert_always(mChunkHashList[end_key] != chunk) + + need_rehash = mChunkHashList[end_key]->mHashNext != NULL ; + if(!need_rehash) + { + mChunkHashList[end_key]->mHashNext = chunk ; + } + } + else + { + mChunkHashList[end_key] = chunk ; + } + } + + if(!need_rehash) { - for(U32 i = 0 ; i < _times; i++) + if(end_key < start_key) { - for(U32 j = 0 ; j < _levels ;j++) + for(U16 i = start_key + 1 ; i < mHashFactor; i++) { - if( i == col && j == row) + if(mChunkHashList[i]) { - continue ; + llassert_always(mChunkHashList[i] != chunk) ; + need_rehash = true ; + break ; + } + else + { + mChunkHashList[i] = chunk ; + } + } + + if(!need_rehash) + { + for(U16 i = 0 ; i < end_key; i++) + { + if(mChunkHashList[i]) + { + llassert_always(mChunkHashList[i] != chunk) ; + need_rehash = true ; + break ; + } + else + { + mChunkHashList[i] = chunk ; + } + } + } + } + else + { + for(i = start_key + 1; i < end_key; i++) + { + if(mChunkHashList[i]) + { + llassert_always(mChunkHashList[i] != chunk) ; + need_rehash = true ; + break ; + } + else + { + mChunkHashList[i] = chunk ; } - llassert_always(!_p[i][j] || !chunk->containsAddress(_p[i][j])) ; } } } - //release memory - delete[] chunk->getBuffer() ; + + if(need_rehash) + { + i = 0 ; + while(HASH_FACTORS[i] <= mHashFactor) i++; + + mHashFactor = HASH_FACTORS[i] ; + llassert_always(mHashFactor != 0xFFFF) ;//stop point of the recursive calls + + rehash() ; + } } -U16 LLPrivateMemoryPool::findHashKey(const char* addr) +void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk) +{ + U16 start_key = findHashKey(chunk->getBuffer()) ; + U16 end_key = findHashKey(chunk->getBuffer() + chunk->getBufferSize() - 1) ; + + mChunkHashList[start_key] = chunk->mHashNext ; + chunk->mHashNext = NULL ; + + if(mChunkHashList[end_key] != chunk) + { + mChunkHashList[end_key]->mHashNext = NULL ; + } + else + { + mChunkHashList[end_key] = NULL ; + } + + if(end_key < start_key) + { + for(U16 i = start_key + 1 ; i < mHashFactor; i++) + { + mChunkHashList[i] = NULL ; + } + for(U16 i = 0 ; i < end_key; i++) + { + mChunkHashList[i] = NULL ; + } + } + else + { + for(U16 i = start_key + 1 ; i < end_key; i++) + { + mChunkHashList[i] = NULL ; + } + } +} + +void LLPrivateMemoryPool::rehash() { - return (((U32)addr) / CHUNK_SIZE) % HASH_FACTOR ; + mChunkHashList.clear() ; + mChunkHashList.resize(mHashFactor, NULL) ; + + LLMemoryChunk* chunk ; + for(U16 i = 0 ; i < SUPER_ALLOCATION ; i++) + { + chunk = mChunkList[i] ; + while(chunk) + { + chunk->mHashNext = NULL ; + addToHashTable(chunk) ; + chunk = chunk->mNext ; + } + } } //-------------------------------------------------------------------- @@ -1587,7 +1606,7 @@ void LLPrivateMemoryPoolTester::run(bool threaded) //run the test correctnessTest() ; - //performanceTest() ; + performanceTest() ; //fragmentationtest() ; //release pool. @@ -1619,10 +1638,6 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 } } - _p = p ; - _times = times; - _levels = levels ; - //allocation U32 size ; for(i = 0 ; i < times ; i++) @@ -1630,7 +1645,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 for(j = 0 ; j < levels; j++) { size = min_size + j * stride ; - _prev = p[i][j] = sPool->allocate(size) ; + p[i][j] = sPool->allocate(size) ; total_allocated_size+= size ; @@ -1643,15 +1658,8 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 { S32 k = rand() % levels ; - col = i ; - row = k ; - if(p[i][k]) { - if(_prev == p[i][k]) - { - _prev = NULL ; - } llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; sPool->free(p[i][k]) ; total_allocated_size -= min_size + k * stride ; @@ -1666,15 +1674,11 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 { } - _prev = NULL ; //release all memory allocations for(i = 0 ; i < times; i++) { for(j = 0 ; j < levels; j++) { - col = i ; - row = j ; - if(p[i][j]) { llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; @@ -1687,7 +1691,57 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 ::delete[] *p ; ::delete[] p ; - _p = NULL ; +} + +void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) +{ + LLTimer timer ; + + llinfos << " -**********************- " << llendl ; + llinfos << "test size: " << size << " test times: " << times << llendl ; + + timer.reset() ; + char** p = new char*[times] ; + + //using the customized memory pool + //allocation + for(U32 i = 0 ; i < times; i++) + { + p[i] = sPool->allocate(size) ; + if(!p[i]) + { + llerrs << "allocation failed" << llendl ; + } + } + //de-allocation + for(U32 i = 0 ; i < times; i++) + { + sPool->free(p[i]) ; + p[i] = NULL ; + } + llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; + + timer.reset() ; + + //using the standard allocator/de-allocator: + //allocation + for(U32 i = 0 ; i < times; i++) + { + p[i] = ::new char[size] ; + if(!p[i]) + { + llerrs << "allocation failed" << llendl ; + } + } + //de-allocation + for(U32 i = 0 ; i < times; i++) + { + ::delete[] p[i] ; + p[i] = NULL ; + } + llinfos << "time spent using standard allocator/de-allocator: " << timer.getElapsedTimeF32() << llendl ; + + delete[] p; } void LLPrivateMemoryPoolTester::correctnessTest() @@ -1715,56 +1769,15 @@ void LLPrivateMemoryPoolTester::correctnessTest() void LLPrivateMemoryPoolTester::performanceTest() { U32 test_size[3] = {768, 3* 1024, 3* 1024 * 1024}; - - S32 i ; - LLFrameTimer timer ; - - //do 1024 various-sized allocations / deallocations, compare the performance with the normal ones. - + //small sized - { - timer.reset() ; - char* p[1024] = {NULL} ; - for(i = 0 ; i < 1024; i++) - { - p[i] = sPool->allocate(test_size[0]) ; - if(!p[i]) - { - llerrs << "allocation failed" << llendl ; - } - } - - for(i = 0 ; i < 1024; i++) - { - sPool->free(p[i]) ; - p[i] = NULL ; - } - llinfos << "time spent on 1024 small allocations: %f " << timer.getElapsedTimeF32() << llendl ; - - timer.reset() ; - - //using the standard allocator/de-allocator: - for(i = 0 ; i < 1024; i++) - { - p[i] = ::new char[test_size[0]] ; - if(!p[i]) - { - llerrs << "allocation failed" << llendl ; - } - } - - for(i = 0 ; i < 1024; i++) - { - ::delete[] p[i] ; - p[i] = NULL ; - } - llinfos << "time spent on 1024 small allocations: %f using standard allocator/de-allocator." << timer.getElapsedTimeF32() << llendl ; - - timer.reset() ; - } + testAndTime(test_size[0], 8) ; + //medium sized + testAndTime(test_size[1], 8) ; //large sized + testAndTime(test_size[2], 8) ; } void LLPrivateMemoryPoolTester::fragmentationtest() diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index f0e26d6b2f..f7ca33a279 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -173,9 +173,6 @@ public: U16 mBlockLevels; U16 mPartitionLevels; - //debug use - std::set mActiveBlockList ; - public: //form a linked list LLMemoryChunk* mNext ; @@ -200,9 +197,13 @@ private: S32 getChunkIndex(U32 size) ; LLMemoryChunk* addChunk(S32 chunk_index) ; void checkSize(U32 asked_size) ; - void removeChunk(LLMemoryChunk* chunk, U16 key) ; + void removeChunk(LLMemoryChunk* chunk) ; U16 findHashKey(const char* addr); - LLMemoryChunk* findChunk(const char* addr, U16& key) ; + void addToHashTable(LLMemoryChunk* chunk) ; + void removeFromHashTable(LLMemoryChunk* chunk) ; + void rehash() ; + LLMemoryChunk* findChunk(const char* addr) ; + void destroyPool() ; public: @@ -222,6 +223,7 @@ private: LLMemoryChunk* mChunkList[SUPER_ALLOCATION] ; //all memory chunks reserved by this pool, sorted by address std::vector mChunkHashList ; U16 mNumOfChunks ; + U16 mHashFactor ; }; // @@ -245,6 +247,7 @@ private: void fragmentationtest() ; void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ; + void testAndTime(U32 size, U32 times) ; public: void* operator new(size_t size) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index fd7e1eda7f..d1727a0e83 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1087,9 +1087,9 @@ bool LLAppViewer::mainLoop() // point of posting. LLSD newFrame; - LLPrivateMemoryPoolTester::getInstance()->run(false) ; - LLPrivateMemoryPoolTester::getInstance()->run(true) ; - LLPrivateMemoryPoolTester::destroy() ; + //LLPrivateMemoryPoolTester::getInstance()->run(false) ; + //LLPrivateMemoryPoolTester::getInstance()->run(true) ; + //LLPrivateMemoryPoolTester::destroy() ; // Handle messages while (!LLApp::isExiting()) -- cgit v1.3 From a3759a7815f7ba55b825bc76f30a1e333e01f295 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 6 Jan 2011 16:17:38 -0700 Subject: add the class LLPrivateMemoryPoolManager --- indra/llcommon/llmemory.cpp | 157 +++++++++++++++++++++++++++++--------------- indra/llcommon/llmemory.h | 32 ++++++++- 2 files changed, 136 insertions(+), 53 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index f9a2770691..f1285841b3 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1404,14 +1404,10 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) return; //already inserted. } - need_rehash = mChunkHashList[start_key]->mHashNext != NULL ; - if(!need_rehash) - { - llassert_always(!chunk->mHashNext) ; + llassert_always(!chunk->mHashNext) ; - chunk->mHashNext = mChunkHashList[start_key] ; - mChunkHashList[start_key] = chunk ; - } + chunk->mHashNext = mChunkHashList[start_key] ; + mChunkHashList[start_key] = chunk ; } else { @@ -1440,52 +1436,15 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) { if(end_key < start_key) { - for(U16 i = start_key + 1 ; i < mHashFactor; i++) - { - if(mChunkHashList[i]) - { - llassert_always(mChunkHashList[i] != chunk) ; - need_rehash = true ; - break ; - } - else - { - mChunkHashList[i] = chunk ; - } - } - + need_rehash = fillHashTable(start_key + 1, mHashFactor, chunk) ; if(!need_rehash) { - for(U16 i = 0 ; i < end_key; i++) - { - if(mChunkHashList[i]) - { - llassert_always(mChunkHashList[i] != chunk) ; - need_rehash = true ; - break ; - } - else - { - mChunkHashList[i] = chunk ; - } - } + need_rehash = fillHashTable(0, end_key, chunk) ; } } else { - for(i = start_key + 1; i < end_key; i++) - { - if(mChunkHashList[i]) - { - llassert_always(mChunkHashList[i] != chunk) ; - need_rehash = true ; - break ; - } - else - { - mChunkHashList[i] = chunk ; - } - } + need_rehash = fillHashTable(start_key + 1, end_key, chunk) ; } } @@ -1495,7 +1454,7 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) while(HASH_FACTORS[i] <= mHashFactor) i++; mHashFactor = HASH_FACTORS[i] ; - llassert_always(mHashFactor != 0xFFFF) ;//stop point of the recursive calls + llassert_always(mHashFactor != 0xFFFF) ;//stop point to prevent endlessly recursive calls rehash() ; } @@ -1540,6 +1499,8 @@ void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk) void LLPrivateMemoryPool::rehash() { + llinfos << "new hash factor: " << mHashFactor << llendl ; + mChunkHashList.clear() ; mChunkHashList.resize(mHashFactor, NULL) ; @@ -1556,8 +1517,100 @@ void LLPrivateMemoryPool::rehash() } } +bool LLPrivateMemoryPool::fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) +{ + for(U16 i = start; i < end; i++) + { + if(mChunkHashList[i]) //the slot is occupied. + { + llassert_always(mChunkHashList[i] != chunk) ; + return true ; + } + else + { + mChunkHashList[i] = chunk ; + } + } + + return false ; +} + +//-------------------------------------------------------------------- +//class LLPrivateMemoryPoolManager +//-------------------------------------------------------------------- +LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ; + +LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() +{ +} + +LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() +{ + //all private pools should be released by their owners before reaching here. + llassert_always(mPoolList.empty()) ; + +#if 0 + if(!mPoolList.empty()) + { + for(std::set::iterator iter = mPoolList.begin(); iter != mPoolList.end(); ++iter) + { + delete *iter; + } + mPoolList.clear() ; + } +#endif +} + +//static +LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::getInstance() +{ + if(!sInstance) + { + sInstance = new LLPrivateMemoryPoolManager() ; + } + return sInstance ; +} + +//static +void LLPrivateMemoryPoolManager::destroyClass() +{ + if(sInstance) + { + delete sInstance ; + sInstance = NULL ; + } +} + +LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(U32 max_size, bool threaded) +{ + LLPrivateMemoryPool* pool = new LLPrivateMemoryPool(max_size, threaded) ; + mPoolList.insert(pool) ; + + return pool ; +} + +void LLPrivateMemoryPoolManager::deletePool(LLPrivateMemoryPool* pool) +{ + mPoolList.erase(pool) ; + delete pool; +} + +//debug +void LLPrivateMemoryPoolManager::updateStatistics() +{ + mTotalReservedSize = 0 ; + mTotalAllocatedSize = 0 ; + + for(std::set::iterator iter = mPoolList.begin(); iter != mPoolList.end(); ++iter) + { + mTotalReservedSize += (*iter)->getTotalReservedSize() ; + mTotalAllocatedSize += (*iter)->getTotalAllocatedSize() ; + } +} + //-------------------------------------------------------------------- //class LLPrivateMemoryPoolTester +//-------------------------------------------------------------------- LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::sInstance = NULL ; LLPrivateMemoryPool* LLPrivateMemoryPoolTester::sPool = NULL ; LLPrivateMemoryPoolTester::LLPrivateMemoryPoolTester() @@ -1589,7 +1642,7 @@ void LLPrivateMemoryPoolTester::destroy() if(sPool) { - ::delete sPool ; + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; sPool = NULL ; } } @@ -1600,9 +1653,9 @@ void LLPrivateMemoryPoolTester::run(bool threaded) if(sPool) { - ::delete sPool ; + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; } - sPool = ::new LLPrivateMemoryPool(max_pool_size, threaded) ; + sPool = LLPrivateMemoryPoolManager::getInstance()->newPool(max_pool_size, threaded) ; //run the test correctnessTest() ; @@ -1610,7 +1663,7 @@ void LLPrivateMemoryPoolTester::run(bool threaded) //fragmentationtest() ; //release pool. - ::delete sPool ; + LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; sPool = NULL ; } diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index f7ca33a279..e42dc174b5 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -73,6 +73,8 @@ private: // class LL_COMMON_API LLPrivateMemoryPool { + friend class LLPrivateMemoryPoolManager ; + public: class LL_COMMON_API LLMemoryBlock //each block is devided into slots uniformly { @@ -181,15 +183,17 @@ public: LLMemoryChunk* mHashNext ; } ; -public: +private: LLPrivateMemoryPool(U32 max_size, bool threaded) ; ~LLPrivateMemoryPool() ; +public: char *allocate(U32 size) ; void free(void* addr) ; void dump() ; U32 getTotalAllocatedSize() ; + U32 getTotalReservedSize() {return mReservedPoolSize;} private: void lock() ; @@ -202,6 +206,7 @@ private: void addToHashTable(LLMemoryChunk* chunk) ; void removeFromHashTable(LLMemoryChunk* chunk) ; void rehash() ; + bool fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk) ; LLMemoryChunk* findChunk(const char* addr) ; void destroyPool() ; @@ -226,6 +231,31 @@ private: U16 mHashFactor ; }; +class LL_COMMON_API LLPrivateMemoryPoolManager +{ +private: + LLPrivateMemoryPoolManager() ; + ~LLPrivateMemoryPoolManager() ; + +public: + static LLPrivateMemoryPoolManager* getInstance() ; + static void destroyClass() ; + + LLPrivateMemoryPool* newPool(U32 max_size, bool threaded) ; + void deletePool(LLPrivateMemoryPool* pool) ; + +private: + static LLPrivateMemoryPoolManager* sInstance ; + std::set mPoolList ; + +public: + //debug and statistics info. + void updateStatistics() ; + + U32 mTotalReservedSize ; + U32 mTotalAllocatedSize ; +}; + // //the below singleton is used to test the private memory pool. // -- cgit v1.3 From 7daa3d1ca10199468946feef0ce8eb67489deee0 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Fri, 7 Jan 2011 14:57:35 -0700 Subject: fixed a hash bug, enlarged the overhead for large allocations, and add new chunk to the tail of the linked list so new allocations go to oldest chunks first. --- indra/llcommon/llmemory.cpp | 46 +++++++++++++++++++++++++++++---------------- indra/llcommon/llmemory.h | 3 ++- 2 files changed, 32 insertions(+), 17 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 1f40f5e17a..543f17baf4 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -393,8 +393,6 @@ LLPrivateMemoryPool::LLMemoryBlock::~LLMemoryBlock() //create and initialize a memory block void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 slot_size) { - llassert_always(buffer_size >= slot_size) ; - mBuffer = buffer ; mBufferSize = buffer_size ; mSlotSize = slot_size ; @@ -590,12 +588,18 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 } //static -U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_page_size) +U32 LLPrivateMemoryPool::LLMemoryChunk::getMaxOverhead(U32 data_buffer_size, U32 min_slot_size, + U32 max_slot_size, U32 min_block_size, U32 max_block_size) { //for large allocations, reserve some extra memory for meta data to avoid wasting much - if(data_buffer_size / min_page_size < 64) //large allocations + if(data_buffer_size / min_slot_size < 64) //large allocations { - return 4096 ; //4KB + U32 overhead = sizeof(LLMemoryChunk) + (data_buffer_size / min_block_size) * sizeof(LLMemoryBlock) + + sizeof(LLMemoryBlock*) * (max_slot_size / min_slot_size) + sizeof(LLMemoryBlock*) * (max_block_size / min_block_size + 1) ; + + //round to integer times of min_block_size + overhead = ((overhead + min_block_size - 1) / min_block_size) * min_block_size ; + return overhead ; } else { @@ -1290,12 +1294,14 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde if(chunk_index < LARGE_ALLOCATION) { preferred_size = CHUNK_SIZE ; //4MB - overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; + overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_SLOT_SIZES[chunk_index], + MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; } else { preferred_size = LARGE_CHUNK_SIZE ; //16MB - overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_BLOCK_SIZES[chunk_index]) ; + overhead = LLMemoryChunk::getMaxOverhead(preferred_size, MIN_SLOT_SIZES[chunk_index], + MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; } checkSize(preferred_size + overhead) ; @@ -1306,20 +1312,28 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde { return NULL ; } - memset(buffer, 0, preferred_size + overhead) ; - + LLMemoryChunk* chunk = new (buffer) LLMemoryChunk() ; chunk->init(buffer, preferred_size + overhead, MIN_SLOT_SIZES[chunk_index], MAX_SLOT_SIZES[chunk_index], MIN_BLOCK_SIZES[chunk_index], MAX_BLOCK_SIZES[chunk_index]) ; - //add to the head of the linked list - chunk->mNext = mChunkList[chunk_index] ; - if(mChunkList[chunk_index]) + //add to the tail of the linked list { - mChunkList[chunk_index]->mPrev = chunk ; + if(!mChunkList[chunk_index]) + { + mChunkList[chunk_index] = chunk ; + } + else + { + LLMemoryChunk* cur = mChunkList[chunk_index] ; + while(cur->mNext) + { + cur = cur->mNext ; + } + cur->mNext = chunk ; + chunk->mPrev = cur ; + } } - chunk->mPrev = NULL ; - mChunkList[chunk_index] = chunk ; //insert into the hash table addToHashTable(chunk) ; @@ -1425,7 +1439,7 @@ void LLPrivateMemoryPool::addToHashTable(LLMemoryChunk* chunk) { llassert_always(mChunkHashList[end_key] != chunk) - need_rehash = mChunkHashList[end_key]->mHashNext != NULL ; + need_rehash = mChunkHashList[end_key]->mHashNext != NULL || mChunkHashList[end_key] == chunk->mHashNext; if(!need_rehash) { mChunkHashList[end_key]->mHashNext = chunk ; diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index e42dc174b5..5a2889958b 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -142,7 +142,8 @@ public: bool containsAddress(const char* addr) const; - static U32 getMaxOverhead(U32 data_buffer_size, U32 min_page_size) ; + static U32 getMaxOverhead(U32 data_buffer_size, U32 min_slot_size, + U32 max_slot_size, U32 min_block_size, U32 max_block_size) ; void dump() ; -- cgit v1.3 From 108980f68c184341e83454bbd5e72a5803b33092 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 23 Feb 2011 17:53:08 -0700 Subject: add types to LLPrivateMemoryPool --- indra/llcommon/llmemory.cpp | 70 +++++++++++++++++++++++++++++---------------- indra/llcommon/llmemory.h | 23 +++++++++++---- indra/llimage/llimage.cpp | 4 +-- 3 files changed, 65 insertions(+), 32 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 1414ac7b9e..062640f546 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1263,13 +1263,16 @@ U16 LLPrivateMemoryPool::LLMemoryChunk::getPageLevel(U32 size) //-------------------------------------------------------------------- const U32 CHUNK_SIZE = 4 << 20 ; //4 MB const U32 LARGE_CHUNK_SIZE = 4 * CHUNK_SIZE ; //16 MB -LLPrivateMemoryPool::LLPrivateMemoryPool(U32 max_size, bool threaded) : - mMutexp(NULL), - mMaxPoolSize(max_size), +LLPrivateMemoryPool::LLPrivateMemoryPool(S32 type) : + mMutexp(NULL), mReservedPoolSize(0), - mHashFactor(1) + mHashFactor(1), + mType(type) { - if(threaded) + const U32 MAX_POOL_SIZE = 256 * 1024 * 1024 ; //256 MB + + mMaxPoolSize = MAX_POOL_SIZE ; + if(type == STATIC_THREADED || type == VOLATILE_THREADED) { mMutexp = new LLMutex ; } @@ -1735,22 +1738,35 @@ LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ; LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() { + mPoolList.resize(LLPrivateMemoryPool::MAX_TYPES) ; + + for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) + { + mPoolList[i] = NULL ; + } } LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() { +#if 0 //all private pools should be released by their owners before reaching here. - llassert_always(mPoolList.empty()) ; + for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) + { + llassert_always(!mPoolList[i]) ; + } + mPoolList.clear() ; -#if 0 - if(!mPoolList.empty()) +#else + //forcefully release all memory + for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) { - for(std::set::iterator iter = mPoolList.begin(); iter != mPoolList.end(); ++iter) + if(mPoolList[i]) { - delete *iter; + delete mPoolList[i] ; + mPoolList[i] = NULL ; } - mPoolList.clear() ; } + mPoolList.clear() ; #endif } @@ -1774,18 +1790,23 @@ void LLPrivateMemoryPoolManager::destroyClass() } } -LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(U32 max_size, bool threaded) +LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type) { - LLPrivateMemoryPool* pool = new LLPrivateMemoryPool(max_size, threaded) ; - mPoolList.insert(pool) ; + if(!mPoolList[type]) + { + mPoolList[type] = new LLPrivateMemoryPool(type) ; + } - return pool ; + return mPoolList[type] ; } void LLPrivateMemoryPoolManager::deletePool(LLPrivateMemoryPool* pool) { - mPoolList.erase(pool) ; - delete pool; + if(pool->isEmpty()) + { + mPoolList[pool->getType()] = NULL ; + delete pool; + } } //debug @@ -1794,10 +1815,13 @@ void LLPrivateMemoryPoolManager::updateStatistics() mTotalReservedSize = 0 ; mTotalAllocatedSize = 0 ; - for(std::set::iterator iter = mPoolList.begin(); iter != mPoolList.end(); ++iter) + for(U32 i = 0; i < mPoolList.size(); i++) { - mTotalReservedSize += (*iter)->getTotalReservedSize() ; - mTotalAllocatedSize += (*iter)->getTotalAllocatedSize() ; + if(mPoolList[i]) + { + mTotalReservedSize += mPoolList[i]->getTotalReservedSize() ; + mTotalAllocatedSize += mPoolList[i]->getTotalAllocatedSize() ; + } } } @@ -1840,15 +1864,13 @@ void LLPrivateMemoryPoolTester::destroy() } } -void LLPrivateMemoryPoolTester::run(bool threaded) +void LLPrivateMemoryPoolTester::run(S32 type) { - const U32 max_pool_size = 1024 << 20 ; - if(sPool) { LLPrivateMemoryPoolManager::getInstance()->deletePool(sPool) ; } - sPool = LLPrivateMemoryPoolManager::getInstance()->newPool(max_pool_size, threaded) ; + sPool = LLPrivateMemoryPoolManager::getInstance()->newPool(type) ; //run the test correctnessTest() ; diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 4474df6f86..a5dbabec5a 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -231,7 +231,7 @@ public: } ; private: - LLPrivateMemoryPool(U32 max_size, bool threaded) ; + LLPrivateMemoryPool(S32 type) ; ~LLPrivateMemoryPool() ; public: @@ -241,7 +241,9 @@ public: void dump() ; U32 getTotalAllocatedSize() ; U32 getTotalReservedSize() {return mReservedPoolSize;} - + S32 getType() const {return mType; } + bool isEmpty() const {return !mNumOfChunks; } + private: void lock() ; void unlock() ; @@ -267,6 +269,15 @@ public: SUPER_ALLOCATION //allocation larger than 4MB. }; + enum + { + STATIC = 0 , //static pool(each alllocation stays for a long time) without threading support + VOLATILE, //Volatile pool(each allocation stays for a very short time) without threading support + STATIC_THREADED, //static pool with threading support + VOLATILE_THREADED, //volatile pool with threading support + MAX_TYPES + }; //pool types + private: LLMutex* mMutexp ; U32 mMaxPoolSize; @@ -276,6 +287,8 @@ private: std::vector mChunkHashList ; U16 mNumOfChunks ; U16 mHashFactor ; + + S32 mType ; }; class LL_COMMON_API LLPrivateMemoryPoolManager @@ -288,12 +301,12 @@ public: static LLPrivateMemoryPoolManager* getInstance() ; static void destroyClass() ; - LLPrivateMemoryPool* newPool(U32 max_size, bool threaded) ; + LLPrivateMemoryPool* newPool(S32 type) ; void deletePool(LLPrivateMemoryPool* pool) ; private: static LLPrivateMemoryPoolManager* sInstance ; - std::set mPoolList ; + std::vector mPoolList ; public: //debug and statistics info. @@ -316,7 +329,7 @@ public: static LLPrivateMemoryPoolTester* getInstance() ; static void destroy() ; - void run(bool threaded) ; + void run(S32 type) ; private: void correctnessTest() ; diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 706231307d..9298716022 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -106,11 +106,9 @@ LLImageBase::~LLImageBase() //static void LLImageBase::createPrivatePool() { - const U32 MAX_POOL_SIZE = 512 * 1024 * 1024 ; //512 MB - if(!sPrivatePoolp) { - sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(MAX_POOL_SIZE, true) ; + sPrivatePoolp = LLPrivateMemoryPoolManager::getInstance()->newPool(LLPrivateMemoryPool::STATIC_THREADED) ; } } -- cgit v1.3 From fc106df53085f549acdbb2f8149ca75e400532fa Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Thu, 24 Feb 2011 19:47:55 -0700 Subject: fix the compiling error: "free" is defined and in use globally. --- indra/llcommon/llmemory.cpp | 20 ++++++++++---------- indra/llcommon/llmemory.h | 12 +++++++----- indra/llimage/llimage.cpp | 2 +- indra/llrender/llvertexbuffer.cpp | 12 ++++++------ 4 files changed, 24 insertions(+), 22 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 062640f546..49e2cd9ac4 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -572,7 +572,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 mSlotSize = slot_size ; mTotalSlots = buffer_size / mSlotSize ; - llassert_always(mTotalSlots <= 256) ; //max number is 256 + llassert_always(buffer_size / mSlotSize <= 256) ; //max number is 256 mAllocatedSlots = 0 ; @@ -669,7 +669,7 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() } //free a slot -void LLPrivateMemoryPool::LLMemoryBlock::free(void* addr) +void LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr) { //bit index U32 idx = ((U32)addr - (U32)mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; @@ -850,14 +850,14 @@ char* LLPrivateMemoryPool::LLMemoryChunk::allocate(U32 size) return p ; } -void LLPrivateMemoryPool::LLMemoryChunk::free(void* addr) +void LLPrivateMemoryPool::LLMemoryChunk::freeMem(void* addr) { U32 blk_idx = getPageIndex((U32)addr) ; LLMemoryBlock* blk = (LLMemoryBlock*)(mMetaBuffer + blk_idx * sizeof(LLMemoryBlock)) ; blk = blk->mSelf ; bool was_full = blk->isFull() ; - blk->free(addr) ; + blk->freeMem(addr) ; mAlloatedSize -= blk->getSlotSize() ; if(blk->empty()) @@ -1349,7 +1349,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) return p ; } -void LLPrivateMemoryPool::free(void* addr) +void LLPrivateMemoryPool::freeMem(void* addr) { if(!addr) { @@ -1366,7 +1366,7 @@ void LLPrivateMemoryPool::free(void* addr) } else { - chunk->free(addr) ; + chunk->freeMem(addr) ; if(chunk->empty()) { @@ -1929,7 +1929,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 if(p[i][k]) { llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; - sPool->free(p[i][k]) ; + sPool->freeMem(p[i][k]) ; total_allocated_size -= min_size + k * stride ; p[i][k] = NULL ; } @@ -1950,7 +1950,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 if(p[i][j]) { llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; - sPool->free(p[i][j]) ; + sPool->freeMem(p[i][j]) ; total_allocated_size -= min_size + j * stride ; p[i][j] = NULL ; } @@ -1984,7 +1984,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) //de-allocation for(U32 i = 0 ; i < times; i++) { - sPool->free(p[i]) ; + sPool->freeMem(p[i]) ; p[i] = NULL ; } llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; @@ -2019,7 +2019,7 @@ void LLPrivateMemoryPoolTester::correctnessTest() //edge case char* p = sPool->allocate(0) ; - sPool->free(p) ; + sPool->freeMem(p) ; //small sized // [8 bytes, 2KB), each asks for 256 allocations and deallocations diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index a5dbabec5a..001ff9c123 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -132,7 +132,7 @@ public: void setBuffer(char* buffer, U32 buffer_size) ; char* allocate() ; - void free(void* addr) ; + void freeMem(void* addr) ; bool empty() {return !mAllocatedSlots;} bool isFull() {return mAllocatedSlots == mTotalSlots;} @@ -180,7 +180,7 @@ public: bool empty() ; char* allocate(U32 size) ; - void free(void* addr) ; + void freeMem(void* addr) ; const char* getBuffer() const {return mBuffer;} U32 getBufferSize() const {return mBufferSize;} @@ -236,7 +236,7 @@ private: public: char *allocate(U32 size) ; - void free(void* addr) ; + void freeMem(void* addr) ; void dump() ; U32 getTotalAllocatedSize() ; @@ -339,6 +339,7 @@ private: void test(U32 min_size, U32 max_size, U32 stride, U32 times, bool random_deletion, bool output_statistics) ; void testAndTime(U32 size, U32 times) ; +#if 0 public: void* operator new(size_t size) { @@ -346,7 +347,7 @@ public: } void operator delete(void* addr) { - sPool->free(addr) ; + sPool->freeMem(addr) ; } void* operator new[](size_t size) { @@ -354,8 +355,9 @@ public: } void operator delete[](void* addr) { - sPool->free(addr) ; + sPool->freeMem(addr) ; } +#endif private: static LLPrivateMemoryPoolTester* sInstance; diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 9298716022..eefcf0a9fb 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -140,7 +140,7 @@ void LLImageBase::deleteMemory(void* p) { if(sPrivatePoolp) { - sPrivatePoolp->free(p) ; + sPrivatePoolp->freeMem(p) ; } else { diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 6b1fd78733..fd2a04373b 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -598,7 +598,7 @@ void LLVertexBuffer::destroyGLBuffer() } else { - sPrivatePoolp->free(mMappedData) ; + sPrivatePoolp->freeMem(mMappedData) ; mMappedData = NULL; mEmpty = TRUE; } @@ -627,7 +627,7 @@ void LLVertexBuffer::destroyGLIndices() } else { - sPrivatePoolp->free(mMappedIndexData) ; + sPrivatePoolp->freeMem(mMappedIndexData) ; mMappedIndexData = NULL; mEmpty = TRUE; } @@ -768,7 +768,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) memset(mMappedData+oldsize, 0, newsize-oldsize); } - sPrivatePoolp->free(old); + sPrivatePoolp->freeMem(old); } else { @@ -805,7 +805,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size); } - sPrivatePoolp->free(old); + sPrivatePoolp->freeMem(old); } else { @@ -852,8 +852,8 @@ void LLVertexBuffer::freeClientBuffer() { if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) { - sPrivatePoolp->free(mMappedData) ; - sPrivatePoolp->free(mMappedIndexData) ; + sPrivatePoolp->freeMem(mMappedData) ; + sPrivatePoolp->freeMem(mMappedIndexData) ; mMappedData = NULL ; mMappedIndexData = NULL ; } -- cgit v1.3 From b594d3b04d3095f15750436910debdd5a602a872 Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 10 May 2011 21:02:20 -0600 Subject: add debug mode to track the memory allocation/deallocation. --- indra/llcommon/llmemory.cpp | 117 ++++++++++++++++++++++++++++++++++---- indra/llcommon/llmemory.h | 24 +++++++- indra/llimage/llimage.cpp | 36 ++---------- indra/llimage/llimage.h | 3 +- indra/llimage/llimagedxt.cpp | 2 +- indra/llimage/llimagej2c.cpp | 4 +- indra/llrender/llvertexbuffer.cpp | 24 ++++---- indra/newview/lltexturecache.cpp | 30 +++++----- indra/newview/lltexturefetch.cpp | 14 ++--- 9 files changed, 173 insertions(+), 81 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index dfc00b5e0a..8f65107e47 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -57,6 +57,10 @@ U32 LLMemory::sAllocatedPageSizeInKB = 0 ; U32 LLMemory::sMaxHeapSizeInKB = U32_MAX ; BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; +#if __DEBUG_PRIVATE_MEM__ +LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker; +#endif + //static void LLMemory::initClass() { @@ -1431,8 +1435,14 @@ S32 LLPrivateMemoryPool::getChunkIndex(U32 size) void LLPrivateMemoryPool::destroyPool() { lock() ; - if(mNumOfChunks > 0) + +#if 0 + if(mNumOfChunks > 0) { + //Warn: + //should crash here because there is memory leaking if reach here. + // + for(U32 i = 0 ; i < mHashFactor; i++) { while(mChunkHashList[i]) @@ -1441,11 +1451,19 @@ void LLPrivateMemoryPool::destroyPool() } } } - mChunkHashList.clear() ; - mHashFactor = 1 ; + llassert_always(mNumOfChunks == 0) ; llassert_always(mReservedPoolSize == 0) ; +#endif + + if(mNumOfChunks > 0) + { + llwarns << "There is some memory not freed when destroy the memory pool!" << llendl ; + } + mNumOfChunks = 0 ; + mChunkHashList.clear() ; + mHashFactor = 1 ; for(S32 i = 0 ; i < SUPER_ALLOCATION ; i++) { mChunkList[i] = NULL ; @@ -1750,6 +1768,21 @@ LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() { + +#if __DEBUG_PRIVATE_MEM__ + if(!sMemAllocationTracker.empty()) + { + llwarns << "there is potential memory leaking here. The list of not freed memory blocks are from: " <second << llendl ; + } + sMemAllocationTracker.clear() ; + } +#endif + #if 0 //all private pools should be released by their owners before reaching here. for(S32 i = 0 ; i < LLPrivateMemoryPool::MAX_TYPES; i++) @@ -1827,6 +1860,70 @@ void LLPrivateMemoryPoolManager::updateStatistics() } } +#if __DEBUG_PRIVATE_MEM__ +//static +char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) +{ + char* p ; + + if(!poolp) + { + p = new char[size] ; + } + else + { + p = poolp->allocate(size) ; + } + + if(p) + { + char num[16] ; + sprintf(num, " line: %d ", line) ; + std::string str(function) ; + str += num; + + sMemAllocationTracker[p] = str ; + } + + return p ; +} +#else +//static +char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) +{ + if(!poolp) + { + return new char[size] ; + } + else + { + return poolp->allocate(size) ; + } +} +#endif + +//static +void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr) +{ + if(!addr) + { + return ; + } + +#if __DEBUG_PRIVATE_MEM__ + sMemAllocationTracker.erase((char*)addr) ; +#endif + + if(poolp) + { + poolp->freeMem(addr) ; + } + else + { + delete[] addr ; + } +} + //-------------------------------------------------------------------- //class LLPrivateMemoryPoolTester //-------------------------------------------------------------------- @@ -1915,7 +2012,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 for(j = 0 ; j < levels; j++) { size = min_size + j * stride ; - p[i][j] = sPool->allocate(size) ; + p[i][j] = ALLOCATE_MEM(sPool, size) ; total_allocated_size+= size ; @@ -1931,7 +2028,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 if(p[i][k]) { llassert_always(*(U32*)p[i][k] == i && *((U32*)p[i][k] + 1) == k) ; - sPool->freeMem(p[i][k]) ; + FREE_MEM(sPool, p[i][k]) ; total_allocated_size -= min_size + k * stride ; p[i][k] = NULL ; } @@ -1952,7 +2049,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 if(p[i][j]) { llassert_always(*(U32*)p[i][j] == i && *((U32*)p[i][j] + 1) == j) ; - sPool->freeMem(p[i][j]) ; + FREE_MEM(sPool, p[i][j]) ; total_allocated_size -= min_size + j * stride ; p[i][j] = NULL ; } @@ -1977,7 +2074,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) //allocation for(U32 i = 0 ; i < times; i++) { - p[i] = sPool->allocate(size) ; + p[i] = ALLOCATE_MEM(sPool, size) ; if(!p[i]) { llerrs << "allocation failed" << llendl ; @@ -1986,7 +2083,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) //de-allocation for(U32 i = 0 ; i < times; i++) { - sPool->freeMem(p[i]) ; + FREE_MEM(sPool, p[i]) ; p[i] = NULL ; } llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; @@ -2020,8 +2117,8 @@ void LLPrivateMemoryPoolTester::correctnessTest() //to see if allocation is right. //edge case - char* p = sPool->allocate(0) ; - sPool->freeMem(p) ; + char* p = ALLOCATE_MEM(sPool, 0) ; + FREE_MEM(sPool, p) ; //small sized // [8 bytes, 2KB), each asks for 256 allocations and deallocations diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 001ff9c123..d50ae99823 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -34,6 +34,10 @@ extern S32 gDACount; extern void* ll_allocate (size_t size); extern void ll_release (void *p); +#ifndef __DEBUG_PRIVATE_MEM__ +#define __DEBUG_PRIVATE_MEM__ 0 +#endif + class LL_COMMON_API LLMemory { public: @@ -234,7 +238,6 @@ private: LLPrivateMemoryPool(S32 type) ; ~LLPrivateMemoryPool() ; -public: char *allocate(U32 size) ; void freeMem(void* addr) ; @@ -314,8 +317,27 @@ public: U32 mTotalReservedSize ; U32 mTotalAllocatedSize ; + +public: +#if __DEBUG_PRIVATE_MEM__ + static char* allocate(LLPrivateMemoryPool* poolp, U32 size, const char* function, const int line) ; + + typedef std::map mem_allocation_info_t ; + static mem_allocation_info_t sMemAllocationTracker; +#else + static char* allocate(LLPrivateMemoryPool* poolp, U32 size) ; +#endif + static void freeMem(LLPrivateMemoryPool* poolp, void* addr) ; }; +//------------------------------------------------------------------------------------- +#if __DEBUG_PRIVATE_MEM__ +#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size), __FUNCTION__, __LINE__) +#else +#define ALLOCATE_MEM(poolp, size) LLPrivateMemoryPoolManager::allocate((poolp), (size)) +#endif +#define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr)) +//------------------------------------------------------------------------------------- // //the below singleton is used to test the private memory pool. // diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index eefcf0a9fb..cfa4123b1e 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -122,32 +122,6 @@ void LLImageBase::destroyPrivatePool() } } -//static -char* LLImageBase::allocateMemory(S32 size) -{ - if(sPrivatePoolp) - { - return sPrivatePoolp->allocate(size) ; - } - else - { - return new char[size]; - } -} - -//static -void LLImageBase::deleteMemory(void* p) -{ - if(sPrivatePoolp) - { - sPrivatePoolp->freeMem(p) ; - } - else - { - delete[] (char*)p ; - } -} - // virtual void LLImageBase::dump() { @@ -181,7 +155,7 @@ void LLImageBase::sanityCheck() // virtual void LLImageBase::deleteData() { - deleteMemory(mData) ; + FREE_MEM(sPrivatePoolp, mData) ; mData = NULL; mDataSize = 0; } @@ -218,7 +192,7 @@ U8* LLImageBase::allocateData(S32 size) { deleteData(); // virtual mBadBufferAllocation = false ; - mData = (U8*)allocateMemory(size); + mData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); if (!mData) { llwarns << "allocate image data: " << size << llendl; @@ -236,7 +210,7 @@ U8* LLImageBase::allocateData(S32 size) U8* LLImageBase::reallocateData(S32 size) { LLMemType mt1(mMemType); - U8 *new_datap = (U8*)allocateMemory(size); + U8 *new_datap = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); if (!new_datap) { llwarns << "Out of memory in LLImageBase::reallocateData" << llendl; @@ -246,7 +220,7 @@ U8* LLImageBase::reallocateData(S32 size) { S32 bytes = llmin(mDataSize, size); memcpy(new_datap, mData, bytes); /* Flawfinder: ignore */ - deleteMemory(mData) ; + FREE_MEM(sPrivatePoolp, mData) ; } mData = new_datap; mDataSize = size; @@ -1601,7 +1575,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size) S32 newsize = cursize + size; reallocateData(newsize); memcpy(getData() + cursize, data, size); - deleteMemory(data); + FREE_MEM(LLImageBase::getPrivatePool(), data); } } } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index ab20ccda9e..10621623ad 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -140,8 +140,7 @@ public: static void createPrivatePool() ; static void destroyPrivatePool() ; - static char* allocateMemory(S32 size) ; - static void deleteMemory(void* p) ; + static LLPrivateMemoryPool* getPrivatePool() {return sPrivatePoolp;} private: U8 *mData; diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 81be09a412..2867f5e6f0 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -429,7 +429,7 @@ bool LLImageDXT::convertToDXR() S32 nmips = calcNumMips(width,height); S32 total_bytes = getDataSize(); U8* olddata = getData(); - U8* newdata = (U8*)allocateMemory(total_bytes); + U8* newdata = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), total_bytes); if (!newdata) { llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 1bdcba6eb5..78e5d58f14 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -372,14 +372,14 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename) } else { - U8 *data = (U8*)allocateMemory(file_size); + U8 *data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), file_size); apr_size_t bytes_read = file_size; apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read infile.close() ; if (s != APR_SUCCESS || (S32)bytes_read != file_size) { - deleteMemory(data); + FREE_MEM(LLImageBase::getPrivatePool(), data); setLastError("Unable to read entire file"); res = FALSE; } diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index fd2a04373b..67417aea43 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -544,7 +544,7 @@ void LLVertexBuffer::createGLBuffer() { static int gl_buffer_idx = 0; mGLBuffer = ++gl_buffer_idx; - mMappedData = (U8*)sPrivatePoolp->allocate(size); + mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); memset(mMappedData, 0, size); } } @@ -574,7 +574,7 @@ void LLVertexBuffer::createGLIndices() } else { - mMappedIndexData = (U8*)sPrivatePoolp->allocate(size); + mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); memset(mMappedIndexData, 0, size); static int gl_buffer_idx = 0; mGLIndices = ++gl_buffer_idx; @@ -598,7 +598,7 @@ void LLVertexBuffer::destroyGLBuffer() } else { - sPrivatePoolp->freeMem(mMappedData) ; + FREE_MEM(sPrivatePoolp, mMappedData) ; mMappedData = NULL; mEmpty = TRUE; } @@ -627,7 +627,7 @@ void LLVertexBuffer::destroyGLIndices() } else { - sPrivatePoolp->freeMem(mMappedIndexData) ; + FREE_MEM(sPrivatePoolp, mMappedIndexData) ; mMappedIndexData = NULL; mEmpty = TRUE; } @@ -759,7 +759,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) if (!useVBOs()) { U8* old = mMappedData; - mMappedData = (U8*)sPrivatePoolp->allocate(newsize); + mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, newsize); if (old) { memcpy(mMappedData, old, llmin(newsize, oldsize)); @@ -768,7 +768,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) memset(mMappedData+oldsize, 0, newsize-oldsize); } - sPrivatePoolp->freeMem(old); + FREE_MEM(sPrivatePoolp, old); } else { @@ -796,7 +796,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { //delete old buffer, keep GL buffer for now U8* old = mMappedIndexData; - mMappedIndexData = (U8*)sPrivatePoolp->allocate(new_index_size); + mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, new_index_size); if (old) { @@ -805,7 +805,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) { memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size); } - sPrivatePoolp->freeMem(old); + FREE_MEM(sPrivatePoolp, old); } else { @@ -852,8 +852,8 @@ void LLVertexBuffer::freeClientBuffer() { if(useVBOs() && sDisableVBOMapping && (mMappedData || mMappedIndexData)) { - sPrivatePoolp->freeMem(mMappedData) ; - sPrivatePoolp->freeMem(mMappedIndexData) ; + FREE_MEM(sPrivatePoolp, mMappedData) ; + FREE_MEM(sPrivatePoolp, mMappedIndexData) ; mMappedData = NULL ; mMappedIndexData = NULL ; } @@ -864,7 +864,7 @@ void LLVertexBuffer::allocateClientVertexBuffer() if(!mMappedData) { U32 size = getSize() ; - mMappedData = (U8*)sPrivatePoolp->allocate(size); + mMappedData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); memset(mMappedData, 0, size); } } @@ -874,7 +874,7 @@ void LLVertexBuffer::allocateClientIndexBuffer() if(!mMappedIndexData) { U32 size = getIndicesSize(); - mMappedIndexData = (U8*)sPrivatePoolp->allocate(size); + mMappedIndexData = (U8*)ALLOCATE_MEM(sPrivatePoolp, size); memset(mMappedIndexData, 0, size); } } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 11dff69e0c..b6e396a96f 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -113,7 +113,7 @@ public: ~LLTextureCacheWorker() { llassert_always(!haveWork()); - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); } // override this interface @@ -215,7 +215,7 @@ bool LLTextureCacheLocalFileWorker::doRead() mDataSize = 0; return true; } - mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); + mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); mBytesRead = -1; mBytesToRead = mDataSize; setPriority(LLWorkerThread::PRIORITY_LOW | mPriority); @@ -233,7 +233,7 @@ bool LLTextureCacheLocalFileWorker::doRead() // << " Bytes: " << mDataSize << " Offset: " << mOffset // << " / " << mDataSize << llendl; mDataSize = 0; // failed - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } return true; @@ -248,7 +248,7 @@ bool LLTextureCacheLocalFileWorker::doRead() { mDataSize = local_size; } - mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); + mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); S32 bytes_read = LLAPRFile::readEx(mFileName, mReadData, mOffset, mDataSize); @@ -258,7 +258,7 @@ bool LLTextureCacheLocalFileWorker::doRead() // << " Bytes: " << mDataSize << " Offset: " << mOffset // << " / " << mDataSize << llendl; mDataSize = 0; - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } else @@ -377,7 +377,7 @@ bool LLTextureCacheRemoteWorker::doRead() mDataSize = local_size; } // Allocate read buffer - mReadData = (U8*)LLImageBase::allocateMemory(mDataSize); + mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); S32 bytes_read = LLAPRFile::readEx(local_filename, mReadData, mOffset, mDataSize); if (bytes_read != mDataSize) { @@ -385,7 +385,7 @@ bool LLTextureCacheRemoteWorker::doRead() << " Bytes: " << mDataSize << " Offset: " << mOffset << " / " << mDataSize << llendl; mDataSize = 0; - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } else @@ -428,14 +428,14 @@ bool LLTextureCacheRemoteWorker::doRead() S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset; size = llmin(size, mDataSize); // Allocate the read buffer - mReadData = (U8*)LLImageBase::allocateMemory(size); + mReadData = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), size); S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, mReadData, offset, size); if (bytes_read != size) { llwarns << "LLTextureCacheWorker: " << mID << " incorrect number of bytes read from header: " << bytes_read << " / " << size << llendl; - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; mDataSize = -1; // failed done = true; @@ -465,7 +465,7 @@ bool LLTextureCacheRemoteWorker::doRead() S32 data_offset, file_size, file_offset; // Reserve the whole data buffer first - U8* data = (U8*)LLImageBase::allocateMemory(mDataSize); + U8* data = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mDataSize); // Set the data file pointers taking the read offset into account. 2 cases: if (mOffset < TEXTURE_CACHE_ENTRY_SIZE) @@ -478,7 +478,7 @@ bool LLTextureCacheRemoteWorker::doRead() // Copy the raw data we've been holding from the header cache into the new sized buffer llassert_always(mReadData); memcpy(data, mReadData, data_offset); - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } else @@ -503,7 +503,7 @@ bool LLTextureCacheRemoteWorker::doRead() llwarns << "LLTextureCacheWorker: " << mID << " incorrect number of bytes read from body: " << bytes_read << " / " << file_size << llendl; - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; mDataSize = -1; // failed done = true; @@ -595,11 +595,11 @@ bool LLTextureCacheRemoteWorker::doWrite() { // We need to write a full record in the header cache so, if the amount of data is smaller // than a record, we need to transfer the data to a buffer padded with 0 and write that - U8* padBuffer = (U8*)LLImageBase::allocateMemory(TEXTURE_CACHE_ENTRY_SIZE); + U8* padBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), TEXTURE_CACHE_ENTRY_SIZE); memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE); // Init with zeros memcpy(padBuffer, mWriteData, mDataSize); // Copy the write buffer bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size); - LLImageBase::deleteMemory(padBuffer); + FREE_MEM(LLImageBase::getPrivatePool(), padBuffer); } else { @@ -694,7 +694,7 @@ void LLTextureCacheWorker::finishWork(S32 param, bool completed) } else { - LLImageBase::deleteMemory(mReadData); + FREE_MEM(LLImageBase::getPrivatePool(), mReadData); mReadData = NULL; } } diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 806f130486..e9be45ffd0 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -816,7 +816,7 @@ void LLTextureFetchWorker::setImagePriority(F32 priority) void LLTextureFetchWorker::resetFormattedData() { - LLImageBase::deleteMemory(mBuffer); + FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); mBuffer = NULL; mBufferSize = 0; if (mFormattedImage.notNull()) @@ -887,7 +887,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mSentRequest = UNSENT; mDecoded = FALSE; mWritten = FALSE; - LLImageBase::deleteMemory(mBuffer); + FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); mBuffer = NULL; mBufferSize = 0; mHaveAllData = FALSE; @@ -1283,7 +1283,7 @@ bool LLTextureFetchWorker::doWork(S32 param) llassert_always(mBufferSize == cur_size + mRequestedSize); if(!mBufferSize)//no data received. { - LLImageBase::deleteMemory(mBuffer); + FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); mBuffer = NULL; //abort. @@ -1311,7 +1311,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded. } - U8* buffer = (U8*)LLImageBase::allocateMemory(mBufferSize); + U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), mBufferSize); if (cur_size > 0) { memcpy(buffer, mFormattedImage->getData(), cur_size); @@ -1320,7 +1320,7 @@ bool LLTextureFetchWorker::doWork(S32 param) // NOTE: setData releases current data and owns new data (buffer) mFormattedImage->setData(buffer, mBufferSize); // delete temp data - LLImageBase::deleteMemory(mBuffer); // Note: not 'buffer' (assigned in setData()) + FREE_MEM(LLImageBase::getPrivatePool(), mBuffer); // Note: not 'buffer' (assigned in setData()) mBuffer = NULL; mBufferSize = 0; mLoadedDiscard = mRequestedDiscard; @@ -1617,7 +1617,7 @@ bool LLTextureFetchWorker::processSimulatorPackets() if (buffer_size > cur_size) { /// We have new data - U8* buffer = (U8*)LLImageBase::allocateMemory(buffer_size); + U8* buffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), buffer_size); S32 offset = 0; if (cur_size > 0 && mFirstPacket > 0) { @@ -1669,7 +1669,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, if (data_size > 0) { // *TODO: set the formatted image data here directly to avoid the copy - mBuffer = (U8*)LLImageBase::allocateMemory(data_size); + mBuffer = (U8*)ALLOCATE_MEM(LLImageBase::getPrivatePool(), data_size); buffer->readAfter(channels.in(), NULL, mBuffer, data_size); mBufferSize += data_size; if (data_size < mRequestedSize && mRequestedDiscard == 0) -- cgit v1.3 From 76eca5d0bce3e303f6d77b0d16f114320830ac6a Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Tue, 19 Jul 2011 23:17:55 -0600 Subject: fix for memory alignment to 16 bytes. --- indra/llcommon/llmemory.cpp | 98 ++++++++++++++++++++++++++++----------------- indra/llcommon/llmemory.h | 7 +++- 2 files changed, 66 insertions(+), 39 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index ed28974163..6e804a94b0 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -62,7 +62,7 @@ LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sM #endif #ifndef _USE_PRIVATE_MEM_POOL_ -#define _USE_PRIVATE_MEM_POOL_ 0 +#define _USE_PRIVATE_MEM_POOL_ 1 #endif //static @@ -535,6 +535,9 @@ const char* LLMemTracker::getNextLine() //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- +//minimum slot size and minimal slot size interval +const U32 ATOMIC_MEM_SLOT = 16 ; //bytes + //minimum block sizes (page size) for small allocation, medium allocation, large allocation const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 << 10, 16 << 10} ; // @@ -542,14 +545,30 @@ const U32 MIN_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {2 << 10, 4 < const U32 MAX_BLOCK_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {64 << 10, 1 << 20, 4 << 20} ; //minimum slot sizes for small allocation, medium allocation, large allocation -const U32 MIN_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {8, 2 << 10, 512 << 10}; +const U32 MIN_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {ATOMIC_MEM_SLOT, 2 << 10, 512 << 10}; //maximum slot sizes for small allocation, medium allocation, large allocation -const U32 MAX_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {(2 << 10) - 8, (512 - 2) << 10, 4 << 20}; +const U32 MAX_SLOT_SIZES[LLPrivateMemoryPool::SUPER_ALLOCATION] = {(2 << 10) - ATOMIC_MEM_SLOT, (512 - 2) << 10, 4 << 20}; //size of a block with multiple slots can not exceed CUT_OFF_SIZE const U32 CUT_OFF_SIZE = (64 << 10) ; //64 KB +//max number of slots in a block +const U32 MAX_NUM_SLOTS_IN_A_BLOCK = llmin(MIN_BLOCK_SIZES[0] / ATOMIC_MEM_SLOT, ATOMIC_MEM_SLOT * 8) ; + +//------------------------------------------------------------- +//align val to be integer times of ATOMIC_MEM_SLOT +U32 align(U32 val) +{ + U32 aligned = (val / ATOMIC_MEM_SLOT) * ATOMIC_MEM_SLOT ; + if(aligned < val) + { + aligned += ATOMIC_MEM_SLOT ; + } + + return aligned ; +} + //------------------------------------------------------------- //class LLPrivateMemoryPool::LLMemoryBlock //------------------------------------------------------------- @@ -575,35 +594,36 @@ void LLPrivateMemoryPool::LLMemoryBlock::init(char* buffer, U32 buffer_size, U32 mSlotSize = slot_size ; mTotalSlots = buffer_size / mSlotSize ; - llassert_always(buffer_size / mSlotSize <= 256) ; //max number is 256 + llassert_always(buffer_size / mSlotSize <= MAX_NUM_SLOTS_IN_A_BLOCK) ; //max number is 128 mAllocatedSlots = 0 ; + mDummySize = 0 ; //init the bit map. - //mark free bits - S32 usage_bit_len = (mTotalSlots + 31) / 32 ; - mDummySize = usage_bit_len - 1 ; //if the mTotalSlots more than 32, needs extra space for bit map - if(mDummySize > 0) //reserve extra space from mBuffer to store bitmap if needed. + //mark free bits + if(mTotalSlots > 32) //reserve extra space from mBuffer to store bitmap if needed. { - mTotalSlots -= (mDummySize * sizeof(mUsageBits) + mSlotSize - 1) / mSlotSize ; - usage_bit_len = (mTotalSlots + 31) / 32 ; - mDummySize = usage_bit_len - 1 ;//number of 32bits reserved from mBuffer for bitmap + mDummySize = ATOMIC_MEM_SLOT ; + mTotalSlots -= (mDummySize + mSlotSize - 1) / mSlotSize ; + mUsageBits = 0 ; - if(mDummySize > 0) + S32 usage_bit_len = (mTotalSlots + 31) / 32 ; + + for(S32 i = 0 ; i < usage_bit_len - 1 ; i++) { - mUsageBits = 0 ; - for(S32 i = 0 ; i < mDummySize ; i++) - { - *((U32*)mBuffer + i) = 0 ; - } - if(mTotalSlots & 31) - { - *((U32*)mBuffer + mDummySize - 1) = (0xffffffff << (mTotalSlots & 31)) ; - } + *((U32*)mBuffer + i) = 0 ; } - } - - if(mDummySize < 1)//no extra bitmap space reserved + for(S32 i = usage_bit_len - 1 ; i < mDummySize / sizeof(U32) ; i++) + { + *((U32*)mBuffer + i) = 0xffffffff ; + } + + if(mTotalSlots & 31) + { + *((U32*)mBuffer + usage_bit_len - 2) = (0xffffffff << (mTotalSlots & 31)) ; + } + } + else//no extra bitmap space reserved { mUsageBits = 0 ; if(mTotalSlots & 31) @@ -642,7 +662,7 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() } else if(mDummySize > 0)//go to extra space { - for(S32 i = 0 ; i < mDummySize; i++) + for(S32 i = 0 ; i < mDummySize / sizeof(U32); i++) { if(*((U32*)mBuffer + i) != 0xffffffff) { @@ -668,14 +688,14 @@ char* LLPrivateMemoryPool::LLMemoryBlock::allocate() mAllocatedSlots++ ; - return mBuffer + mDummySize * sizeof(U32) + (k * 32 + idx) * mSlotSize ; + return mBuffer + mDummySize + (k * 32 + idx) * mSlotSize ; } //free a slot void LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr) { //bit index - U32 idx = ((U32)addr - (U32)mBuffer - mDummySize * sizeof(U32)) / mSlotSize ; + U32 idx = ((U32)addr - (U32)mBuffer - mDummySize) / mSlotSize ; U32* bits = &mUsageBits ; if(idx >= 32) @@ -699,7 +719,7 @@ void LLPrivateMemoryPool::LLMemoryBlock::freeMem(void* addr) //for debug use: reset the entire bitmap. void LLPrivateMemoryPool::LLMemoryBlock::resetBitMap() { - for(S32 i = 0 ; i < mDummySize ; i++) + for(S32 i = 0 ; i < mDummySize / sizeof(U32) ; i++) { *((U32*)mBuffer + i) = 0 ; } @@ -742,7 +762,10 @@ void LLPrivateMemoryPool::LLMemoryChunk::init(char* buffer, U32 buffer_size, U32 //data buffer, which can be used for allocation mDataBuffer = (char*)mFreeSpaceList + sizeof(LLMemoryBlock*) * mPartitionLevels ; - + + //alignmnet + mDataBuffer = mBuffer + align(mDataBuffer - mBuffer) ; + //init for(U32 i = 0 ; i < mBlockLevels; i++) { @@ -1306,7 +1329,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) //if the asked size larger than MAX_BLOCK_SIZE, fetch from heap directly, the pool does not manage it if(size >= CHUNK_SIZE) { - return new char[size] ; + return (char*)malloc(size) ; } char* p = NULL ; @@ -1367,7 +1390,7 @@ void LLPrivateMemoryPool::freeMem(void* addr) if(!chunk) { - delete[] (char*)addr ; //release from heap + free(addr) ; //release from heap } else { @@ -1503,7 +1526,7 @@ LLPrivateMemoryPool::LLMemoryChunk* LLPrivateMemoryPool::addChunk(S32 chunk_inde checkSize(preferred_size + overhead) ; mReservedPoolSize += preferred_size + overhead ; - char* buffer = new(std::nothrow) char[preferred_size + overhead] ; + char* buffer = (char*)malloc(preferred_size + overhead) ; if(!buffer) { return NULL ; @@ -1571,7 +1594,7 @@ void LLPrivateMemoryPool::removeChunk(LLMemoryChunk* chunk) mReservedPoolSize -= chunk->getBufferSize() ; //release memory - delete[] chunk->getBuffer() ; + free(chunk->getBuffer()) ; } U16 LLPrivateMemoryPool::findHashKey(const char* addr) @@ -1875,7 +1898,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, if(!poolp) { - p = new char[size] ; + p = (char*)malloc(size) ; } else { @@ -1901,7 +1924,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) #if _USE_PRIVATE_MEM_POOL_ if(!poolp) { - return new char[size] ; + return (char*)malloc(size) ; } else { @@ -1932,7 +1955,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr } else { - delete[] (char*)addr ; + free(addr) ; } #else free(addr) ; @@ -1942,6 +1965,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr //-------------------------------------------------------------------- //class LLPrivateMemoryPoolTester //-------------------------------------------------------------------- +#if 0 LLPrivateMemoryPoolTester* LLPrivateMemoryPoolTester::sInstance = NULL ; LLPrivateMemoryPool* LLPrivateMemoryPoolTester::sPool = NULL ; LLPrivateMemoryPoolTester::LLPrivateMemoryPoolTester() @@ -2168,5 +2192,5 @@ void LLPrivateMemoryPoolTester::fragmentationtest() //every time when asking for a new chunk during correctness test, and performance test, //print out the chunk usage statistices. } - +#endif //-------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index d3b824c6e9..26488423a3 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -226,7 +226,7 @@ public: U32 mUsageBits ; U8 mTotalSlots ; U8 mAllocatedSlots ; - U8 mDummySize ; //size of extra U32 reserved for mUsageBits. + U8 mDummySize ; //size of extra bytes reserved for mUsageBits. public: LLMemoryBlock* mPrev ; @@ -256,7 +256,7 @@ public: char* allocate(U32 size) ; void freeMem(void* addr) ; - const char* getBuffer() const {return mBuffer;} + char* getBuffer() const {return mBuffer;} U32 getBufferSize() const {return mBufferSize;} U32 getAllocatedSize() const {return mAlloatedSize;} @@ -408,9 +408,11 @@ public: #endif #define FREE_MEM(poolp, addr) LLPrivateMemoryPoolManager::freeMem((poolp), (addr)) //------------------------------------------------------------------------------------- + // //the below singleton is used to test the private memory pool. // +#if 0 class LL_COMMON_API LLPrivateMemoryPoolTester { private: @@ -481,6 +483,7 @@ void LLPrivateMemoryPoolTester::operator delete[](void* addr) sPool->free(addr) ; } #endif +#endif // LLRefCount moved to llrefcount.h // LLPointer moved to llpointer.h -- cgit v1.3 From 48d949150cd445ce1e801a7a8ee67597a965f14b Mon Sep 17 00:00:00 2001 From: Xiaohong Bao Date: Wed, 20 Jul 2011 16:05:19 -0600 Subject: add a debug setting "MemoryPrivatePoolEnabled" to turn on/off private memory pool. --- indra/llcommon/llmemory.cpp | 51 +++++++++++++++++---------------- indra/llcommon/llmemory.h | 6 ++-- indra/newview/app_settings/settings.xml | 13 ++++++++- indra/newview/llappviewer.cpp | 2 ++ 4 files changed, 45 insertions(+), 27 deletions(-) (limited to 'indra/llcommon/llmemory.h') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index eb55bdae84..0d36009fc4 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -61,10 +61,6 @@ BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; LLPrivateMemoryPoolManager::mem_allocation_info_t LLPrivateMemoryPoolManager::sMemAllocationTracker; #endif -#ifndef _USE_PRIVATE_MEM_POOL_ -#define _USE_PRIVATE_MEM_POOL_ 1 -#endif - //static void LLMemory::initClass() { @@ -1386,7 +1382,7 @@ void LLPrivateMemoryPool::freeMem(void* addr) { return ; } - + lock() ; LLMemoryChunk* chunk = findChunk((char*)addr) ; @@ -1789,7 +1785,7 @@ bool LLPrivateMemoryPool::fillHashTable(U16 start, U16 end, LLMemoryChunk* chunk //-------------------------------------------------------------------- LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::sInstance = NULL ; -LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() +LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager(BOOL enabled) { mPoolList.resize(LLPrivateMemoryPool::MAX_TYPES) ; @@ -1797,6 +1793,8 @@ LLPrivateMemoryPoolManager::LLPrivateMemoryPoolManager() { mPoolList[i] = NULL ; } + + mPrivatePoolEnabled = enabled ; } LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() @@ -1838,13 +1836,21 @@ LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() #endif } +//static +void LLPrivateMemoryPoolManager::initClass(BOOL enabled) +{ + llassert_always(!sInstance) ; + + sInstance = new LLPrivateMemoryPoolManager(enabled) ; +} + //static LLPrivateMemoryPoolManager* LLPrivateMemoryPoolManager::getInstance() { - if(!sInstance) - { - sInstance = new LLPrivateMemoryPoolManager() ; - } + //if(!sInstance) + //{ + // sInstance = new LLPrivateMemoryPoolManager(FALSE) ; + //} return sInstance ; } @@ -1860,6 +1866,11 @@ void LLPrivateMemoryPoolManager::destroyClass() LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type) { + if(!mPrivatePoolEnabled) + { + return NULL ; + } + if(!mPoolList[type]) { mPoolList[type] = new LLPrivateMemoryPool(type) ; @@ -1870,7 +1881,7 @@ LLPrivateMemoryPool* LLPrivateMemoryPoolManager::newPool(S32 type) void LLPrivateMemoryPoolManager::deletePool(LLPrivateMemoryPool* pool) { - if(pool->isEmpty()) + if(pool && pool->isEmpty()) { mPoolList[pool->getType()] = NULL ; delete pool; @@ -1907,7 +1918,7 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, { p = poolp->allocate(size) ; } - + if(p) { char num[16] ; @@ -1924,18 +1935,14 @@ char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size, //static char* LLPrivateMemoryPoolManager::allocate(LLPrivateMemoryPool* poolp, U32 size) { -#if _USE_PRIVATE_MEM_POOL_ - if(!poolp) + if(poolp) { - return (char*)malloc(size) ; + return poolp->allocate(size) ; } else { - return poolp->allocate(size) ; + return (char*)malloc(size) ; } -#else - return (char*)malloc(size) ; -#endif } #endif @@ -1951,7 +1958,6 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr sMemAllocationTracker.erase((char*)addr) ; #endif -#if _USE_PRIVATE_MEM_POOL_ if(poolp) { poolp->freeMem(addr) ; @@ -1959,10 +1965,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr else { free(addr) ; - } -#else - free(addr) ; -#endif + } } //-------------------------------------------------------------------- diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 26488423a3..f9099da612 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -367,11 +367,12 @@ private: class LL_COMMON_API LLPrivateMemoryPoolManager { private: - LLPrivateMemoryPoolManager() ; + LLPrivateMemoryPoolManager(BOOL enabled) ; ~LLPrivateMemoryPoolManager() ; -public: +public: static LLPrivateMemoryPoolManager* getInstance() ; + static void initClass(BOOL enabled) ; static void destroyClass() ; LLPrivateMemoryPool* newPool(S32 type) ; @@ -380,6 +381,7 @@ public: private: static LLPrivateMemoryPoolManager* sInstance ; std::vector mPoolList ; + BOOL mPrivatePoolEnabled; public: //debug and statistics info. diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 8ff5341297..9c065537e5 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5561,7 +5561,7 @@ Comment If set, the viewer will quit to avoid crash when memory failure happens Persist - 0 + 1 Type Boolean Value @@ -5578,6 +5578,17 @@ Value 600.0 + MemoryPrivatePoolEnabled + + Comment + Enable the private memory pool management + Persist + 1 + Type + Boolean + Value + 0 + MemProfiling Comment diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 86b34ac327..156c76e84c 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -686,6 +686,8 @@ bool LLAppViewer::init() //set the max heap size. initMaxHeapSize() ; + LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled")) ; + // write Google Breakpad minidump files to our log directory std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); logdir += gDirUtilp->getDirDelimiter(); -- cgit v1.3