Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #ifndef GrMemoryPool_DEFINED | 8 #ifndef GrMemoryPool_DEFINED |
| 9 #define GrMemoryPool_DEFINED | 9 #define GrMemoryPool_DEFINED |
| 10 | 10 |
| 11 #include "GrTypes.h" | 11 #include "GrTypes.h" |
| 12 | 12 |
| 13 /** | 13 /** |
| 14 * Allocates memory in blocks and parcels out space in the blocks for allocation | 14 * Allocates memory in blocks and parcels out space in the blocks for allocation |
| 15 * requests. It is optimized for allocate / release speed over memory | 15 * requests. It is optimized for allocate / release speed over memory |
| 16 * effeciency. The interface is designed to be used to implement operator new | 16 * efficiency. The interface is designed to be used to implement operator new |
| 17 * and delete overrides. All allocations are expected to be released before the | 17 * and delete overrides. All allocations are expected to be released before the |
| 18 * pool's destructor is called. Allocations will be 8-byte aligned. | 18 * pool's destructor is called. Allocations will be 8-byte aligned. |
| 19 */ | 19 */ |
| 20 class GrMemoryPool { | 20 class GrMemoryPool { |
| 21 public: | 21 public: |
| 22 /** | 22 /** |
| 23 * Prealloc size is the amount of space to make available at pool creation | 23 * Prealloc size is the amount of space to allocate at pool creation |
| 24 * time and keep around until pool destruction. The min alloc size is the | 24 * time and keep around until pool destruction. The min alloc size is |
| 25 * smallest allowed size of additional allocations. | 25 * the smallest allowed size of additional allocations. Both sizes are |
| 26 * adjusted to ensure that: | |
| 27 * 1. they are are 8-byte aligned | |
|
herb_g
2016/11/29 18:31:14
Generally , 8-byte alignment is not enough. You sh
| |
| 28 * 2. minAllocSize >= kSmallestMinAllocSize | |
| 29 * 3. preallocSize >= minAllocSize | |
| 30 * | |
| 31 * Both sizes is what the pool will end up allocating from the system, and | |
| 32 * portions of the allocated memory is used for internal bookkeeping. | |
| 26 */ | 33 */ |
| 27 GrMemoryPool(size_t preallocSize, size_t minAllocSize); | 34 GrMemoryPool(size_t preallocSize, size_t minAllocSize); |
| 28 | 35 |
| 29 ~GrMemoryPool(); | 36 ~GrMemoryPool(); |
| 30 | 37 |
| 31 /** | 38 /** |
| 32 * Allocates memory. The memory must be freed with release(). | 39 * Allocates memory. The memory must be freed with release(). |
| 33 */ | 40 */ |
| 34 void* allocate(size_t size); | 41 void* allocate(size_t size); |
| 35 | 42 |
| 36 /** | 43 /** |
| 37 * p must have been returned by allocate() | 44 * p must have been returned by allocate() |
| 38 */ | 45 */ |
| 39 void release(void* p); | 46 void release(void* p); |
| 40 | 47 |
| 41 /** | 48 /** |
| 42 * Returns true if there are no unreleased allocations. | 49 * Returns true if there are no unreleased allocations. |
| 43 */ | 50 */ |
| 44 bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; } | 51 bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; } |
| 45 | 52 |
| 46 /** | 53 /** |
| 47 * Returns the total allocated size of the GrMemoryPool minus any preallocat ed amount | 54 * Returns the total allocated size of the GrMemoryPool minus any preallocat ed amount |
| 48 */ | 55 */ |
| 49 size_t size() const { return fSize; } | 56 size_t size() const { return fSize; } |
| 50 | 57 |
| 58 /** | |
| 59 * Returns the preallocated size of the GrMemoryPool | |
| 60 */ | |
| 61 size_t preallocSize() const { return fHead->fSize; } | |
| 62 | |
| 63 /** | |
| 64 * Minimum value of minAllocSize constructor argument. | |
| 65 */ | |
| 66 constexpr static size_t kSmallestMinAllocSize = 1 << 10; | |
| 67 | |
| 51 private: | 68 private: |
| 52 struct BlockHeader; | 69 struct BlockHeader; |
| 53 | 70 |
| 54 static BlockHeader* CreateBlock(size_t size); | 71 static BlockHeader* CreateBlock(size_t size); |
| 55 | 72 |
| 56 static void DeleteBlock(BlockHeader* block); | 73 static void DeleteBlock(BlockHeader* block); |
| 57 | 74 |
| 58 void validate(); | 75 void validate(); |
| 59 | 76 |
| 60 struct BlockHeader { | 77 struct BlockHeader { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 74 static const uint32_t kAssignedMarker = 0xCDCDCDCD; | 91 static const uint32_t kAssignedMarker = 0xCDCDCDCD; |
| 75 static const uint32_t kFreedMarker = 0xEFEFEFEF; | 92 static const uint32_t kFreedMarker = 0xEFEFEFEF; |
| 76 | 93 |
| 77 struct AllocHeader { | 94 struct AllocHeader { |
| 78 #ifdef SK_DEBUG | 95 #ifdef SK_DEBUG |
| 79 uint32_t fSentinal; ///< known value to check for memory stomping ( e.g., (CD)*) | 96 uint32_t fSentinal; ///< known value to check for memory stomping ( e.g., (CD)*) |
| 80 #endif | 97 #endif |
| 81 BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides | 98 BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides |
| 82 }; | 99 }; |
| 83 | 100 |
| 84 enum { | |
| 85 // We assume this alignment is good enough for everybody. | |
| 86 kAlignment = 8, | |
| 87 kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), | |
| 88 kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), | |
| 89 }; | |
| 90 size_t fSize; | 101 size_t fSize; |
| 91 size_t fPreallocSize; | |
| 92 size_t fMinAllocSize; | 102 size_t fMinAllocSize; |
| 93 BlockHeader* fHead; | 103 BlockHeader* fHead; |
| 94 BlockHeader* fTail; | 104 BlockHeader* fTail; |
| 95 #ifdef SK_DEBUG | 105 #ifdef SK_DEBUG |
| 96 int fAllocationCnt; | 106 int fAllocationCnt; |
| 97 int fAllocBlockCnt; | 107 int fAllocBlockCnt; |
| 98 #endif | 108 #endif |
| 109 | |
| 110 protected: | |
| 111 enum { | |
| 112 // We assume this alignment is good enough for everybody. | |
| 113 kAlignment = 8, | |
| 114 kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment), | |
| 115 kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment), | |
| 116 }; | |
| 99 }; | 117 }; |
| 100 | 118 |
| 119 /** | |
| 120 * Variant of GrMemoryPool that can only allocate objects of a single type. It i s | |
| 121 * not as flexible as GrMemoryPool, but it has more convenient allocate() method , | |
| 122 * and more importantly, it guarantees number of objects that are preallocated a t | |
| 123 * construction or when adding a new memory block. I.e. | |
| 124 * | |
| 125 * GrMemoryPool pool(3 * sizeof(T), 1000 * sizeof(T)); | |
| 126 * pool.allocate(sizeof(T)); | |
| 127 * pool.allocate(sizeof(T)); | |
| 128 * pool.allocate(sizeof(T)); | |
| 129 * | |
| 130 * will preallocate 3 * sizeof(T) bytes and use some of those bytes for internal | |
| 131 * structures. Because of that, last allocate() call will end up allocating a ne w | |
| 132 * block of 1000 * sizeof(T) bytes. In contrast, | |
| 133 * | |
| 134 * GrObjectMemoryPool<T> pool(3, 1000); | |
| 135 * pool.allocate(); | |
| 136 * pool.allocate(); | |
| 137 * pool.allocate(); | |
| 138 * | |
| 139 * guarantees to preallocate enough memory for 3 objects of sizeof(T), so last | |
| 140 * allocate() will use preallocated memory and won't cause allocation of a new b lock. | |
| 141 * | |
| 142 * Same thing is true for the second (minAlloc) ctor argument: this class guaran tees | |
| 143 * that a newly added block will have enough space for 1000 objects of sizeof(T) , while | |
| 144 * GrMemoryPool does not. | |
| 145 */ | |
| 146 template <class T> | |
| 147 class GrObjectMemoryPool: public GrMemoryPool { | |
| 148 public: | |
| 149 /** | |
| 150 * Preallocates memory for preallocCount objects, and sets new block size to be | |
| 151 * enough to hold minAllocCount objects. | |
| 152 */ | |
| 153 GrObjectMemoryPool(size_t preallocCount, size_t minAllocCount) | |
| 154 : GrMemoryPool(CountToSize(preallocCount), | |
| 155 CountToSize(SkTMax(minAllocCount, kSmallestMinAllocCount) )) { | |
| 156 } | |
| 157 | |
| 158 /** | |
| 159 * Allocates memory for an object, but doesn't construct or otherwise initia lize it. | |
| 160 * The memory must be freed with release(). | |
| 161 */ | |
| 162 T* allocate() { return static_cast<T*>(GrMemoryPool::allocate(sizeof(T))); } | |
|
herb_g
2016/11/29 18:31:14
I think this is a very dangerous API. It is not RA
| |
| 163 | |
| 164 private: | |
| 165 constexpr static size_t kTotalObjectSize = | |
| 166 kPerAllocPad + GR_CT_ALIGN_UP(sizeof(T), kAlignment); | |
| 167 | |
| 168 constexpr static size_t CountToSize(size_t count) { | |
| 169 return kHeaderSize + count * kTotalObjectSize; | |
| 170 } | |
| 171 | |
| 172 public: | |
| 173 /** | |
| 174 * Minimum value of minAllocCount constructor argument. | |
| 175 */ | |
| 176 constexpr static size_t kSmallestMinAllocCount = | |
| 177 (GrMemoryPool::kSmallestMinAllocSize - kHeaderSize + kTotalObjectSize - 1) / | |
| 178 kTotalObjectSize; | |
| 179 }; | |
| 180 | |
| 181 template <class T> | |
| 182 constexpr size_t GrObjectMemoryPool<T>::kSmallestMinAllocCount; | |
| 183 | |
| 101 #endif | 184 #endif |
| OLD | NEW |