blob: 26a763430ff013becafd30c49009630f46690d23 [file] [log] [blame]
bsalomon@google.com4da34e32012-06-19 15:40:27 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrMemoryPool_DEFINED
9#define GrMemoryPool_DEFINED
10
11#include "GrTypes.h"
Brian Salomona5002c32017-03-28 16:51:02 -040012#ifdef SK_DEBUG
13#include "SkTHash.h"
14#endif
bsalomon@google.com4da34e32012-06-19 15:40:27 +000015
16/**
17 * Allocates memory in blocks and parcels out space in the blocks for allocation
18 * requests. It is optimized for allocate / release speed over memory
dskibae4cd0062016-11-29 06:50:35 -080019 * efficiency. The interface is designed to be used to implement operator new
bsalomon@google.com4da34e32012-06-19 15:40:27 +000020 * and delete overrides. All allocations are expected to be released before the
21 * pool's destructor is called. Allocations will be 8-byte aligned.
22 */
23class GrMemoryPool {
24public:
25 /**
dskibae4cd0062016-11-29 06:50:35 -080026 * Prealloc size is the amount of space to allocate at pool creation
27 * time and keep around until pool destruction. The min alloc size is
28 * the smallest allowed size of additional allocations. Both sizes are
29 * adjusted to ensure that:
30 * 1. they are are 8-byte aligned
31 * 2. minAllocSize >= kSmallestMinAllocSize
32 * 3. preallocSize >= minAllocSize
33 *
34 * Both sizes is what the pool will end up allocating from the system, and
35 * portions of the allocated memory is used for internal bookkeeping.
bsalomon@google.com4da34e32012-06-19 15:40:27 +000036 */
37 GrMemoryPool(size_t preallocSize, size_t minAllocSize);
38
39 ~GrMemoryPool();
40
41 /**
42 * Allocates memory. The memory must be freed with release().
43 */
44 void* allocate(size_t size);
45
46 /**
47 * p must have been returned by allocate()
48 */
49 void release(void* p);
50
51 /**
52 * Returns true if there are no unreleased allocations.
53 */
54 bool isEmpty() const { return fTail == fHead && !fHead->fLiveCount; }
55
joshualittb7133be2015-04-08 09:08:31 -070056 /**
joshualitt22c6f5c2016-01-05 08:07:18 -080057 * Returns the total allocated size of the GrMemoryPool minus any preallocated amount
joshualittb7133be2015-04-08 09:08:31 -070058 */
59 size_t size() const { return fSize; }
60
dskibae4cd0062016-11-29 06:50:35 -080061 /**
62 * Returns the preallocated size of the GrMemoryPool
63 */
64 size_t preallocSize() const { return fHead->fSize; }
65
66 /**
67 * Minimum value of minAllocSize constructor argument.
68 */
69 constexpr static size_t kSmallestMinAllocSize = 1 << 10;
70
bsalomon@google.com4da34e32012-06-19 15:40:27 +000071private:
72 struct BlockHeader;
73
commit-bot@chromium.org8743b8f2013-08-01 14:23:33 +000074 static BlockHeader* CreateBlock(size_t size);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000075
commit-bot@chromium.org8743b8f2013-08-01 14:23:33 +000076 static void DeleteBlock(BlockHeader* block);
bsalomon@google.com4da34e32012-06-19 15:40:27 +000077
78 void validate();
79
80 struct BlockHeader {
robertphillipsb7f4b8e2016-01-07 10:12:16 -080081#ifdef SK_DEBUG
82 uint32_t fBlockSentinal; ///< known value to check for bad back pointers to blocks
83#endif
tomhudson@google.comdcba4c22012-07-24 21:36:16 +000084 BlockHeader* fNext; ///< doubly-linked list of blocks.
bsalomon@google.com4da34e32012-06-19 15:40:27 +000085 BlockHeader* fPrev;
tomhudson@google.comdcba4c22012-07-24 21:36:16 +000086 int fLiveCount; ///< number of outstanding allocations in the
87 ///< block.
88 intptr_t fCurrPtr; ///< ptr to the start of blocks free space.
89 intptr_t fPrevPtr; ///< ptr to the last allocation made
90 size_t fFreeSize; ///< amount of free space left in the block.
joshualittb7133be2015-04-08 09:08:31 -070091 size_t fSize; ///< total allocated size of the block
bsalomon@google.com4da34e32012-06-19 15:40:27 +000092 };
93
robertphillips19c62502016-01-06 07:04:46 -080094 static const uint32_t kAssignedMarker = 0xCDCDCDCD;
95 static const uint32_t kFreedMarker = 0xEFEFEFEF;
96
97 struct AllocHeader {
98#ifdef SK_DEBUG
99 uint32_t fSentinal; ///< known value to check for memory stomping (e.g., (CD)*)
Brian Salomona5002c32017-03-28 16:51:02 -0400100 int32_t fID; ///< ID that can be used to track down leaks by clients.
robertphillips19c62502016-01-06 07:04:46 -0800101#endif
102 BlockHeader* fHeader; ///< pointer back to the block header in which an alloc resides
103 };
104
joshualittb7133be2015-04-08 09:08:31 -0700105 size_t fSize;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000106 size_t fMinAllocSize;
107 BlockHeader* fHead;
108 BlockHeader* fTail;
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000109#ifdef SK_DEBUG
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000110 int fAllocationCnt;
joshualittb7133be2015-04-08 09:08:31 -0700111 int fAllocBlockCnt;
Brian Salomona5002c32017-03-28 16:51:02 -0400112 SkTHashSet<int32_t> fAllocatedIDs;
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000113#endif
dskibae4cd0062016-11-29 06:50:35 -0800114
115protected:
116 enum {
117 // We assume this alignment is good enough for everybody.
118 kAlignment = 8,
119 kHeaderSize = GR_CT_ALIGN_UP(sizeof(BlockHeader), kAlignment),
120 kPerAllocPad = GR_CT_ALIGN_UP(sizeof(AllocHeader), kAlignment),
121 };
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000122};
123
dskibae4cd0062016-11-29 06:50:35 -0800124/**
125 * Variant of GrMemoryPool that can only allocate objects of a single type. It is
126 * not as flexible as GrMemoryPool, but it has more convenient allocate() method,
127 * and more importantly, it guarantees number of objects that are preallocated at
128 * construction or when adding a new memory block. I.e.
129 *
130 * GrMemoryPool pool(3 * sizeof(T), 1000 * sizeof(T));
131 * pool.allocate(sizeof(T));
132 * pool.allocate(sizeof(T));
133 * pool.allocate(sizeof(T));
134 *
135 * will preallocate 3 * sizeof(T) bytes and use some of those bytes for internal
136 * structures. Because of that, last allocate() call will end up allocating a new
137 * block of 1000 * sizeof(T) bytes. In contrast,
138 *
139 * GrObjectMemoryPool<T> pool(3, 1000);
140 * pool.allocate();
141 * pool.allocate();
142 * pool.allocate();
143 *
144 * guarantees to preallocate enough memory for 3 objects of sizeof(T), so last
145 * allocate() will use preallocated memory and won't cause allocation of a new block.
146 *
147 * Same thing is true for the second (minAlloc) ctor argument: this class guarantees
148 * that a newly added block will have enough space for 1000 objects of sizeof(T), while
149 * GrMemoryPool does not.
150 */
151template <class T>
152class GrObjectMemoryPool: public GrMemoryPool {
153public:
154 /**
155 * Preallocates memory for preallocCount objects, and sets new block size to be
156 * enough to hold minAllocCount objects.
157 */
158 GrObjectMemoryPool(size_t preallocCount, size_t minAllocCount)
159 : GrMemoryPool(CountToSize(preallocCount),
160 CountToSize(SkTMax(minAllocCount, kSmallestMinAllocCount))) {
161 }
162
163 /**
164 * Allocates memory for an object, but doesn't construct or otherwise initialize it.
165 * The memory must be freed with release().
166 */
167 T* allocate() { return static_cast<T*>(GrMemoryPool::allocate(sizeof(T))); }
168
169private:
170 constexpr static size_t kTotalObjectSize =
171 kPerAllocPad + GR_CT_ALIGN_UP(sizeof(T), kAlignment);
172
173 constexpr static size_t CountToSize(size_t count) {
174 return kHeaderSize + count * kTotalObjectSize;
175 }
176
177public:
178 /**
179 * Minimum value of minAllocCount constructor argument.
180 */
181 constexpr static size_t kSmallestMinAllocCount =
182 (GrMemoryPool::kSmallestMinAllocSize - kHeaderSize + kTotalObjectSize - 1) /
183 kTotalObjectSize;
184};
185
186template <class T>
187constexpr size_t GrObjectMemoryPool<T>::kSmallestMinAllocCount;
188
bsalomon@google.com4da34e32012-06-19 15:40:27 +0000189#endif