diff options
author | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 |
commit | 15740faf9fe9fe4be08965098bbf2947e096aeeb (patch) | |
tree | a730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/mecanim/memory.h |
Diffstat (limited to 'Runtime/mecanim/memory.h')
-rw-r--r-- | Runtime/mecanim/memory.h | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/Runtime/mecanim/memory.h b/Runtime/mecanim/memory.h new file mode 100644 index 0000000..5331051 --- /dev/null +++ b/Runtime/mecanim/memory.h @@ -0,0 +1,618 @@ +#pragma once + +#include "Runtime/mecanim/defs.h" +#include "Runtime/mecanim/types.h" +#include "Runtime/Utilities/dynamic_array.h" +#include "Runtime/Utilities/FileUtilities.h" + +#include "Runtime/Allocator/MemoryManager.h" + +#include <assert.h> +#include <new> + +#if ENABLE_MECANIM_PROFILER +#include <fstream> +#include <stack> +#include <string.h> +#include <stdlib.h> +#include <ctime> +#endif + +template <typename TYPE> class OffsetPtr; + +namespace mecanim +{ + +namespace memory +{ +#if ENABLE_MECANIM_PROFILER + class Profiler + { + public: + + struct AllocationInfo + { + AllocationInfo():m_Size(0),m_Allocator("Unknow"){} + AllocationInfo(size_t size, char const* allocator):m_Size(size),m_Allocator(allocator){} + bool operator==(AllocationInfo const& allocationInfo)const + { + return m_Size == allocationInfo.m_Size && strcmp(m_Allocator, allocationInfo.m_Allocator) == 0; + } + size_t m_Size; + char const* m_Allocator; + }; + + + typedef std::map<void*, AllocationInfo> AllocationInfos; + struct ProfilerLabel + { + ProfilerLabel():m_Label("Unknow"), m_ExclusiveSize(0),m_InclusiveSize(0),m_Parent(0),m_Count(0){} + ProfilerLabel(char const* labelId):m_Label(labelId), m_ExclusiveSize(0),m_InclusiveSize(0),m_Parent(0),m_Count(0){} + ~ProfilerLabel() + { + for(int i=0;i<m_Children.size();i++) + { + m_Children[i]->~ProfilerLabel(); + MemoryManager::LowLevelFree(m_Children[i]); + } + + m_Children.clear(); + } + + char const* m_Label; + size_t m_ExclusiveSize; + size_t m_InclusiveSize; + size_t m_Count; + AllocationInfos m_Allocations; + + ProfilerLabel* m_Parent; + std::vector<ProfilerLabel*> m_Children; + }; + + Profiler():m_Root("Root"){} + ~Profiler(){} + + static void StaticInitialize() + { + s_Profiler = UNITY_NEW(Profiler, kMemDefault)(); + s_Profiler->m_Current = &s_Profiler->m_Root; + } + + static void StaticDestroy() + { + UNITY_DELETE(s_Profiler, kMemDefault); + } + + void PushLabel(char const * label) + { + m_LabelStack.push(label); + LabelMap::iterator it = m_Label.find(label); + if(it == m_Label.end()) + it = m_Label.insert( std::make_pair(label, ProfilerLabel(label) ) ).first; + + AssertIf(it == m_Label.end()); + it->second.m_Count++; + + s_Profiler->m_Current->m_Children.push_back( new (MemoryManager::LowLevelAllocate(sizeof(ProfilerLabel))) ProfilerLabel(label) ); + ProfilerLabel* newLabel = s_Profiler->m_Current->m_Children.back(); + newLabel->m_Parent = s_Profiler->m_Current; + s_Profiler->m_Current = newLabel; + } + + void PopLabel() + { + m_LabelStack.pop(); + + ProfilerLabel* parentLabel = s_Profiler->m_Current->m_Parent; + + // If not a single allocation had been made, remove it + if(s_Profiler->m_Current->m_Allocations.size() == 0 && s_Profiler->m_Current->m_Children.size() == 0) + { + parentLabel->m_Children[parentLabel->m_Children.size()-1]->~ProfilerLabel(); + MemoryManager::LowLevelFree(parentLabel->m_Children[parentLabel->m_Children.size()-1]); + + parentLabel->m_Children.resize( parentLabel->m_Children.size()-1 ); + } + + s_Profiler->m_Current = parentLabel; + + assert(s_Profiler->m_Current != NULL); + } + + void RegisterAllocation(void* ptr, char const* alloc, size_t size = 0) + { + AssertIf(m_LabelStack.empty()); + char const* label = m_LabelStack.empty() ? "Unknow" : m_LabelStack.top(); + + std::map<char const*, ProfilerLabel>::iterator it = m_Label.find(label); + if(it == m_Label.end()) + m_Label.insert( std::make_pair(label, ProfilerLabel(label) ) ); + + m_Label[label].m_Allocations.insert( std::make_pair(ptr, AllocationInfo(size, alloc) ) ); + m_Label[label].m_ExclusiveSize += size; + + s_Profiler->m_Current->m_Allocations.insert( std::make_pair(ptr, AllocationInfo(size, alloc) ) ); + s_Profiler->m_Current->m_ExclusiveSize += size; + s_Profiler->m_Current->m_InclusiveSize += size; + + ProfilerLabel* profilerLabel = s_Profiler->m_Current->m_Parent; + while(profilerLabel!=NULL) + { + profilerLabel->m_InclusiveSize += size; + profilerLabel = profilerLabel->m_Parent; + } + + m_PointerRegister.insert( std::make_pair(ptr, std::make_pair( &m_Label[label], s_Profiler->m_Current))); + } + + void UnregisterAllocation(void* ptr) + { + if(ptr == NULL) + return; + + PointerRegister::iterator it = m_PointerRegister.find(ptr); + + assert(it!=m_PointerRegister.end()); + + if(it!=m_PointerRegister.end()) + { + ProfilerLabel* label = it->second.first; + AllocationInfos::iterator itAlloc = label->m_Allocations.find(ptr); + if(itAlloc!=label->m_Allocations.end()) + { + label->m_ExclusiveSize -= itAlloc->second.m_Size; + label->m_Allocations.erase(itAlloc); + if(label->m_Allocations.size() == 0 ) + m_Label.erase( m_Label.find(label->m_Label) ); + } + + label = it->second.second; + itAlloc = label->m_Allocations.find(ptr); + if(itAlloc != label->m_Allocations.end()) + { + size_t size = itAlloc->second.m_Size; + label->m_ExclusiveSize -= size; + label->m_InclusiveSize -= size; + label->m_Allocations.erase(itAlloc); + + ProfilerLabel* parentLabel = label->m_Parent; + + if(parentLabel != NULL && label->m_Allocations.size() == 0 && label->m_Children.size() == 0) + { + parentLabel->m_Children.erase( std::find(parentLabel->m_Children.begin(), parentLabel->m_Children.end(), label )); + label->~ProfilerLabel(); + MemoryManager::LowLevelFree(label); + } + + while(parentLabel!=NULL) + { + label = parentLabel; + parentLabel = label->m_Parent; + + label->m_InclusiveSize -= size; + if(parentLabel != NULL && label->m_Allocations.size() == 0 && label->m_Children.size() == 0) + { + parentLabel->m_Children.erase( std::find(parentLabel->m_Children.begin(), parentLabel->m_Children.end(), label )); + label->~ProfilerLabel(); + MemoryManager::LowLevelFree(label); + } + } + } + + m_PointerRegister.erase(it); + } + } + + static Profiler* GetProfiler() + { + return s_Profiler; + } + + void DumpObjectTypeMemoryInfo() + { + time_t rawtime; + struct tm * timeinfo; + + time (&rawtime); + timeinfo = localtime (&rawtime); + + string tempDir = Format("%s/ObjectTypeMemoryInfo_%.2d_%.2d_%.2d_%.2dh%.2dm%.2ds.csv", + GetApplicationFolder().c_str(), + 1900 + timeinfo->tm_year, + timeinfo->tm_mon, + timeinfo->tm_mday, + timeinfo->tm_hour, + timeinfo->tm_min, + timeinfo->tm_sec); + std::ofstream file(tempDir); + + file << "Object, Size, Count, Allocation Count" << std::endl; + + LabelMap::iterator it; + for(it=m_Label.begin();it!=m_Label.end();it++) + file << it->second.m_Label << "," << it->second.m_ExclusiveSize << "," << it->second.m_Count << "," << it->second.m_Allocations.size() << std::endl; + + file.close(); + } + + void DumpCallSiteMemoryInfo() + { + time_t rawtime; + struct tm * timeinfo; + + time (&rawtime); + timeinfo = localtime (&rawtime); + + string tempDir = Format("%s/CallSiteMemoryInfo_%.2d_%.2d_%.2d_%.2dh%.2dm%.2ds.csv", + GetApplicationFolder().c_str(), + 1900 + timeinfo->tm_year, + timeinfo->tm_mon, + timeinfo->tm_mday, + timeinfo->tm_hour, + timeinfo->tm_min, + timeinfo->tm_sec); + //std::ofstream file(tempDir); + //file.close(); + } + + protected: + static Profiler* s_Profiler; + + std::stack<char const*> m_LabelStack; + + typedef std::map<char const*, ProfilerLabel> LabelMap; + LabelMap m_Label; + + typedef std::map<void *, std::pair<ProfilerLabel*, ProfilerLabel*> > PointerRegister; + PointerRegister m_PointerRegister; + + ProfilerLabel m_Root; + ProfilerLabel* m_Current; + }; +#else + class Profiler + { + public:Profiler(){} + ~Profiler(){} + + static void StaticInitialize() + { + s_Profiler = UNITY_NEW(Profiler, kMemDefault)(); + } + + static void StaticDestroy() + { + UNITY_DELETE(s_Profiler, kMemDefault); + } + + void PushLabel(char const * label){ } + + void PopLabel(){} + + void RegisterAllocation(void* ptr, char const* alloc, size_t size = 0){ } + + void UnregisterAllocation(void* ptr){} + + void DumpObjectTypeMemoryInfo(){} + + void DumpCallSiteMemoryInfo(){} + + static Profiler* GetProfiler() + { + return s_Profiler; + } + protected: + static Profiler* s_Profiler; + }; +#endif + + class AutoScopeProfiler + { + public: + AutoScopeProfiler(char const* label) { Profiler::GetProfiler()->PushLabel(label); } + ~AutoScopeProfiler() { Profiler::GetProfiler()->PopLabel();} + }; + + #define SETPROFILERLABEL(type) mecanim::memory::AutoScopeProfiler scopeProfiler##type(#type) + + class Allocator + { + public: + std::size_t AlignAddress(std::size_t aAddr, std::size_t aAlign) + { + return aAddr + ((~aAddr + 1U) & (aAlign - 1U)); + } + + virtual void* Allocate(std::size_t size, std::size_t align) = 0 ; + virtual void Deallocate(void * p) = 0; + + template <typename TYPE> + TYPE* Construct(std::size_t align = ALIGN_OF(TYPE)) + { + + char *ptr = reinterpret_cast<char *>(Allocate(sizeof(TYPE), align)); + return new( (void *) ptr) TYPE; + } + + template <typename TYPE> + TYPE* ConstructArray(std::size_t count, std::size_t align = ALIGN_OF(TYPE)) + { + if(count > 0) + { + char *ptr = reinterpret_cast<char *>(Allocate(sizeof(TYPE)*count, align)); + return new( (void *) ptr) TYPE[count]; + } + else + { + return 0; + } + } + + template <typename TYPE> + TYPE* ConstructArray(const TYPE* input, std::size_t count, std::size_t align = ALIGN_OF(TYPE)) + { + if(count > 0) + { + TYPE *ptr = reinterpret_cast<TYPE*> (Allocate(sizeof(TYPE)*count, align)); + memcpy(ptr, input, sizeof(TYPE)*count); + return ptr; + } + else + { + return 0; + } + } + + template <typename TYPE> + void Deallocate(OffsetPtr<TYPE>& p) + { + if(!p.IsNull()) + Deallocate(p.Get()); + } + }; + + // Should be constructed with either: + // kMemAnimation + // kMemAnimationTemp + class MecanimAllocator : public Allocator + { + MemLabelId m_Label; + protected: + MecanimAllocator(MecanimAllocator const& e):Allocator(){ m_Label = e.m_Label; m_Label.SetRootHeader(GET_CURRENT_ALLOC_ROOT_HEADER());} + MecanimAllocator& operator=(MecanimAllocator const &){ return *this; } + public: + MecanimAllocator(MemLabelId label):m_Label(label){ m_Label.SetRootHeader(GET_CURRENT_ALLOC_ROOT_HEADER());} + + virtual void* Allocate(std::size_t size, std::size_t align) + { + void* p = UNITY_MALLOC_ALIGNED(m_Label, size, align); + + Profiler::GetProfiler()->RegisterAllocation(p, "MecanimAllocator", size); + + return p; + } + + virtual void Deallocate(void * p) + { + Profiler::GetProfiler()->UnregisterAllocation(p); + UNITY_FREE(m_Label, p); + } + }; + + class InPlaceAllocator : public Allocator + { + protected: + char* mP; + char* mHead; + std::size_t mMaxSize; + InPlaceAllocator(InPlaceAllocator const &):Allocator(){} + InPlaceAllocator& operator=(InPlaceAllocator const &){ return *this; } + public: + + + InPlaceAllocator(void *p, std::size_t aSize):mP(reinterpret_cast<char *>(p)),mHead(reinterpret_cast<char *>(p)), mMaxSize(aSize){}; + +// InPlaceAllocator(size_t size, MemoryLabelId label) +// { +// mHead = mP = UNITY_MALLOC_ALIGNED(label, size, 16); +// mMaxSize = aSize; +// +// } + + ~InPlaceAllocator() { } + + inline std::size_t TotalMemorySize()const { return mMaxSize; } + inline std::size_t UsedMemorySize()const { return reinterpret_cast<std::size_t>(mP) - reinterpret_cast<std::size_t>(mHead); } + inline std::size_t FreeMemorySize()const { return TotalMemorySize() - UsedMemorySize(); } + + void* GetMemory () + { + return mP; + } + + virtual void* Allocate(std::size_t n, std::size_t align) + { + char *p = reinterpret_cast<char *>(AlignAddress(reinterpret_cast<std::size_t>(mP), align)); + + // The first allocation must always be aligned already + AssertIf(mHead == mP && p != mHead); + + // assert(p+n <= mHead+mMaxSize); + + if(p+n <= mHead+mMaxSize) + { + mP = p+n; + return reinterpret_cast<void *>(p); + } + else + { + return 0; + } + } + + virtual void Deallocate(void * p) + { + AssertString("Not supported"); + } + }; + + class ChainedAllocator : public Allocator + { + ProfilerAllocationHeader* rootHeader; + protected: + + enum { + BlockAlign = 16 + }; + + struct MemoryBlock { + MemoryBlock* next; + uint8_t* headPtr; + std::size_t blockSize; + }; + + ChainedAllocator(ChainedAllocator const&):Allocator(){rootHeader = GET_CURRENT_ALLOC_ROOT_HEADER();} + ChainedAllocator& operator=(ChainedAllocator const &){ return *this; } + + std::size_t GetMemBlockSize(std::size_t aSize, std::size_t aAlign) + { + return sizeof(MemoryBlock) + aSize + aAlign - 1U; + } + + std::size_t GetAllocateSize(std::size_t aSize, std::size_t aAlign) + { + return aSize + aAlign - 1U; + } + + MemoryBlock* first; + MemoryBlock* current; + uint8_t* heapPtr; + std::size_t blockSize; + public: + ChainedAllocator(std::size_t aBlockSize):first(0),current(0),blockSize(aBlockSize) + { + rootHeader = GET_CURRENT_ALLOC_ROOT_HEADER(); + } + + ~ChainedAllocator() + { + Reset(); + } + + void Init() + { + if(first == 0) + { + size_t size = GetMemBlockSize(blockSize, BlockAlign); + void *p = UNITY_MALLOC(MemLabelId(kMemAnimationId,rootHeader), size); + Profiler::GetProfiler()->RegisterAllocation(p, "ChainedAllocator", size); + if(p) + { + current = first = new(p) MemoryBlock; + current->next = 0; + current->blockSize = blockSize; + + uint8_t* head = reinterpret_cast<uint8_t*>(p); + heapPtr = current->headPtr = reinterpret_cast<uint8_t*>( AlignAddress( reinterpret_cast<std::size_t>(head + sizeof(MemoryBlock)), BlockAlign)); + } + } + } + + void Reset() + { + MemoryBlock* c = first; + while(c != 0) + { + void* p = reinterpret_cast<void*>(c); + c = c->next; + Profiler::GetProfiler()->UnregisterAllocation(p); + UNITY_FREE(kMemAnimation, p); + } + current = first = 0; + heapPtr = 0; + } + + void Reserve(std::size_t size) + { + if(size > 0) + { + if(first == 0) + { + size_t size1 = GetMemBlockSize(size, BlockAlign); + void *p = UNITY_MALLOC(MemLabelId(kMemAnimationId,rootHeader), size1); + Profiler::GetProfiler()->RegisterAllocation(p, "ChainedAllocator", size1); + + if(p) + { + current = first = new(p) MemoryBlock; + current->next = 0; + current->blockSize = size; + + uint8_t* head = reinterpret_cast<uint8_t*>(p); + heapPtr = current->headPtr = reinterpret_cast<uint8_t*>( AlignAddress( reinterpret_cast<std::size_t>(head + sizeof(MemoryBlock)), BlockAlign)); + } + } + else + { + size_t size1 = GetMemBlockSize(size, BlockAlign); + void *p = UNITY_MALLOC(MemLabelId(kMemAnimationId,rootHeader), size1); + Profiler::GetProfiler()->RegisterAllocation(p, "ChainedAllocator", size1); + if(p) + { + current->next = new(p) MemoryBlock; + current = current->next; + current->next = 0; + current->blockSize = size > blockSize ? size : blockSize; + + uint8_t* head = reinterpret_cast<uint8_t*>(p); + heapPtr = current->headPtr = reinterpret_cast<uint8_t*>( AlignAddress( reinterpret_cast<std::size_t>(head + sizeof(MemoryBlock)), BlockAlign)); + } + } + } + } + + // Limit case are + // no memory left in current block, allocate a new block + // no memory left in system, bail out + virtual void* Allocate(std::size_t size, std::size_t align) + { + Init(); + + std::size_t s = GetAllocateSize(size, align); + + // Not enough memory left in current block, allocate a new block + if( heapPtr + s > current->headPtr + current->blockSize) + { + // If not enough memory left in system, bail out + // If the requested size is bigger than the block size, allocate at least a block big enough for this request. + size_t size1 = GetMemBlockSize(size > blockSize ? size : blockSize, BlockAlign); + void *p = UNITY_MALLOC(MemLabelId(kMemAnimationId,rootHeader), size1); + Profiler::GetProfiler()->RegisterAllocation(p, "ChainedAllocator", size1); + if(p) + { + current->next = new(p) MemoryBlock; + current = current->next; + current->next = 0; + current->blockSize = size > blockSize ? size : blockSize; + + uint8_t* head = reinterpret_cast<uint8_t*>(p); + heapPtr = current->headPtr = reinterpret_cast<uint8_t*>( AlignAddress( reinterpret_cast<std::size_t>(head + sizeof(MemoryBlock)), BlockAlign)); + } + else + return 0; + } + + uint8_t *p = reinterpret_cast<uint8_t *>(AlignAddress(reinterpret_cast<std::size_t>(heapPtr), align)); + heapPtr = p+size; + return reinterpret_cast<void *>(p); + } + + virtual void Deallocate(void * p) + { + assert(true); + } + }; + +} + +} |