Movatterモバイル変換


[0]ホーム

URL:


PPTX, PDF16,531 views

Scope Stack Allocation

The document discusses the concept of scope stacks as a memory management tool for embedded systems, particularly in console games where memory limitations and fragmentation are critical issues. It explains how scope stacks provide finer control over the allocation and deallocation of memory, facilitating the management of object lifetimes and resources efficiently. The approach enhances performance by reducing fragmentation and simplifying resource cleanup through finalizers without adding significant overhead.

Embed presentation

Downloaded 93 times
Scope Stack AllocationAndreas Fredriksson, DICE<dep@dice.se>
ContentsWhat are Scope Stacks?Background – embedded systemsLinear memory allocationScope StacksBits and pieces
What are Scope Stacks?A memory management toolLinear memory layout of arbitrary object hierarchiesSupport C++ object life cycle if desiredDestructors called in correct dependency orderSuper-duper oiled-up fast!Makes debugging easier
BackgroundWhy is all this relevant?Console games are embedded systemsFixed (small) amount of memoryCan't run out of memory or you can't ship – fragmentation is a serious issueHeap allocation is very expensiveLots of code for complex heap managerBad cache localityAllocation & deallocation speed
Embedded systemsWith a global heap, memory fragmentsAssume 10-15% wasted with good allocatorCan easily get 25% wasted with poor allocatorCaused by allocating objects with mixed life time next to each otherTemporary stuff allocated next to semi-permanent stuff (system arrays etc)
Heap FragmentationEach alloc has to traverse the free list of this structure!Assuming “best fit” allocator for less fragmentationWill likely cache miss for each probed locationLarge blocks disappear quickly
Memory MapIdeally we would like fully deterministic memory mapPopular approach on consolePartition all memory up frontLoad new levelRewind level part onlyReconfigure systemsRewind both level, systemsFragmentation not possible
Linear AllocationMany games use linear allocators to achieve this kind of memory mapLinear allocators basically sit on a pointerAllocations just increment the pointerTo rewind, reset the pointerVery fast, but only suitable for POD dataNo finalizers/destructors calledUsed in Frostbite's renderer for command buffers
Linear Allocator ImplementationSimplified C++ exampleReal implementation needs checks, alignmentIn retail build, allocation will be just a few cycles 1 class LinearAllocator { 2 // ... 3     u8 *allocate(size_t size) { 4 return m_ptr += size; 5     } 6 void rewind(u8 *ptr) { 7         m_ptr = ptr; 8     } 9 // ...10     u8 *m_ptr;11 };
Using Linear AllocationWe're implementing FrogSystemA new system tied to the levelRandomly place frogs across the level as the player is moving aroundClearly the Next Big ThingDesign for linear allocationGrab all memory up frontMr FISK (c) FLTUsed with permission
FrogSystem - Linear AllocationSimplified C++ example 1 struct FrogInfo { ... }; 2 3 struct FrogSystem { 4 // ... 5 int maxFrogs; 6     FrogInfo *frogPool; 7 }; 8 9 FrogSystem* FrogSystem_init(LinearAllocator& alloc) {10     FrogSystem *self = alloc.allocate(sizeof(FrogSystem));11     self->maxFrogs = ...;12     self->frogPool = alloc.allocate(sizeof(FrogInfo) * self->maxFrogs);13 return self;14 }1516 void FrogSystem_update(FrogSystem *system) {17 // ...18 }
Resulting Memory LayoutFrogSystemFrog PoolAllocationPointPOD Data
Linear allocation limitationsWorks well until we need resource cleanupFile handles, sockets, ...Pool handles, other API resourcesThis is the “systems programming” aspectAssume frog system needs a critical sectionKernel objectMust be released when no longer used
FrogSystem – Adding a lock 1 class FrogSystem { 2     CriticalSection *m_lock; 3 4     FrogSystem(LinearAllocator& a) 5 // get memory 6     ,   m_lock((CriticalSection*) a.allocate(sizeof(CriticalSection))) 7 // ... 8     { 9 new (m_lock) CriticalSection; // construct object10     }1112     ~FrogSystem() {13         m_lock->~CriticalSection(); // destroy object14     }15 };1617 FrogSystem* FrogSystem_init(LinearAllocator& a) {18 returnnew (a.allocate(sizeof(FrogSystem))) FrogSystem(a);19 }2021 void FrogSystem_cleanup(FrogSystem *system) {22     system->~FrogSystem();23 }
Resulting Memory LayoutFrogSystemFrog PoolCritialSectAllocationPointPOD DataObject with cleanup
Linear allocation limitationsCode quickly drowns in low-level detailsLots of boilerplateWe must add a cleanup functionManually remember what resources to freeError proneIn C++, we would rather rely on destructors
Scope StacksIntroducing Scope StacksSits on top of linear allocatorRewinds part of underlying allocator when destroyedDesigned to make larger-scale system design with linear allocation possibleMaintain a list of finalizers to run when rewindingOnly worry about allocation, not cleanup
Scope Stacks, contd.Type itself is a lightweight construct 1 struct Finalizer { 2 void (*fn)(void *ptr); 3     Finalizer *chain; 4 }; 5 6 class ScopeStack { 7     LinearAllocator& m_alloc; 8 void *m_rewindPoint; 9     Finalizer *m_finalizerChain;1011 explicit ScopeStack(LinearAllocator& a);12     ~ScopeStack(); // unwind1314 template <typename T> T* newObject();15 template <typename T> T* newPOD();16 };17
Scope Stacks, contd.Can create a stack of scopes on top of a single linear allocatorOnly allocate from topmost scopeCan rewind scopes as desiredFor example init/systems/levelFiner-grained control over nested lifetimesCan also follow call stackVery elegant per-thread scratch pad
Scope Stack DiagramLinear AllocatorScopeScopeActive Scope
Scope Stack APISimple C++ interfacescope.newObject<T>(...) - allocate object with cleanup (stores finalizer)scope.newPod<T>(...) - allocate object without cleanupscope.alloc(...) - raw memory allocationCan also implement as C interfaceSimilar ideas in APR (Apache Portable Runtime)
Scope Stack ImplementationnewObject<T>() 1 template <typename T> 2 void destructorCall(void *ptr) { 3 static_cast<T*>(ptr)->~T(); 4 } 5 6 template <typename T> 7 T* ScopeStack::newObject() { 8 // Allocate memory for finalizer + object. 9     Finalizer* f = allocWithFinalizer(sizeof(T));1011 // Placement construct object in space after finalizer.12     T* result = new (objectFromFinalizer(f)) T;1314 // Link this finalizer onto the chain.15     f->fn = &destructorCall<T>;16     f->chain = m_finalizerChain;17     m_finalizerChain = f;18 return result;19 }
FrogSystem – Scope StacksCritical Section example with Scope Stack 1 class FrogSystem { 2 // ... 3     CriticalSection *m_lock; 4 5     FrogSystem(ScopeStack& scope) 6     :   m_lock(scope.newObject<CriticalSection>()) 7 // ... 8     {} 910 // no destructor needed!11 };1213 FrogSystem* FrogSystem_init(ScopeStack& scope) {14 return scope.newPod<FrogSystem>();15 }
Memory Layout (with context)FrogSystemFrog PoolCritialSect(other stuff)...AllocationPointPOD DataObject with cleanupFinalizer recordScope
Scope CleanupWith finalizer chain in place we can unwind without manual codeIterate linked listCall finalizer for objects that require cleanupPOD data still zero overheadFinalizer for C++ objects => destructor call
Per-thread allocationScratch pad = Thread-local linear allocatorConstruct nested scopes on this allocatorUtility functions can lay out arbitrary objects on scratch pad scope 1 class File; // next slide 2 3 constchar *formatString(ScopeStack& scope, constchar *fmt, ...); 4 5 void myFunction(constchar *fn) { 6     ScopeStack scratch(tls_allocator); 7 constchar *filename = formatString(scratch, "foo/bar/%s", fn); 8     File *file = scratch.newObject<File>(scratch, filename); 910     file->read(...);1112 // No cleanup required!13 }
Per-thread allocation, contd.File object allocates buffer from designed scopeDoesn't care about lifetime – its buffer and itself will live for exactly the same timeCan live on scratch pad without knowing it 1 class File { 2 private: 3     u8 *m_buffer; 4 int m_handle; 5 public: 6     File(ScopeStack& scope, constchar *filename) 7     :   m_buffer(scope.alloc(8192)) 8     ,   m_handle(open(filename, O_READ)) 9     {}1011     ~File() {12         close(m_handle);13     }14 };
Memory Layout: Scratch PadFile BufferFilenameFileAllocationPointOldAllocationPointPOD DataObject with cleanupFinalizer recordRewind PointScopeParent Scope
PIMPLC++ addicts can enjoy free PIMPL idiomBecause allocations are essentially “free”; PIMPL idiom becomes more attractiveCan slim down headers and hide all data members without concern for performance
LimitationsMust set upper bound all pool sizesCan never grow an allocationThis design style is classical in games industryBut pool sizes can vary between levels!Reconfigure after rewindBy default API not thread safeMakes sense as this is more like layout than allocationPools/other structures can still be made thread safe once memory is allocated
Limitations, contd.Doesn't map 100% to C++ object modelingBut finalizers enable RAII-like cleanupMany traditional C++ tricks become obsoletePointer swappingReference countingMust always think about lifetime and ownership when allocatingLifetime determined on global levelCan't hold on to pointers – unwind = apocalypseManage on higher level instead
ConclusionScope stacks are a system programming toolSuitable for embedded systems with few variable parameters – gamesRequires planning and commitmentPays dividends in speed and simplicitySame pointers every time – debugging easierOut of memory analysis usually very simpleEither the level runs, or doesn't runCan never fail half through
LinksToy implementation of scope stacksFor playing with, not industrial strengthhttp://pastebin.com/h7nU8JE2“Start Pre-allocating And Stop Worrying” - Noel Llopishttp://gamesfromwithin.com/start-pre-allocating-and-stop-worryingApache Portable Runtimehttp://apr.apache.org/
Questions
Bonus: what about....building an array, final size unknown?Standard approach in C++: STL vector pushInstead build linked list/dequeue on scratch padAllocate array in target scope stack once size is known..dynamic lifetime of individual objects?Allocate object pool from scope stackRequires bounding the worst case – a good idea for games anyway

Recommended

PPTX
Parallel Futures of a Game Engine
 
PPTX
Parallel Futures of a Game Engine (v2.0)
 
PDF
Siggraph2016 - The Devil is in the Details: idTech 666
PPSX
Vertex Shader Tricks by Bill Bilodeau - AMD at GDC14
PPTX
Shiny PC Graphics in Battlefield 3
PPSX
Dx11 performancereloaded
PPTX
Optimizing the Graphics Pipeline with Compute, GDC 2016
PPTX
A Step Towards Data Orientation
PDF
Rendering Techniques in Rise of the Tomb Raider
PPT
Terrain Rendering in Frostbite using Procedural Shader Splatting (Siggraph 2007)
 
PDF
Graphics Gems from CryENGINE 3 (Siggraph 2013)
PPT
Secrets of CryENGINE 3 Graphics Technology
PPTX
Low-level Shader Optimization for Next-Gen and DX11 by Emil Persson
PPTX
Five Rendering Ideas from Battlefield 3 & Need For Speed: The Run
PPTX
Rendering Technologies from Crysis 3 (GDC 2013)
PPTX
Stochastic Screen-Space Reflections
PPTX
Siggraph 2011: Occlusion culling in Alan Wake
 
PPTX
Triangle Visibility buffer
PPTX
Terrain in Battlefield 3: A Modern, Complete and Scalable System
PPTX
The Rendering Technology of Killzone 2
PDF
The Guerrilla Guide to Game Code
PPTX
Deferred shading
PPTX
4K Checkerboard in Battlefield 1 and Mass Effect Andromeda
PDF
Bindless Deferred Decals in The Surge 2
PDF
Taking Killzone Shadow Fall Image Quality Into The Next Generation
PPTX
Decima Engine: Visibility in Horizon Zero Dawn
PPTX
Past, Present and Future Challenges of Global Illumination in Games
PDF
Lighting Shading by John Hable
PPTX
How data rules the world: Telemetry in Battlefield Heroes
PPT
5 Major Challenges in Interactive Rendering

More Related Content

PPTX
Parallel Futures of a Game Engine
 
PPTX
Parallel Futures of a Game Engine (v2.0)
 
PDF
Siggraph2016 - The Devil is in the Details: idTech 666
PPSX
Vertex Shader Tricks by Bill Bilodeau - AMD at GDC14
PPTX
Shiny PC Graphics in Battlefield 3
PPSX
Dx11 performancereloaded
PPTX
Optimizing the Graphics Pipeline with Compute, GDC 2016
PPTX
A Step Towards Data Orientation
Parallel Futures of a Game Engine
 
Parallel Futures of a Game Engine (v2.0)
 
Siggraph2016 - The Devil is in the Details: idTech 666
Vertex Shader Tricks by Bill Bilodeau - AMD at GDC14
Shiny PC Graphics in Battlefield 3
Dx11 performancereloaded
Optimizing the Graphics Pipeline with Compute, GDC 2016
A Step Towards Data Orientation

What's hot

PDF
Rendering Techniques in Rise of the Tomb Raider
PPT
Terrain Rendering in Frostbite using Procedural Shader Splatting (Siggraph 2007)
 
PDF
Graphics Gems from CryENGINE 3 (Siggraph 2013)
PPT
Secrets of CryENGINE 3 Graphics Technology
PPTX
Low-level Shader Optimization for Next-Gen and DX11 by Emil Persson
PPTX
Five Rendering Ideas from Battlefield 3 & Need For Speed: The Run
PPTX
Rendering Technologies from Crysis 3 (GDC 2013)
PPTX
Stochastic Screen-Space Reflections
PPTX
Siggraph 2011: Occlusion culling in Alan Wake
 
PPTX
Triangle Visibility buffer
PPTX
Terrain in Battlefield 3: A Modern, Complete and Scalable System
PPTX
The Rendering Technology of Killzone 2
PDF
The Guerrilla Guide to Game Code
PPTX
Deferred shading
PPTX
4K Checkerboard in Battlefield 1 and Mass Effect Andromeda
PDF
Bindless Deferred Decals in The Surge 2
PDF
Taking Killzone Shadow Fall Image Quality Into The Next Generation
PPTX
Decima Engine: Visibility in Horizon Zero Dawn
PPTX
Past, Present and Future Challenges of Global Illumination in Games
PDF
Lighting Shading by John Hable
Rendering Techniques in Rise of the Tomb Raider
Terrain Rendering in Frostbite using Procedural Shader Splatting (Siggraph 2007)
 
Graphics Gems from CryENGINE 3 (Siggraph 2013)
Secrets of CryENGINE 3 Graphics Technology
Low-level Shader Optimization for Next-Gen and DX11 by Emil Persson
Five Rendering Ideas from Battlefield 3 & Need For Speed: The Run
Rendering Technologies from Crysis 3 (GDC 2013)
Stochastic Screen-Space Reflections
Siggraph 2011: Occlusion culling in Alan Wake
 
Triangle Visibility buffer
Terrain in Battlefield 3: A Modern, Complete and Scalable System
The Rendering Technology of Killzone 2
The Guerrilla Guide to Game Code
Deferred shading
4K Checkerboard in Battlefield 1 and Mass Effect Andromeda
Bindless Deferred Decals in The Surge 2
Taking Killzone Shadow Fall Image Quality Into The Next Generation
Decima Engine: Visibility in Horizon Zero Dawn
Past, Present and Future Challenges of Global Illumination in Games
Lighting Shading by John Hable

Viewers also liked

PPTX
How data rules the world: Telemetry in Battlefield Heroes
PPT
5 Major Challenges in Interactive Rendering
PPTX
SPU-Based Deferred Shading in BATTLEFIELD 3 for Playstation 3
PPTX
Battlelog - Building scalable web sites with tight game integration
PPT
Destruction Masking in Frostbite 2 using Volume Distance Fields
PPTX
Shadows & Decals: D3D10 Techniques in Frostbite (GDC'09)
 
PPTX
Building the Battlefield AI Experience
PPT
Bending the Graphics Pipeline
PPT
Stylized Rendering in Battlefield Heroes
PPTX
A Real-time Radiosity Architecture
PPT
Stable SSAO in Battlefield 3 with Selective Temporal Filtering
PPT
Introduction to Data Oriented Design
PPT
Level Design Challenges & Solutions - Mirror's Edge
PPTX
Future Directions for Compute-for-Graphics
How data rules the world: Telemetry in Battlefield Heroes
5 Major Challenges in Interactive Rendering
SPU-Based Deferred Shading in BATTLEFIELD 3 for Playstation 3
Battlelog - Building scalable web sites with tight game integration
Destruction Masking in Frostbite 2 using Volume Distance Fields
Shadows & Decals: D3D10 Techniques in Frostbite (GDC'09)
 
Building the Battlefield AI Experience
Bending the Graphics Pipeline
Stylized Rendering in Battlefield Heroes
A Real-time Radiosity Architecture
Stable SSAO in Battlefield 3 with Selective Temporal Filtering
Introduction to Data Oriented Design
Level Design Challenges & Solutions - Mirror's Edge
Future Directions for Compute-for-Graphics

Similar to Scope Stack Allocation

PDF
Practical Code & Data Design
PPTX
#OOP_D_ITS - 2nd - C++ Getting Started
PPT
Memory Management In C++
PPT
memory
PPT
Handling Exceptions In C &amp; C++ [Part B] Ver 2
PDF
RAII and ScopeGuard
PPT
C++tutorial
 
PPTX
C traps and pitfalls for C++ programmers
PPT
PPT
Object Lifetime In C C++
PDF
Operating Systems - Dynamic Memory Management
PPT
C++ Memory Management
PPTX
Session - Debugging memory stomps and other atrocities - Stefan Reinalter - T...
PPTX
#OOP_D_ITS - 3rd - Pointer And References
PPT
Memory allocation
PPT
Cpp tutorial
PPT
Memory Optimization
PPT
Memory Optimization
PPT
Composing High-Performance Memory Allocators with Heap Layers
PPT
Advance features of C++
Practical Code & Data Design
#OOP_D_ITS - 2nd - C++ Getting Started
Memory Management In C++
memory
Handling Exceptions In C &amp; C++ [Part B] Ver 2
RAII and ScopeGuard
C++tutorial
 
C traps and pitfalls for C++ programmers
Object Lifetime In C C++
Operating Systems - Dynamic Memory Management
C++ Memory Management
Session - Debugging memory stomps and other atrocities - Stefan Reinalter - T...
#OOP_D_ITS - 3rd - Pointer And References
Memory allocation
Cpp tutorial
Memory Optimization
Memory Optimization
Composing High-Performance Memory Allocators with Heap Layers
Advance features of C++

More from Electronic Arts / DICE

PPTX
GDC2019 - SEED - Towards Deep Generative Models in Game Development
PPT
SIGGRAPH 2010 - Style and Gameplay in the Mirror's Edge
PDF
SEED - Halcyon Architecture
PDF
Syysgraph 2018 - Modern Graphics Abstractions & Real-Time Ray Tracing
PPTX
Khronos Munich 2018 - Halcyon and Vulkan
PDF
CEDEC 2018 - Towards Effortless Photorealism Through Real-Time Raytracing
PPTX
CEDEC 2018 - Functional Symbiosis of Art Direction and Proceduralism
PPTX
SIGGRAPH 2018 - PICA PICA and NVIDIA Turing
PPTX
SIGGRAPH 2018 - Full Rays Ahead! From Raster to Real-Time Raytracing
PPTX
HPG 2018 - Game Ray Tracing: State-of-the-Art and Open Problems
PDF
EPC 2018 - SEED - Exploring The Collaboration Between Proceduralism & Deep Le...
PDF
DD18 - SEED - Raytracing in Hybrid Real-Time Rendering
PDF
Creativity of Rules and Patterns: Designing Procedural Systems
PPTX
Shiny Pixels and Beyond: Real-Time Raytracing at SEED
PPTX
A Certain Slant of Light - Past, Present and Future Challenges of Global Illu...
PPTX
Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite
PPTX
High Dynamic Range color grading and display in Frostbite
PPTX
FrameGraph: Extensible Rendering Architecture in Frostbite
PPTX
Lighting the City of Glass
PPTX
Photogrammetry and Star Wars Battlefront
GDC2019 - SEED - Towards Deep Generative Models in Game Development
SIGGRAPH 2010 - Style and Gameplay in the Mirror's Edge
SEED - Halcyon Architecture
Syysgraph 2018 - Modern Graphics Abstractions & Real-Time Ray Tracing
Khronos Munich 2018 - Halcyon and Vulkan
CEDEC 2018 - Towards Effortless Photorealism Through Real-Time Raytracing
CEDEC 2018 - Functional Symbiosis of Art Direction and Proceduralism
SIGGRAPH 2018 - PICA PICA and NVIDIA Turing
SIGGRAPH 2018 - Full Rays Ahead! From Raster to Real-Time Raytracing
HPG 2018 - Game Ray Tracing: State-of-the-Art and Open Problems
EPC 2018 - SEED - Exploring The Collaboration Between Proceduralism & Deep Le...
DD18 - SEED - Raytracing in Hybrid Real-Time Rendering
Creativity of Rules and Patterns: Designing Procedural Systems
Shiny Pixels and Beyond: Real-Time Raytracing at SEED
A Certain Slant of Light - Past, Present and Future Challenges of Global Illu...
Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite
High Dynamic Range color grading and display in Frostbite
FrameGraph: Extensible Rendering Architecture in Frostbite
Lighting the City of Glass
Photogrammetry and Star Wars Battlefront

Recently uploaded

PDF
Festival Fever_ Exploring the Best Music Events for Every Taste By Kevin Knas...
PDF
Remote IT Jobs in canada- career growth and flexibility.pdf
PDF
Green Chemistry, Lecture 37 DL, REACH and GHS.pdf
PPTX
Celebracion del dia delKrampusnacht.pptx
PPTX
TEMPLATE PowerPoint PROJECT 1 - GISTARIAU.pptx
PPTX
Slide rules: The development of modern slide-based instruments.pptx
PDF
SITUS TERBAIK DI ASIA DAN DI INDONESIA HANYA DI PINOQQ
PDF
Iconique Divas – "Her Voice. Her Vision"
PPTX
The History of the Renaissance Guitar.pptx
PDF
Enzo Zelocchi The Star Breaking Through Hollywood’s Noise.pdf
PDF
How Staffing Agencies in Canada Help Immigrants Find Jobs Faster.pdf
PDF
Journey Through Global Performance Arts_ Experiencing Culture Live by Produce...
PPTX
Simple Halloween Presentation for Young Kids Learning English
PPTX
The history of Whip Sigils: from solo pandemic project to band.pptx
Festival Fever_ Exploring the Best Music Events for Every Taste By Kevin Knas...
Remote IT Jobs in canada- career growth and flexibility.pdf
Green Chemistry, Lecture 37 DL, REACH and GHS.pdf
Celebracion del dia delKrampusnacht.pptx
TEMPLATE PowerPoint PROJECT 1 - GISTARIAU.pptx
Slide rules: The development of modern slide-based instruments.pptx
SITUS TERBAIK DI ASIA DAN DI INDONESIA HANYA DI PINOQQ
Iconique Divas – "Her Voice. Her Vision"
The History of the Renaissance Guitar.pptx
Enzo Zelocchi The Star Breaking Through Hollywood’s Noise.pdf
How Staffing Agencies in Canada Help Immigrants Find Jobs Faster.pdf
Journey Through Global Performance Arts_ Experiencing Culture Live by Produce...
Simple Halloween Presentation for Young Kids Learning English
The history of Whip Sigils: from solo pandemic project to band.pptx
In this document
Powered by AI

Overview of Scope Stacks and relevance for embedded systems, specifically in gaming.

Discussion on memory management tools, fragmentation issues, and the significance of efficient memory allocation in embedded systems.

Linear memory allocation approaches in games, including advantages, speed, and implementation examples.

Limitations of linear allocation concerning resource cleanup and introduction of cleanup functions.

Definition and principles of Scope Stacks, including management of object lifetimes and finalizers.

Detailed mechanisms of Scope Stacks, including C++ implementation and automatic cleanup process.

Utilization of per-thread scratch pads for allocation and lifetime management of objects.

Limitations of Scope Stacks, including constraints on dynamic allocation and implications for C++ modeling.

Final thoughts on the effectiveness of Scope Stacks in system programming and embedded systems.

Further discussions on dynamic array building and handling variable object lifetimes within Scope Stacks.

Scope Stack Allocation

  • 1.
    Scope Stack AllocationAndreasFredriksson, DICE<dep@dice.se>
  • 2.
    ContentsWhat are ScopeStacks?Background – embedded systemsLinear memory allocationScope StacksBits and pieces
  • 3.
    What are ScopeStacks?A memory management toolLinear memory layout of arbitrary object hierarchiesSupport C++ object life cycle if desiredDestructors called in correct dependency orderSuper-duper oiled-up fast!Makes debugging easier
  • 4.
    BackgroundWhy is allthis relevant?Console games are embedded systemsFixed (small) amount of memoryCan't run out of memory or you can't ship – fragmentation is a serious issueHeap allocation is very expensiveLots of code for complex heap managerBad cache localityAllocation & deallocation speed
  • 5.
    Embedded systemsWith aglobal heap, memory fragmentsAssume 10-15% wasted with good allocatorCan easily get 25% wasted with poor allocatorCaused by allocating objects with mixed life time next to each otherTemporary stuff allocated next to semi-permanent stuff (system arrays etc)
  • 6.
    Heap FragmentationEach allochas to traverse the free list of this structure!Assuming “best fit” allocator for less fragmentationWill likely cache miss for each probed locationLarge blocks disappear quickly
  • 7.
    Memory MapIdeally wewould like fully deterministic memory mapPopular approach on consolePartition all memory up frontLoad new levelRewind level part onlyReconfigure systemsRewind both level, systemsFragmentation not possible
  • 8.
    Linear AllocationMany gamesuse linear allocators to achieve this kind of memory mapLinear allocators basically sit on a pointerAllocations just increment the pointerTo rewind, reset the pointerVery fast, but only suitable for POD dataNo finalizers/destructors calledUsed in Frostbite's renderer for command buffers
  • 9.
    Linear Allocator ImplementationSimplifiedC++ exampleReal implementation needs checks, alignmentIn retail build, allocation will be just a few cycles 1 class LinearAllocator { 2 // ... 3 u8 *allocate(size_t size) { 4 return m_ptr += size; 5 } 6 void rewind(u8 *ptr) { 7 m_ptr = ptr; 8 } 9 // ...10 u8 *m_ptr;11 };
  • 10.
    Using Linear AllocationWe'reimplementing FrogSystemA new system tied to the levelRandomly place frogs across the level as the player is moving aroundClearly the Next Big ThingDesign for linear allocationGrab all memory up frontMr FISK (c) FLTUsed with permission
  • 11.
    FrogSystem - LinearAllocationSimplified C++ example 1 struct FrogInfo { ... }; 2 3 struct FrogSystem { 4 // ... 5 int maxFrogs; 6 FrogInfo *frogPool; 7 }; 8 9 FrogSystem* FrogSystem_init(LinearAllocator& alloc) {10 FrogSystem *self = alloc.allocate(sizeof(FrogSystem));11 self->maxFrogs = ...;12 self->frogPool = alloc.allocate(sizeof(FrogInfo) * self->maxFrogs);13 return self;14 }1516 void FrogSystem_update(FrogSystem *system) {17 // ...18 }
  • 12.
    Resulting Memory LayoutFrogSystemFrogPoolAllocationPointPOD Data
  • 13.
    Linear allocation limitationsWorkswell until we need resource cleanupFile handles, sockets, ...Pool handles, other API resourcesThis is the “systems programming” aspectAssume frog system needs a critical sectionKernel objectMust be released when no longer used
  • 14.
    FrogSystem – Addinga lock 1 class FrogSystem { 2 CriticalSection *m_lock; 3 4 FrogSystem(LinearAllocator& a) 5 // get memory 6 , m_lock((CriticalSection*) a.allocate(sizeof(CriticalSection))) 7 // ... 8 { 9 new (m_lock) CriticalSection; // construct object10 }1112 ~FrogSystem() {13 m_lock->~CriticalSection(); // destroy object14 }15 };1617 FrogSystem* FrogSystem_init(LinearAllocator& a) {18 returnnew (a.allocate(sizeof(FrogSystem))) FrogSystem(a);19 }2021 void FrogSystem_cleanup(FrogSystem *system) {22 system->~FrogSystem();23 }
  • 15.
    Resulting Memory LayoutFrogSystemFrogPoolCritialSectAllocationPointPOD DataObject with cleanup
  • 16.
    Linear allocation limitationsCodequickly drowns in low-level detailsLots of boilerplateWe must add a cleanup functionManually remember what resources to freeError proneIn C++, we would rather rely on destructors
  • 17.
    Scope StacksIntroducing ScopeStacksSits on top of linear allocatorRewinds part of underlying allocator when destroyedDesigned to make larger-scale system design with linear allocation possibleMaintain a list of finalizers to run when rewindingOnly worry about allocation, not cleanup
  • 18.
    Scope Stacks, contd.Typeitself is a lightweight construct 1 struct Finalizer { 2 void (*fn)(void *ptr); 3 Finalizer *chain; 4 }; 5 6 class ScopeStack { 7 LinearAllocator& m_alloc; 8 void *m_rewindPoint; 9 Finalizer *m_finalizerChain;1011 explicit ScopeStack(LinearAllocator& a);12 ~ScopeStack(); // unwind1314 template <typename T> T* newObject();15 template <typename T> T* newPOD();16 };17
  • 19.
    Scope Stacks, contd.Cancreate a stack of scopes on top of a single linear allocatorOnly allocate from topmost scopeCan rewind scopes as desiredFor example init/systems/levelFiner-grained control over nested lifetimesCan also follow call stackVery elegant per-thread scratch pad
  • 20.
    Scope Stack DiagramLinearAllocatorScopeScopeActive Scope
  • 21.
    Scope Stack APISimpleC++ interfacescope.newObject<T>(...) - allocate object with cleanup (stores finalizer)scope.newPod<T>(...) - allocate object without cleanupscope.alloc(...) - raw memory allocationCan also implement as C interfaceSimilar ideas in APR (Apache Portable Runtime)
  • 22.
    Scope Stack ImplementationnewObject<T>()1 template <typename T> 2 void destructorCall(void *ptr) { 3 static_cast<T*>(ptr)->~T(); 4 } 5 6 template <typename T> 7 T* ScopeStack::newObject() { 8 // Allocate memory for finalizer + object. 9 Finalizer* f = allocWithFinalizer(sizeof(T));1011 // Placement construct object in space after finalizer.12 T* result = new (objectFromFinalizer(f)) T;1314 // Link this finalizer onto the chain.15 f->fn = &destructorCall<T>;16 f->chain = m_finalizerChain;17 m_finalizerChain = f;18 return result;19 }
  • 23.
    FrogSystem – ScopeStacksCritical Section example with Scope Stack 1 class FrogSystem { 2 // ... 3 CriticalSection *m_lock; 4 5 FrogSystem(ScopeStack& scope) 6 : m_lock(scope.newObject<CriticalSection>()) 7 // ... 8 {} 910 // no destructor needed!11 };1213 FrogSystem* FrogSystem_init(ScopeStack& scope) {14 return scope.newPod<FrogSystem>();15 }
  • 24.
    Memory Layout (withcontext)FrogSystemFrog PoolCritialSect(other stuff)...AllocationPointPOD DataObject with cleanupFinalizer recordScope
  • 25.
    Scope CleanupWith finalizerchain in place we can unwind without manual codeIterate linked listCall finalizer for objects that require cleanupPOD data still zero overheadFinalizer for C++ objects => destructor call
  • 26.
    Per-thread allocationScratch pad= Thread-local linear allocatorConstruct nested scopes on this allocatorUtility functions can lay out arbitrary objects on scratch pad scope 1 class File; // next slide 2 3 constchar *formatString(ScopeStack& scope, constchar *fmt, ...); 4 5 void myFunction(constchar *fn) { 6 ScopeStack scratch(tls_allocator); 7 constchar *filename = formatString(scratch, "foo/bar/%s", fn); 8 File *file = scratch.newObject<File>(scratch, filename); 910 file->read(...);1112 // No cleanup required!13 }
  • 27.
    Per-thread allocation, contd.Fileobject allocates buffer from designed scopeDoesn't care about lifetime – its buffer and itself will live for exactly the same timeCan live on scratch pad without knowing it 1 class File { 2 private: 3 u8 *m_buffer; 4 int m_handle; 5 public: 6 File(ScopeStack& scope, constchar *filename) 7 : m_buffer(scope.alloc(8192)) 8 , m_handle(open(filename, O_READ)) 9 {}1011 ~File() {12 close(m_handle);13 }14 };
  • 28.
    Memory Layout: ScratchPadFile BufferFilenameFileAllocationPointOldAllocationPointPOD DataObject with cleanupFinalizer recordRewind PointScopeParent Scope
  • 29.
    PIMPLC++ addicts canenjoy free PIMPL idiomBecause allocations are essentially “free”; PIMPL idiom becomes more attractiveCan slim down headers and hide all data members without concern for performance
  • 30.
    LimitationsMust set upperbound all pool sizesCan never grow an allocationThis design style is classical in games industryBut pool sizes can vary between levels!Reconfigure after rewindBy default API not thread safeMakes sense as this is more like layout than allocationPools/other structures can still be made thread safe once memory is allocated
  • 31.
    Limitations, contd.Doesn't map100% to C++ object modelingBut finalizers enable RAII-like cleanupMany traditional C++ tricks become obsoletePointer swappingReference countingMust always think about lifetime and ownership when allocatingLifetime determined on global levelCan't hold on to pointers – unwind = apocalypseManage on higher level instead
  • 32.
    ConclusionScope stacks area system programming toolSuitable for embedded systems with few variable parameters – gamesRequires planning and commitmentPays dividends in speed and simplicitySame pointers every time – debugging easierOut of memory analysis usually very simpleEither the level runs, or doesn't runCan never fail half through
  • 33.
    LinksToy implementation ofscope stacksFor playing with, not industrial strengthhttp://pastebin.com/h7nU8JE2“Start Pre-allocating And Stop Worrying” - Noel Llopishttp://gamesfromwithin.com/start-pre-allocating-and-stop-worryingApache Portable Runtimehttp://apr.apache.org/
  • 34.
  • 35.
    Bonus: what about....buildingan array, final size unknown?Standard approach in C++: STL vector pushInstead build linked list/dequeue on scratch padAllocate array in target scope stack once size is known..dynamic lifetime of individual objects?Allocate object pool from scope stackRequires bounding the worst case – a good idea for games anyway

[8]ページ先頭

©2009-2025 Movatter.jp