1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2012 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef GrMemoryPool_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define GrMemoryPool_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkBlockAllocator.h" 13*c8dee2aaSAndroid Build Coastguard Worker 14*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 15*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 16*c8dee2aaSAndroid Build Coastguard Worker #include <memory> 17*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits> 18*c8dee2aaSAndroid Build Coastguard Worker 19*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG 20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h" 21*c8dee2aaSAndroid Build Coastguard Worker #endif 22*c8dee2aaSAndroid Build Coastguard Worker 23*c8dee2aaSAndroid Build Coastguard Worker /** 24*c8dee2aaSAndroid Build Coastguard Worker * Allocates memory in blocks and parcels out space in the blocks for allocation requests. It is 25*c8dee2aaSAndroid Build Coastguard Worker * optimized for allocate / release speed over memory efficiency. The interface is designed to be 26*c8dee2aaSAndroid Build Coastguard Worker * used to implement operator new and delete overrides. All allocations are expected to be released 27*c8dee2aaSAndroid Build Coastguard Worker * before the pool's destructor is called. Allocations will be aligned to sizeof(std::max_align_t). 28*c8dee2aaSAndroid Build Coastguard Worker * 29*c8dee2aaSAndroid Build Coastguard Worker * All allocated objects must be released back to the memory pool before it can be destroyed. 30*c8dee2aaSAndroid Build Coastguard Worker */ 31*c8dee2aaSAndroid Build Coastguard Worker class GrMemoryPool { 32*c8dee2aaSAndroid Build Coastguard Worker public: 33*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_FORCE_8_BYTE_ALIGNMENT 34*c8dee2aaSAndroid Build Coastguard Worker // https://github.com/emscripten-core/emscripten/issues/10072 35*c8dee2aaSAndroid Build Coastguard Worker // Since Skia does not use "long double" (16 bytes), we should be ok to force it back to 8 bytes 36*c8dee2aaSAndroid Build Coastguard Worker // until emscripten is fixed. 37*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t kAlignment = 8; 38*c8dee2aaSAndroid Build Coastguard Worker #else 39*c8dee2aaSAndroid Build Coastguard Worker // Guaranteed alignment of pointer returned by allocate(). 40*c8dee2aaSAndroid Build Coastguard Worker static constexpr size_t kAlignment = alignof(std::max_align_t); 41*c8dee2aaSAndroid Build Coastguard Worker #endif 42*c8dee2aaSAndroid Build Coastguard Worker 43*c8dee2aaSAndroid Build Coastguard Worker // Smallest block size allocated on the heap (not the smallest reservation via allocate()). 44*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr size_t kMinAllocationSize = 1 << 10; 45*c8dee2aaSAndroid Build Coastguard Worker 46*c8dee2aaSAndroid Build Coastguard Worker /** 47*c8dee2aaSAndroid Build Coastguard Worker * Prealloc size is the amount of space to allocate at pool creation 48*c8dee2aaSAndroid Build Coastguard Worker * time and keep around until pool destruction. The min alloc size is 49*c8dee2aaSAndroid Build Coastguard Worker * the smallest allowed size of additional allocations. Both sizes are 50*c8dee2aaSAndroid Build Coastguard Worker * adjusted to ensure that they are at least as large as kMinAllocationSize 51*c8dee2aaSAndroid Build Coastguard Worker * and less than SkBlockAllocator::kMaxAllocationSize. 52*c8dee2aaSAndroid Build Coastguard Worker * 53*c8dee2aaSAndroid Build Coastguard Worker * Both sizes are what the pool will end up allocating from the system, and 54*c8dee2aaSAndroid Build Coastguard Worker * portions of the allocated memory is used for internal bookkeeping. 55*c8dee2aaSAndroid Build Coastguard Worker */ 56*c8dee2aaSAndroid Build Coastguard Worker static std::unique_ptr<GrMemoryPool> Make(size_t preallocSize, size_t minAllocSize); 57*c8dee2aaSAndroid Build Coastguard Worker 58*c8dee2aaSAndroid Build Coastguard Worker ~GrMemoryPool(); delete(void * p)59*c8dee2aaSAndroid Build Coastguard Worker void operator delete(void* p) { ::operator delete(p); } 60*c8dee2aaSAndroid Build Coastguard Worker 61*c8dee2aaSAndroid Build Coastguard Worker /** 62*c8dee2aaSAndroid Build Coastguard Worker * Allocates memory. The memory must be freed with release() before the GrMemoryPool is deleted. 63*c8dee2aaSAndroid Build Coastguard Worker */ 64*c8dee2aaSAndroid Build Coastguard Worker void* allocate(size_t size); 65*c8dee2aaSAndroid Build Coastguard Worker /** 66*c8dee2aaSAndroid Build Coastguard Worker * p must have been returned by allocate(). 67*c8dee2aaSAndroid Build Coastguard Worker */ 68*c8dee2aaSAndroid Build Coastguard Worker void release(void* p); 69*c8dee2aaSAndroid Build Coastguard Worker 70*c8dee2aaSAndroid Build Coastguard Worker /** 71*c8dee2aaSAndroid Build Coastguard Worker * Returns true if there are no unreleased allocations. 72*c8dee2aaSAndroid Build Coastguard Worker */ isEmpty()73*c8dee2aaSAndroid Build Coastguard Worker bool isEmpty() const { 74*c8dee2aaSAndroid Build Coastguard Worker // If size is the same as preallocSize, there aren't any heap blocks, so currentBlock() 75*c8dee2aaSAndroid Build Coastguard Worker // is the inline head block. 76*c8dee2aaSAndroid Build Coastguard Worker return fAllocator.currentBlock() == fAllocator.headBlock() && 77*c8dee2aaSAndroid Build Coastguard Worker fAllocator.currentBlock()->metadata() == 0; 78*c8dee2aaSAndroid Build Coastguard Worker } 79*c8dee2aaSAndroid Build Coastguard Worker 80*c8dee2aaSAndroid Build Coastguard Worker /** 81*c8dee2aaSAndroid Build Coastguard Worker * In debug mode, this reports the IDs of unfreed nodes via `SkDebugf`. This reporting is also 82*c8dee2aaSAndroid Build Coastguard Worker * performed automatically whenever a GrMemoryPool is destroyed. 83*c8dee2aaSAndroid Build Coastguard Worker * In release mode, this method is a no-op. 84*c8dee2aaSAndroid Build Coastguard Worker */ 85*c8dee2aaSAndroid Build Coastguard Worker void reportLeaks() const; 86*c8dee2aaSAndroid Build Coastguard Worker 87*c8dee2aaSAndroid Build Coastguard Worker /** 88*c8dee2aaSAndroid Build Coastguard Worker * Returns the total allocated size of the GrMemoryPool minus any preallocated amount 89*c8dee2aaSAndroid Build Coastguard Worker */ size()90*c8dee2aaSAndroid Build Coastguard Worker size_t size() const { return fAllocator.totalSize() - fAllocator.preallocSize(); } 91*c8dee2aaSAndroid Build Coastguard Worker 92*c8dee2aaSAndroid Build Coastguard Worker /** 93*c8dee2aaSAndroid Build Coastguard Worker * Returns the preallocated size of the GrMemoryPool 94*c8dee2aaSAndroid Build Coastguard Worker */ preallocSize()95*c8dee2aaSAndroid Build Coastguard Worker size_t preallocSize() const { 96*c8dee2aaSAndroid Build Coastguard Worker // Account for the debug-only fields in this count, the offset is 0 for release builds 97*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::is_standard_layout<GrMemoryPool>::value, ""); 98*c8dee2aaSAndroid Build Coastguard Worker return offsetof(GrMemoryPool, fAllocator) + fAllocator.preallocSize(); 99*c8dee2aaSAndroid Build Coastguard Worker } 100*c8dee2aaSAndroid Build Coastguard Worker 101*c8dee2aaSAndroid Build Coastguard Worker /** 102*c8dee2aaSAndroid Build Coastguard Worker * Frees any scratch blocks that are no longer being used. 103*c8dee2aaSAndroid Build Coastguard Worker */ resetScratchSpace()104*c8dee2aaSAndroid Build Coastguard Worker void resetScratchSpace() { 105*c8dee2aaSAndroid Build Coastguard Worker fAllocator.resetScratchSpace(); 106*c8dee2aaSAndroid Build Coastguard Worker } 107*c8dee2aaSAndroid Build Coastguard Worker 108*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG 109*c8dee2aaSAndroid Build Coastguard Worker void validate() const; 110*c8dee2aaSAndroid Build Coastguard Worker #endif 111*c8dee2aaSAndroid Build Coastguard Worker 112*c8dee2aaSAndroid Build Coastguard Worker private: 113*c8dee2aaSAndroid Build Coastguard Worker // Per-allocation overhead so that GrMemoryPool can always identify the block owning each and 114*c8dee2aaSAndroid Build Coastguard Worker // release all occupied bytes, including any resulting from alignment padding. 115*c8dee2aaSAndroid Build Coastguard Worker struct Header { 116*c8dee2aaSAndroid Build Coastguard Worker int fStart; 117*c8dee2aaSAndroid Build Coastguard Worker int fEnd; 118*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG) 119*c8dee2aaSAndroid Build Coastguard Worker int fID; // ID that can be used to track down leaks by clients. 120*c8dee2aaSAndroid Build Coastguard Worker #endif 121*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG) || defined(SK_SANITIZE_ADDRESS) 122*c8dee2aaSAndroid Build Coastguard Worker uint32_t fSentinel; // set to a known value to check for memory stomping; poisoned in ASAN mode 123*c8dee2aaSAndroid Build Coastguard Worker #endif 124*c8dee2aaSAndroid Build Coastguard Worker }; 125*c8dee2aaSAndroid Build Coastguard Worker 126*c8dee2aaSAndroid Build Coastguard Worker GrMemoryPool(size_t preallocSize, size_t minAllocSize); 127*c8dee2aaSAndroid Build Coastguard Worker 128*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG 129*c8dee2aaSAndroid Build Coastguard Worker // Because this exists preallocSize wants to use offsetof, so keep GrMemoryPool standard layout 130*c8dee2aaSAndroid Build Coastguard Worker // without depending on THashSet being standard layout. Note that std::unique_ptr may not be 131*c8dee2aaSAndroid Build Coastguard Worker // standard layout. 132*c8dee2aaSAndroid Build Coastguard Worker struct Debug{ 133*c8dee2aaSAndroid Build Coastguard Worker skia_private::THashSet<int> fAllocatedIDs; 134*c8dee2aaSAndroid Build Coastguard Worker int fAllocationCount; 135*c8dee2aaSAndroid Build Coastguard Worker }; 136*c8dee2aaSAndroid Build Coastguard Worker Debug* fDebug{nullptr}; 137*c8dee2aaSAndroid Build Coastguard Worker #endif 138*c8dee2aaSAndroid Build Coastguard Worker 139*c8dee2aaSAndroid Build Coastguard Worker SkBlockAllocator fAllocator; // Must be the last field, in order to use extra allocated space 140*c8dee2aaSAndroid Build Coastguard Worker }; 141*c8dee2aaSAndroid Build Coastguard Worker #endif 142