Adds DynamicArena allocator that grows by fixed chunk size, fixes #2142.
Changes fixed size arenas to new dynamic arenas with reasonable chunk sizes (may require tuning), refs #1842 This was SVN commit r13916.
This commit is contained in:
parent
fbee618ac8
commit
e24ce51029
@ -1,4 +1,4 @@
|
||||
/* Copyright (c) 2010 Wildfire Games
|
||||
/* Copyright (c) 2013 Wildfire Games
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@ -83,6 +83,91 @@ private:
|
||||
|
||||
LIB_API void TestArena();
|
||||
|
||||
|
||||
/**
|
||||
* allocator design parameters:
|
||||
* - grow dynamically with a fixed chunkSize
|
||||
* - for frequent allocations of size << chunkSize
|
||||
* - no reallocations, pointers remain valid
|
||||
**/
|
||||
class DynamicArena
|
||||
{
|
||||
struct ArenaChunk
|
||||
{
|
||||
bool Available(size_t size) const
|
||||
{
|
||||
return size <= (capacity - end);
|
||||
}
|
||||
|
||||
// Must check Available first or this may return an invalid address
|
||||
uintptr_t Allocate(size_t size)
|
||||
{
|
||||
uintptr_t ptr = storage + end;
|
||||
end += size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uintptr_t storage;
|
||||
size_t end;
|
||||
size_t capacity;
|
||||
ArenaChunk* next;
|
||||
};
|
||||
|
||||
NONCOPYABLE(DynamicArena);
|
||||
public:
|
||||
DynamicArena(size_t chunkSize) : chunkSize(chunkSize), head(NULL)
|
||||
{
|
||||
AllocateNewChunk();
|
||||
}
|
||||
|
||||
~DynamicArena()
|
||||
{
|
||||
ArenaChunk* chunk = head;
|
||||
while (chunk != NULL)
|
||||
{
|
||||
ArenaChunk* next = chunk->next;
|
||||
free(chunk);
|
||||
chunk = next;
|
||||
}
|
||||
}
|
||||
|
||||
void AllocateNewChunk()
|
||||
{
|
||||
// For efficiency, do a single allocation with the ArenaChunk and its storage
|
||||
ArenaChunk* next = head;
|
||||
head = (ArenaChunk*)malloc(sizeof(ArenaChunk) + chunkSize);
|
||||
ENSURE(head);
|
||||
head->storage = sizeof(ArenaChunk) + uintptr_t(head);
|
||||
head->end = 0;
|
||||
head->capacity = chunkSize;
|
||||
head->next = next;
|
||||
}
|
||||
|
||||
void* allocate(size_t size)
|
||||
{
|
||||
if (size > chunkSize)
|
||||
{
|
||||
debug_warn(L"DynamicArena cannot allocate more than chunk size");
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
else if (!head->Available(size))
|
||||
AllocateNewChunk();
|
||||
|
||||
return (void*)head->Allocate(size);
|
||||
}
|
||||
|
||||
void deallocate(void* UNUSED(p), size_t UNUSED(size))
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const size_t chunkSize;
|
||||
ArenaChunk *head;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Allocators
|
||||
|
||||
#endif // #ifndef INCLUDED_ALLOCATORS_ARENA
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2012 Wildfire Games.
|
||||
/* Copyright (C) 2013 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -419,11 +419,11 @@ void ShaderModelRenderer::Render(const RenderModifierPtr& modifier, const CShade
|
||||
* list in each, rebinding the GL state whenever it changes.
|
||||
*/
|
||||
|
||||
Allocators::Arena<> arena(1*MiB);
|
||||
typedef ProxyAllocator<void*, Allocators::Arena<> > ArenaProxyAllocator;
|
||||
Allocators::DynamicArena arena(256 * KiB);
|
||||
typedef ProxyAllocator<void*, Allocators::DynamicArena > ArenaProxyAllocator;
|
||||
typedef std::vector<CModel*, ArenaProxyAllocator> ModelList_t;
|
||||
typedef boost::unordered_map<SMRMaterialBucketKey, ModelList_t, SMRMaterialBucketKeyHash,
|
||||
std::equal_to<SMRMaterialBucketKey>, ProxyAllocator<void*, Allocators::Arena<> >
|
||||
std::equal_to<SMRMaterialBucketKey>, ProxyAllocator<void*, Allocators::DynamicArena >
|
||||
> MaterialBuckets_t;
|
||||
MaterialBuckets_t materialBuckets((MaterialBuckets_t::allocator_type(arena)));
|
||||
|
||||
|
@ -684,12 +684,12 @@ void CPatchRData::Update(CSimulation2* simulation)
|
||||
|
||||
// std::map types with appropriate arena allocators and default comparison operator
|
||||
#define POOLED_BATCH_MAP(Key, Value) \
|
||||
std::map<Key, Value, std::less<Key>, ProxyAllocator<std::pair<Key const, Value>, Allocators::Arena<> > >
|
||||
std::map<Key, Value, std::less<Key>, ProxyAllocator<std::pair<Key const, Value>, Allocators::DynamicArena > >
|
||||
|
||||
// Equivalent to "m[k]", when it returns a arena-allocated std::map (since we can't
|
||||
// use the default constructor in that case)
|
||||
template<typename M>
|
||||
typename M::mapped_type& PooledMapGet(M& m, const typename M::key_type& k, Allocators::Arena<>& arena)
|
||||
typename M::mapped_type& PooledMapGet(M& m, const typename M::key_type& k, Allocators::DynamicArena& arena)
|
||||
{
|
||||
return m.insert(std::make_pair(k,
|
||||
typename M::mapped_type(typename M::mapped_type::key_compare(), typename M::mapped_type::allocator_type(arena))
|
||||
@ -698,7 +698,7 @@ typename M::mapped_type& PooledMapGet(M& m, const typename M::key_type& k, Alloc
|
||||
|
||||
// Equivalent to "m[k]", when it returns a std::pair of arena-allocated std::vectors
|
||||
template<typename M>
|
||||
typename M::mapped_type& PooledPairGet(M& m, const typename M::key_type& k, Allocators::Arena<>& arena)
|
||||
typename M::mapped_type& PooledPairGet(M& m, const typename M::key_type& k, Allocators::DynamicArena& arena)
|
||||
{
|
||||
return m.insert(std::make_pair(k, std::make_pair(
|
||||
typename M::mapped_type::first_type(typename M::mapped_type::first_type::allocator_type(arena)),
|
||||
@ -706,10 +706,8 @@ typename M::mapped_type& PooledPairGet(M& m, const typename M::key_type& k, Allo
|
||||
))).first->second;
|
||||
}
|
||||
|
||||
static const size_t ARENA_SIZE = 4*MiB; // this should be enough for fairly huge maps
|
||||
|
||||
// Each multidraw batch has a list of index counts, and a list of pointers-to-first-indexes
|
||||
typedef std::pair<std::vector<GLint, ProxyAllocator<GLint, Allocators::Arena<> > >, std::vector<void*, ProxyAllocator<void*, Allocators::Arena<> > > > BatchElements;
|
||||
typedef std::pair<std::vector<GLint, ProxyAllocator<GLint, Allocators::DynamicArena > >, std::vector<void*, ProxyAllocator<void*, Allocators::DynamicArena > > > BatchElements;
|
||||
|
||||
// Group batches by index buffer
|
||||
typedef POOLED_BATCH_MAP(CVertexBuffer*, BatchElements) IndexBufferBatches;
|
||||
@ -723,7 +721,7 @@ typedef POOLED_BATCH_MAP(CTerrainTextureEntry*, VertexBufferBatches) TextureBatc
|
||||
void CPatchRData::RenderBases(const std::vector<CPatchRData*>& patches, const CShaderDefines& context,
|
||||
ShadowMap* shadow, bool isDummyShader, const CShaderProgramPtr& dummy)
|
||||
{
|
||||
Allocators::Arena<> arena(ARENA_SIZE);
|
||||
Allocators::DynamicArena arena(1 * MiB);
|
||||
|
||||
TextureBatches batches (TextureBatches::key_compare(), (TextureBatches::allocator_type(arena)));
|
||||
|
||||
@ -871,7 +869,7 @@ void CPatchRData::RenderBases(const std::vector<CPatchRData*>& patches, const CS
|
||||
*/
|
||||
struct SBlendBatch
|
||||
{
|
||||
SBlendBatch(Allocators::Arena<>& arena) :
|
||||
SBlendBatch(Allocators::DynamicArena& arena) :
|
||||
m_Batches(VertexBufferBatches::key_compare(), VertexBufferBatches::allocator_type(arena))
|
||||
{
|
||||
}
|
||||
@ -886,12 +884,12 @@ struct SBlendBatch
|
||||
struct SBlendStackItem
|
||||
{
|
||||
SBlendStackItem(CVertexBuffer::VBChunk* v, CVertexBuffer::VBChunk* i,
|
||||
const std::vector<CPatchRData::SSplat>& s, Allocators::Arena<>& arena) :
|
||||
const std::vector<CPatchRData::SSplat>& s, Allocators::DynamicArena& arena) :
|
||||
vertices(v), indices(i), splats(s.begin(), s.end(), SplatStack::allocator_type(arena))
|
||||
{
|
||||
}
|
||||
|
||||
typedef std::vector<CPatchRData::SSplat, ProxyAllocator<CPatchRData::SSplat, Allocators::Arena<> > > SplatStack;
|
||||
typedef std::vector<CPatchRData::SSplat, ProxyAllocator<CPatchRData::SSplat, Allocators::DynamicArena > > SplatStack;
|
||||
CVertexBuffer::VBChunk* vertices;
|
||||
CVertexBuffer::VBChunk* indices;
|
||||
SplatStack splats;
|
||||
@ -900,9 +898,9 @@ struct SBlendStackItem
|
||||
void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches, const CShaderDefines& context,
|
||||
ShadowMap* shadow, bool isDummyShader, const CShaderProgramPtr& dummy)
|
||||
{
|
||||
Allocators::Arena<> arena(ARENA_SIZE);
|
||||
Allocators::DynamicArena arena(1 * MiB);
|
||||
|
||||
typedef std::vector<SBlendBatch, ProxyAllocator<SBlendBatch, Allocators::Arena<> > > BatchesStack;
|
||||
typedef std::vector<SBlendBatch, ProxyAllocator<SBlendBatch, Allocators::DynamicArena > > BatchesStack;
|
||||
BatchesStack batches((BatchesStack::allocator_type(arena)));
|
||||
|
||||
CShaderDefines contextBlend = context;
|
||||
@ -914,7 +912,7 @@ void CPatchRData::RenderBlends(const std::vector<CPatchRData*>& patches, const C
|
||||
// to avoid heavy reallocations
|
||||
batches.reserve(256);
|
||||
|
||||
typedef std::vector<SBlendStackItem, ProxyAllocator<SBlendStackItem, Allocators::Arena<> > > BlendStacks;
|
||||
typedef std::vector<SBlendStackItem, ProxyAllocator<SBlendStackItem, Allocators::DynamicArena > > BlendStacks;
|
||||
BlendStacks blendStacks((BlendStacks::allocator_type(arena)));
|
||||
blendStacks.reserve(patches.size());
|
||||
|
||||
|
@ -57,7 +57,7 @@ static u8 GetArrayType(uint32 arrayType)
|
||||
|
||||
CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(ScriptInterface& scriptInterface, ISerializer& serializer) :
|
||||
m_ScriptInterface(scriptInterface), m_Serializer(serializer), m_Rooter(m_ScriptInterface),
|
||||
m_ScriptBackrefsArena(16*MiB), m_ScriptBackrefs(backrefs_t::key_compare(), ScriptBackrefsAlloc(m_ScriptBackrefsArena)), m_ScriptBackrefsNext(1)
|
||||
m_ScriptBackrefsArena(1 * MiB), m_ScriptBackrefs(backrefs_t::key_compare(), ScriptBackrefsAlloc(m_ScriptBackrefsArena)), m_ScriptBackrefsNext(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -65,10 +65,10 @@ private:
|
||||
ISerializer& m_Serializer;
|
||||
|
||||
// Pooling helps since we do a lot of short-lived allocations
|
||||
typedef ProxyAllocator<std::pair<JSObject* const, u32>, Allocators::Arena<> > ScriptBackrefsAlloc;
|
||||
typedef ProxyAllocator<std::pair<JSObject* const, u32>, Allocators::DynamicArena> ScriptBackrefsAlloc;
|
||||
typedef std::map<JSObject*, u32, std::less<JSObject*>, ScriptBackrefsAlloc> backrefs_t;
|
||||
|
||||
Allocators::Arena<> m_ScriptBackrefsArena;
|
||||
Allocators::DynamicArena m_ScriptBackrefsArena;
|
||||
backrefs_t m_ScriptBackrefs;
|
||||
u32 m_ScriptBackrefsNext;
|
||||
u32 GetScriptBackrefTag(JSObject* obj);
|
||||
|
Loading…
Reference in New Issue
Block a user