From 4e6a1106fadeff45cd4adc9133c61d15b604b766 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Tue, 12 Jul 2011 18:59:45 -0300 Subject: [PATCH] allocator remake --- CMakeLists.txt | 1 + src/allocator.cpp | 220 +++++++++++++++++++++++----------------------- src/allocator.h | 86 +++++++++++------- 3 files changed, 165 insertions(+), 142 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 64508f63..cffcc39a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,6 +120,7 @@ IF(WIN32) ADD_DEFINITIONS(-DWIN32_NO_CONSOLE) ELSE(WIN32) SET(SOURCES ${SOURCES} src/framework/platform/x11platform.cpp) + ADD_DEFINITIONS(-D_DEBUG_MEMORY) SET(ADDITIONAL_LIBRARIES pthread GLU) ENDIF(WIN32) diff --git a/src/allocator.cpp b/src/allocator.cpp index 97f48f5d..a66f2ddb 100644 --- a/src/allocator.cpp +++ b/src/allocator.cpp @@ -1,28 +1,39 @@ +#ifdef _DEBUG_MEMORY + #include "allocator.h" -#include +#include +#include #include -#if defined(REG_EIP) -# define MACHINE_X86 -# define REGFORMAT "0x%08x" -# define ADDRTYPE unsigned int -#elif defined(REG_RIP) -# define MACHINE_X86_64 -# define REGFORMAT "0x%016lx" -# define ADDRTYPE long unsigned int -#endif +bool allocatorEnabled = false; +Allocator *allocator = NULL; -Allocator Allocator::m_instance __attribute__((init_priority(101))); +void disableAllocator() { allocatorEnabled = false; } +void enableAllocator() { allocatorEnabled = true; } +bool isAllocatorEnabled() { return allocatorEnabled; } -static void addr2line(ADDRTYPE address, const char* name, bool viewSource = false) +class Initializer { +public: + Initializer() { + allocator = new Allocator; + enableAllocator(); + } + ~Initializer() { + disableAllocator(); + Allocator *tmp = allocator; + allocator = NULL; + delete tmp; + } +}; +Initializer initializer __attribute__((init_priority(101))); + +static void addr2line(void *address, const char* name, bool viewSource = false) { char tmpbuf[1024]; char *pos; - printf(REGFORMAT": ", address); - - snprintf(tmpbuf, sizeof(tmpbuf), "addr2line --functions --demangle -e %s "REGFORMAT, name, address); + snprintf(tmpbuf, sizeof(tmpbuf), "addr2line --functions --demangle -e %s %p", name, address); FILE *output = popen(tmpbuf, "r"); if(output) { @@ -95,63 +106,63 @@ static void addr2line(ADDRTYPE address, const char* name, bool viewSource = fals printf("\n"); } -Allocator::Allocator() : m_inside(false) +Allocator::Allocator() { - } Allocator::~Allocator() { +#ifdef _REENTRANT boost::recursive_mutex::scoped_lock lock(m_allocatorLock); +#endif dumpLeaks(); - m_inside = true; + disableAllocator(); for(AllocationBlocksList::iterator it = m_allocationsBlocks.begin(), end = m_allocationsBlocks.end(); it != end; ++it) { AllocationBlock* block = (*it); - block->~AllocationBlock(); + free(block->backtraceBuffer); free(block); } m_allocationsBlocks.clear(); - m_allocationAddresses.clear(); - m_inside = false; + enableAllocator(); } -//TODO: dump leaks to a file void Allocator::dumpLeaks() { +#ifdef _REENTRANT boost::recursive_mutex::scoped_lock lock(m_allocatorLock); +#endif - m_inside = true; + disableAllocator(); - if(m_allocationAddresses.size() > 0) { - uint32_t definitelyLostBytes = 0; - uint32_t blockNumber = 1; - uint32_t countRecords = 0; - uint32_t numberOfLeakedBlocks = 0; - uint32_t numberOfBlocks = m_allocationsBlocks.size(); + unsigned int definitelyLostBytes = 0; + unsigned int blockNumber = 1; + unsigned int countRecords = 0; + unsigned int numberOfLeakedBlocks = 0; + unsigned int numberOfBlocks = m_allocationsBlocks.size(); - - for(AllocationBlocksList::iterator it = m_allocationsBlocks.begin(), end = m_allocationsBlocks.end(); it != end; ++it) { - AllocationBlock* block = (*it); - if(block->records != 0) { - numberOfLeakedBlocks++; - } + for(AllocationBlocksList::iterator it = m_allocationsBlocks.begin(), end = m_allocationsBlocks.end(); it != end; ++it) { + AllocationBlock* block = (*it); + if(block->records != 0) { + numberOfLeakedBlocks++; } + } + if(numberOfLeakedBlocks > 0) { printf("== LOST BLOCKS:\n"); for(AllocationBlocksList::iterator it = m_allocationsBlocks.begin(), end = m_allocationsBlocks.end(); it != end; ++it) { AllocationBlock* block = (*it); if(block->records != 0) { - uint32_t lostBytes = block->bytes * block->records; + unsigned int lostBytes = block->bytes * block->records; definitelyLostBytes += lostBytes; countRecords += block->records; printf("%d bytes in %d block\'s records are definitely lost in loss %d of %d\n", - lostBytes, block->records, blockNumber, numberOfLeakedBlocks); + lostBytes, block->records, blockNumber, numberOfLeakedBlocks); char **strings = backtrace_symbols(block->backtraceBuffer, block->backtraceSize); for(int i = 0; i < block->backtraceSize; i++) { @@ -161,7 +172,7 @@ void Allocator::dumpLeaks() printf("\tby "); } std::string str = strings[i]; - addr2line((ADDRTYPE)block->backtraceBuffer[i], str.substr(0, str.find('(')).c_str()); + addr2line(block->backtraceBuffer[i], str.substr(0, str.find('(')).c_str()); } printf("\n"); free(strings); @@ -176,7 +187,7 @@ void Allocator::dumpLeaks() printf("leaked blocks: %d in %d blocks\n", numberOfLeakedBlocks, numberOfBlocks); } - m_inside = false; + enableAllocator(); } void printBacktrace() @@ -191,137 +202,128 @@ void printBacktrace() printf("\tat "); } std::string str = strings[i]; - addr2line((ADDRTYPE)buffer[i], str.substr(0, str.find('(')).c_str()); + addr2line(buffer[i], str.substr(0, str.find('(')).c_str()); } printf("\n"); free(strings); } -//TODO: dump allocator memory stats by blocks to a file - -AllocationBlock* Allocator::findBlock(void **backtraceBuffer, int backtraceSize, uint32_t bytes) +AllocationBlock* Allocator::findBlock(void **backtraceBuffer, int backtraceSize, unsigned int bytes) { - for(AllocationBlocksList::iterator it = m_allocationsBlocks.begin(), end = m_allocationsBlocks.end(); it != end; ++it) { - AllocationBlock* block = (*it); + AllocationBlock blockToFind; + blockToFind.backtraceBuffer = backtraceBuffer; + blockToFind.backtraceSize = backtraceSize; + blockToFind.bytes = bytes; - if(block->bytes != bytes || block->backtraceSize != backtraceSize) { - continue; - } - - bool isSame = true; - for(int i = 0; i < backtraceSize; i++) { - if(block->backtraceBuffer[i] != backtraceBuffer[i]) { - isSame = false; - break; - } - } - - if(isSame) { - return block; - } - } + auto it = m_allocationsBlocks.find(&blockToFind); + if(it != m_allocationsBlocks.end()) + return (*it); return NULL; } void *Allocator::allocate(size_t bytes) { +#ifdef _REENTRANT boost::recursive_mutex::scoped_lock lock(m_allocatorLock); +#endif - if(m_inside) { + if(!isAllocatorEnabled()) { return malloc(bytes); } else { - void* p = malloc(bytes + sizeof(ADDRTYPE)); - void* p2 = (void*)((ADDRTYPE)p + sizeof(ADDRTYPE)); + disableAllocator(); - m_inside = true; - - static void* buffer[128]; + void* p = malloc(bytes + sizeof(void *)); + void* usedPtr = (void *)((char *)p + sizeof(void *)); + static void *buffer[128]; int size = backtrace(buffer, 128); + AllocationBlock* block = findBlock(&buffer[1], size - 1, bytes); - AllocationBlock* block = findBlock(&buffer[1], size-1, bytes); if(!block) { - block = (AllocationBlock *) malloc(sizeof(AllocationBlock)); + block = (AllocationBlock *)malloc(sizeof(AllocationBlock)); - block->backtraceBuffer = (void**) malloc((sizeof(void*)) * (size - 1)); - block->backtraceSize = size-1; + block->backtraceBuffer = (void **)malloc(sizeof(void*) * (size - 1)); + block->backtraceSize = size - 1; block->bytes = bytes; block->records = 0; - for(int i=0;ibacktraceBuffer[i] = buffer[i+1]; - } - m_allocationsBlocks.push_front(block); + m_allocationsBlocks.insert(block); } block->records += 1; + *((void **)p) = (void *)block; - m_allocationAddresses.push_front(block); - *(ADDRTYPE *)p = (ADDRTYPE)m_allocationAddresses.begin()._M_node; - - m_inside = false; - - return p2; + enableAllocator(); + return usedPtr; } } -void Allocator::deallocate(void* p) +void Allocator::deallocate(void *p) { +#ifdef _REENTRANT boost::recursive_mutex::scoped_lock lock(m_allocatorLock); +#endif - if(m_inside) { + if(!isAllocatorEnabled()) { free(p); } else if(p == NULL) { - m_inside = true; + disableAllocator(); printf("attempt to delete NULL address\n"); printBacktrace(); - m_inside = false; - return; + enableAllocator(); } else { - void *p2 = (void*)((ADDRTYPE)p - sizeof(ADDRTYPE)); + disableAllocator(); - if(!m_inside) { - m_inside = true; + void *allocatedPtr = (void *)((char *)p - sizeof(void *)); + AllocationBlock *block = (AllocationBlock *)(*((void **)allocatedPtr)); - AllocationsAddressesMap::iterator it((std::__detail::_List_node_base*)(*(ADDRTYPE*)p2)); + block->records--; + memset(allocatedPtr, 0, block->bytes + sizeof(void *)); - AllocationBlock* block = (*it); - block->records -= 1; - memset(p2, 0x00, block->bytes); + free(allocatedPtr); - m_allocationAddresses.erase(it); - - m_inside = false; - - free(p2); - } else { - free(p); - } + enableAllocator(); } } -void* operator new(size_t bytes, int dummy) +void *operator new(size_t bytes, int dummy) { - return Allocator::instance()->allocate(bytes); + if(allocator) + return allocator->allocate(bytes); + return malloc(bytes); } -void* operator new(size_t bytes) +void *operator new(size_t bytes) { - return Allocator::instance()->allocate(bytes); + if(allocator) + return allocator->allocate(bytes); + return malloc(bytes); } -void* operator new[](size_t bytes) +void *operator new[](size_t bytes) { - return Allocator::instance()->allocate(bytes); + if(allocator) + return allocator->allocate(bytes); + return malloc(bytes); } void operator delete(void *p) { - Allocator::instance()->deallocate(p); + if(allocator) + allocator->deallocate(p); + else + free(p); } -void operator delete[](void* p) +void operator delete[](void *p) { - Allocator::instance()->deallocate(p); + if(allocator) + allocator->deallocate(p); + else + free(p); } + +#endif // _DEBUG_MEMORY diff --git a/src/allocator.h b/src/allocator.h index dd428c85..58f86c77 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -1,31 +1,57 @@ #ifndef __ALLOCATOR_H__ #define __ALLOCATOR_H__ -#include -#include -#include +#ifdef _DEBUG_MEMORY + +#include + +#ifdef _REENTRANT #include +#endif -class Allocator; - -struct AllocationBlock +struct AllocationBlock { - ~AllocationBlock() { free(backtraceBuffer); } - - uint32_t bytes; - uint32_t records; + unsigned int bytes; void** backtraceBuffer; - uint8_t backtraceSize; - - friend class Allocator; + unsigned char backtraceSize; + unsigned int records; }; -//TODO: allocattion tags -/* -struct AllocationTag -{ - std::_List_node_base *listNode; -};*/ +struct block_hash : std::unary_function { + std::size_t operator()(const AllocationBlock *block) const { + struct HashKey { + unsigned int bytes; + void *backtraceTop[3]; + unsigned char backtraceSize; + } hashKey; + + hashKey.bytes = block->bytes; + for(int i=0;i<3;++i) { + if(i < block->backtraceSize) + hashKey.backtraceTop[i] = block->backtraceBuffer[i]; + else + hashKey.backtraceTop[i] = NULL; + } + hashKey.backtraceSize = block->backtraceSize; + + //std::hash hasher; + return 1;//hasher(hashKey); + } +}; + +struct block_equal_to : std::binary_function { + bool operator()(const AllocationBlock* a, const AllocationBlock *b) const + { + if(a->bytes != b->bytes || a->backtraceSize != b->backtraceSize) + return false; + for(int i=0;ibacktraceSize;++i) + if(a->backtraceBuffer[i] != b->backtraceBuffer[i]) + return false; + return true; + } +}; + +//TODO: use mem tags class Allocator { @@ -34,34 +60,28 @@ public: ~Allocator(); void *allocate(size_t bytes); - void deallocate(void* p); + void deallocate(void *p); void dumpLeaks(); - static Allocator* instance() { - return &m_instance; - } - private: - AllocationBlock* findBlock(void **backtrace, int backtraceSize, uint32_t bytes); + AllocationBlock* findBlock(void** backtraceBuffer, int backtraceSize, unsigned int bytes); - typedef std::list AllocationBlocksList; + typedef std::unordered_set AllocationBlocksList; AllocationBlocksList m_allocationsBlocks; - typedef std::list AllocationsAddressesMap; - AllocationsAddressesMap m_allocationAddresses; - +#ifdef _REENTRANT boost::recursive_mutex m_allocatorLock; - bool m_inside; - - static Allocator m_instance; +#endif }; void* operator new(size_t bytes, int dummy); void* operator new(size_t bytes); void* operator new[](size_t bytes); void operator delete(void *p); -void operator delete[](void* p); +void operator delete[](void *p); + +#endif // _DEBUG_MEMORY #endif