ScratchpadAllocator is an allocator adapter which implements a per-thread StackAllocator (a.k.a. LinearAllocator). The purpose of this is to allow code to make fast temporary allocations from a heap without interfering with the main application heap(s). It works by maintaining a container of StackAllocators, with each StackAllocator being created on-demand per thread.
This class is useful for when you want to quickly allocate temporary memory in a function but don't want to hit the main heap for it. Allocating this memory is much faster than allocating main heap memory because it's allocated via a StackAllocator (a.k.a. LinearAllocator) with no thread synchronization required. Avoiding the main heap has the benefit of reducing memory fragmentation in that heap
There are two primary costs in this system: 1) a Futex lock/unlock in the construction of the first (and only the first) instance of a ScratchpadAllocator for a thread, and 2) the heap allocation cost needed when a ScratchpadAllocator needs to expand its memory. The large majority of the time there are no synchronization primitives required and no heap allocation done and so allocation is similar in speed to directly using a growable StackAllocator or alloca.
The end-user of ScratchpadAllocator simply creates a local instance of ScratchpadAllocator in a function, and uses its Malloc and (optionally) Free functionality. You can declare these in multiple functions, as per the example usage below. End users don't normally need to care about the ScratchpadManager class except for custom cases, and can usually leave the ScratchpadManager constructor argument NULL. However, if you don't want to use the default global ScratchpadManager then you can create one yourself and use it instead of the default one. This will result in a separate StackAllocator that you can use instead of, and in parallel to, the default one.
The application normally needs to create the default global ScratchpadManager instance which serves as the default for ScratchpadAllocator instances. You would normally do this on startup by declarating an instances of ScratchpadManager, calling its setup functions and calling SetScratchpadManager with it. The ScratchpadAllocator class instances will automatically find that global manager class via GetScratchpadManager.
There are two primary limiting requirements of ScratchpadAllocator:
EA::Allocator::ScratchpadManager gScratchpadManager;
void DoSomething2()
{
ScratchpadAllocator scratchpad;
void* p1 = scratchpad.Malloc(10);
void* p2 = scratchpad.MallocAligned(10, 64);
scratchpad.Free(p1); // Calling Free is optional, though it allows for the potential of more efficient usage of scatch memory.
scratchpad.Free(p2);
}
void DoSomething1()
{
ScratchpadAllocator scratchpad;
void* p1 = scratchpad.Malloc(10);
DoSomething2();
scratchpad.Free(p1);
}
int main(int, char**)
{
EA::Allocator::SetScratchpadManager(&gScratchpadManager);
gScratchpadManager.SetAllocatorCallbacks(ScratchpadAllocationFunction, ScratchpadFreeFunction, NULL);
// Possibly call other manager setup functions.
DoSomething1();
}