Flutter Engine
The Flutter Engine
|
#include <SkBlockAllocator.h>
Classes | |
class | Block |
class | BlockIter |
struct | ByteRange |
Public Types | |
enum class | GrowthPolicy : int { kFixed , kLinear , kFibonacci , kExponential , kLast = kExponential } |
enum | ReserveFlags : unsigned { kIgnoreGrowthPolicy_Flag = 0b01 , kIgnoreExistingBytes_Flag = 0b10 , kNo_ReserveFlags = 0b00 } |
Public Member Functions | |
SkBlockAllocator (GrowthPolicy policy, size_t blockIncrementBytes, size_t additionalPreallocBytes=0) | |
~SkBlockAllocator () | |
void | operator delete (void *p) |
size_t | totalSize () const |
size_t | totalUsableSpace () const |
size_t | totalSpaceInUse () const |
size_t | preallocSize () const |
size_t | preallocUsableSpace () const |
int | metadata () const |
void | setMetadata (int value) |
template<size_t Align, size_t Padding = 0> | |
ByteRange | allocate (size_t size) |
template<size_t Align = 1, size_t Padding = 0> | |
void | reserve (size_t size, ReserveFlags flags=kNo_ReserveFlags) |
const Block * | currentBlock () const |
Block * | currentBlock () |
const Block * | headBlock () const |
Block * | headBlock () |
template<size_t Align, size_t Padding = 0> | |
Block * | owningBlock (const void *ptr, int start) |
template<size_t Align, size_t Padding = 0> | |
const Block * | owningBlock (const void *ptr, int start) const |
Block * | findOwningBlock (const void *ptr) |
const Block * | findOwningBlock (const void *ptr) const |
void | releaseBlock (Block *block) |
void | stealHeapBlocks (SkBlockAllocator *other) |
void | reset () |
void | resetScratchSpace () |
BlockIter< true, false > | blocks () |
BlockIter< true, true > | blocks () const |
BlockIter< false, false > | rblocks () |
BlockIter< false, true > | rblocks () const |
Static Public Member Functions | |
template<size_t Align = 1, size_t Padding = 0> | |
static constexpr size_t | BlockOverhead () |
template<size_t Align = 1, size_t Padding = 0> | |
static constexpr size_t | Overhead () |
Static Public Attributes | |
static constexpr int | kMaxAllocationSize = 1 << 29 |
static constexpr int | kGrowthPolicyCount = static_cast<int>(GrowthPolicy::kLast) + 1 |
Friends | |
class | BlockAllocatorTestAccess |
class | TBlockListTestAccess |
SkBlockAllocator provides low-level support for a block allocated arena with a dynamic tail that tracks space reservations within each block. Its APIs provide the ability to reserve space, resize reservations, and release reservations. It will automatically create new blocks if needed and destroy all remaining blocks when it is destructed. It assumes that anything allocated within its blocks has its destructors called externally. It is recommended that SkBlockAllocator is wrapped by a higher-level allocator that uses the low-level APIs to implement a simpler, purpose-focused API w/o having to worry as much about byte-level concerns.
SkBlockAllocator has no limit to its total size, but each allocation is limited to 512MB (which should be sufficient for Skia's use cases). This upper allocation limit allows all internal operations to be performed using 'int' and avoid many overflow checks. Static asserts are used to ensure that those operations would not overflow when using the largest possible values.
Possible use modes:
Definition at line 56 of file SkBlockAllocator.h.
|
strong |
Enumerator | |
---|---|
kFixed | |
kLinear | |
kFibonacci | |
kExponential | |
kLast |
Definition at line 62 of file SkBlockAllocator.h.
enum SkBlockAllocator::ReserveFlags : unsigned |
Enumerator | |
---|---|
kIgnoreGrowthPolicy_Flag | |
kIgnoreExistingBytes_Flag | |
kNo_ReserveFlags |
Definition at line 285 of file SkBlockAllocator.h.
SkBlockAllocator::SkBlockAllocator | ( | GrowthPolicy | policy, |
size_t | blockIncrementBytes, | ||
size_t | additionalPreallocBytes = 0 |
||
) |
Definition at line 17 of file SkBlockAllocator.cpp.
|
inline |
Definition at line 187 of file SkBlockAllocator.h.
SkBlockAllocator::ByteRange SkBlockAllocator::allocate | ( | size_t | size | ) |
Reserve space that will hold 'size' bytes. This will automatically allocate a new block if there is not enough available space in the current block to provide 'size' bytes. The returned ByteRange tuple specifies the Block owning the reserved memory, the full byte range, and the aligned offset within that range to use for the user-facing pointer. The following invariants hold:
Invariant #3, when Padding > 0, allows intermediate allocators to embed metadata along with the allocations. If the Padding bytes are used for some 'struct Meta', then ptr(alignedOffset - sizeof(Meta)) can be safely used as a Meta* if Meta's alignment requirements are less than or equal to the alignment specified in allocate<>. This can be easily guaranteed by using the pattern:
allocate<max(UserAlign, alignof(Meta)), sizeof(Meta)>(userSize);
This ensures that ptr(alignedOffset) will always satisfy UserAlign and ptr(alignedOffset - sizeof(Meta)) will always satisfy alignof(Meta). Alternatively, memcpy can be used to read and write values between start and alignedOffset without worrying about alignment requirements of the metadata.
For over-aligned allocations, the alignedOffset (as an int) may not be a multiple of Align, but the result of ptr(alignedOffset) will be a multiple of Align.
Definition at line 566 of file SkBlockAllocator.h.
|
staticconstexpr |
Helper to calculate the minimum number of bytes needed for heap block size, under the assumption that Align will be the requested alignment of the first call to allocate(). Ex. To store N instances of T in a heap block, the 'blockIncrementBytes' should be set to BlockOverhead<alignof(T)>() + N * sizeof(T) when making the SkBlockAllocator.
Definition at line 521 of file SkBlockAllocator.h.
|
inline |
Clients can iterate over all active Blocks in the SkBlockAllocator using for loops:
Forward iteration from head to tail block (or non-const variant): for (const Block* b : this->blocks()) { } Reverse iteration from tail to head block: for (const Block* b : this->rblocks()) { }
It is safe to call releaseBlock() on the active block while looping.
Definition at line 741 of file SkBlockAllocator.h.
|
inline |
Definition at line 744 of file SkBlockAllocator.h.
|
inline |
Definition at line 316 of file SkBlockAllocator.h.
|
inline |
Return a pointer to the start of the current block. This will never be null.
Definition at line 315 of file SkBlockAllocator.h.
SkBlockAllocator::Block * SkBlockAllocator::findOwningBlock | ( | const void * | ptr | ) |
Find the owning block of the allocated pointer, 'p'. Without any additional information this is O(N) on the number of allocated blocks.
Definition at line 86 of file SkBlockAllocator.cpp.
|
inline |
Definition at line 346 of file SkBlockAllocator.h.
|
inline |
Definition at line 319 of file SkBlockAllocator.h.
|
inline |
Definition at line 318 of file SkBlockAllocator.h.
|
inline |
Get the current value of the allocator-level metadata (a user-oriented slot). This is separate from any block-level metadata, but can serve a similar purpose to compactly support data collections on top of SkBlockAllocator.
Definition at line 248 of file SkBlockAllocator.h.
|
inline |
Definition at line 188 of file SkBlockAllocator.h.
|
staticconstexpr |
Helper to calculate the minimum number of bytes needed for a preallocation, under the assumption that Align will be the requested alignment of the first call to allocate(). Ex. To preallocate a SkSBlockAllocator to hold N instances of T, its arge should be Overhead<alignof(T)>() + N * sizeof(T)
Definition at line 527 of file SkBlockAllocator.h.
SkBlockAllocator::Block * SkBlockAllocator::owningBlock | ( | const void * | ptr, |
int | start | ||
) |
Return the block that owns the allocated 'ptr'. Assuming that earlier, an allocation was returned as {b, start, alignedOffset, end}, and 'p = b->ptr(alignedOffset)', then a call to 'owningBlock<Align, Padding>(p, start) == b'.
If calling code has already made a pointer to their metadata, i.e. 'm = p - Padding', then 'owningBlock<Align, 0>(m, start)' will also return b, allowing you to recover the block from the metadata pointer.
If calling code has access to the original alignedOffset, this function should not be used since the owning block is just 'p - alignedOffset', regardless of original Align or Padding.
Definition at line 606 of file SkBlockAllocator.h.
|
inline |
Definition at line 337 of file SkBlockAllocator.h.
|
inline |
Return the total number of bytes that were pre-allocated for the SkBlockAllocator. This will include 'additionalPreallocBytes' passed to the constructor, and represents what the total size would become after a call to reset().
Definition at line 230 of file SkBlockAllocator.h.
|
inline |
Return the usable size of the inline head block; this will be equal to 'additionalPreallocBytes' plus any alignment padding that the system had to add to Block. The returned value represents what could be allocated before a heap block is be created.
Definition at line 239 of file SkBlockAllocator.h.
|
inline |
Definition at line 747 of file SkBlockAllocator.h.
|
inline |
Definition at line 750 of file SkBlockAllocator.h.
void SkBlockAllocator::releaseBlock | ( | Block * | block | ) |
Explicitly free an entire block, invalidating any remaining allocations from the block. SkBlockAllocator will release all alive blocks automatically when it is destroyed, but this function can be used to reclaim memory over the lifetime of the allocator. The provided 'block' pointer must have previously come from a call to currentBlock() or allocate().
If 'block' represents the inline-allocated head block, its cursor and metadata are instead reset to their defaults.
If the block is not the head block, it may be kept as a scratch block to be reused for subsequent allocation requests, instead of making an entirely new block. A scratch block is not visible when iterating over blocks but is reported in the total size of the allocator.
Definition at line 100 of file SkBlockAllocator.cpp.
void SkBlockAllocator::reserve | ( | size_t | size, |
ReserveFlags | flags = kNo_ReserveFlags |
||
) |
Ensure the block allocator has 'size' contiguous available bytes. After calling this function, currentBlock()->avail<Align, Padding>() may still report less than 'size' if the reserved space was added as a scratch block. This is done so that anything remaining in the current block can still be used if a smaller-than-size allocation is requested. If 'size' is requested by a subsequent allocation, the scratch block will automatically be activated and the request will not itself trigger any malloc.
The optional 'flags' controls how the input size is allocated; by default it will attempt to use available contiguous bytes in the current block and will respect the growth policy of the allocator.
Definition at line 543 of file SkBlockAllocator.h.
void SkBlockAllocator::reset | ( | ) |
Explicitly free all blocks (invalidating all allocations), and resets the head block to its default state. The allocator-level metadata is reset to 0 as well.
Definition at line 169 of file SkBlockAllocator.cpp.
void SkBlockAllocator::resetScratchSpace | ( | ) |
Remove any reserved scratch space, either from calling reserve() or releaseBlock().
Definition at line 194 of file SkBlockAllocator.cpp.
|
inline |
Set the current value of the allocator-level metadata.
Definition at line 253 of file SkBlockAllocator.h.
void SkBlockAllocator::stealHeapBlocks | ( | SkBlockAllocator * | other | ) |
Detach every heap-allocated block owned by 'other' and concatenate them to this allocator's list of blocks. This memory is now managed by this allocator. Since this only transfers ownership of a Block, and a Block itself does not move, any previous allocations remain valid and associated with their original Block instances. SkBlockAllocator-level functions that accept allocated pointers (e.g. findOwningBlock), must now use this allocator and not 'other' for these allocations.
The head block of 'other' cannot be stolen, so higher-level allocators and memory structures must handle that data differently.
Definition at line 154 of file SkBlockAllocator.cpp.
size_t SkBlockAllocator::totalSize | ( | ) | const |
Return the total number of bytes of the allocator, including its instance overhead, per-block overhead and space used for allocations.
Definition at line 55 of file SkBlockAllocator.cpp.
size_t SkBlockAllocator::totalSpaceInUse | ( | ) | const |
Return the total number of usable bytes that have been reserved by allocations. This will be less than or equal to totalUsableSpace().
Definition at line 77 of file SkBlockAllocator.cpp.
size_t SkBlockAllocator::totalUsableSpace | ( | ) | const |
Return the total number of bytes usable for allocations. This includes bytes that have been reserved already by a call to allocate() and bytes that are still available. It is totalSize() minus all allocator and block-level overhead.
Definition at line 65 of file SkBlockAllocator.cpp.
|
friend |
Definition at line 414 of file SkBlockAllocator.h.
|
friend |
Definition at line 415 of file SkBlockAllocator.h.
|
inlinestaticconstexpr |
Definition at line 69 of file SkBlockAllocator.h.
|
inlinestaticconstexpr |
Definition at line 60 of file SkBlockAllocator.h.