Skip to content

Commit ee17ad3

Browse files
committed
Split TLSF Allocator into size classes
1 parent 6259a82 commit ee17ad3

File tree

3 files changed

+1139
-160
lines changed

3 files changed

+1139
-160
lines changed

engine/utils/TlsfAllocator.cpp renamed to engine/utils/allocators/Tlsf.cpp

Lines changed: 111 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@
77
// https://opensource.org/licenses/Zlib
88
//
99

10-
#include "TlsfAllocator.h"
11-
10+
#include "Tlsf.h"
1211
#include <memory>
13-
14-
#include "Logging.h"
12+
#include "../Logging.h"
1513

1614
#define TO_BYTES(val) reinterpret_cast<uint8_t*>(val)
1715
#define TO_HEADER(val) reinterpret_cast<BlockHeader*>(val)
@@ -24,27 +22,30 @@
2422
#define METADATA_OVERHEAD HEADER_SIZE + FOOTER_SIZE
2523
#define PAD_SIZE(size) size + METADATA_OVERHEAD
2624

27-
#define FL_MIN_INDEX 4
2825
#define MAX_SL_BUCKETS 16
2926
#define FL(size) 63 - __builtin_clzll(size)
30-
#define SL(size, fl) (size >> fl) & ((1 << FL_MIN_INDEX) - 1);
27+
#define SL(size, fl) (size >> fl) & ((1 << MIN_SIZE_INDEX) - 1);
3128
#define FLAG_OFFSET 3
32-
#define MIN_ALLOCATION 16
33-
#define INVALID_INDEX UINT64_MAX
29+
#define INVALID_INDEX(T) std::numeric_limits<T>::max()
30+
#define MIN_ALLOCATION_SIZE 16
3431

3532
namespace Siege
3633
{
34+
template<typename T>
35+
uint8_t TlsfAllocator<T>::MIN_SIZE_INDEX = sizeof(T) < 4 ? 4 : sizeof(T);
3736

38-
TlsfAllocator::TlsfAllocator() {}
37+
template<typename T>
38+
TlsfAllocator<T>::TlsfAllocator() {}
3939

40-
TlsfAllocator::TlsfAllocator(const uint64_t size)
40+
template<typename T>
41+
TlsfAllocator<T>::TlsfAllocator(const uint64_t size)
4142
{
4243
uint64_t paddedSize = PAD_SIZE(size);
43-
if (size == 0 || size < MIN_ALLOCATION || size > (UINT64_MAX - METADATA_OVERHEAD) ||
44+
if (size == 0 || size < MIN_ALLOCATION_SIZE || size > (INVALID_INDEX(T) - METADATA_OVERHEAD) ||
4445
paddedSize < size)
4546
return;
4647

47-
uint64_t maxBuckets = (FL(size) - FL_MIN_INDEX) + 1;
48+
uint64_t maxBuckets = (FL(size) - MIN_SIZE_INDEX) + 1;
4849

4950
uint64_t slBucketSize = sizeof(uint16_t) * maxBuckets;
5051
uint64_t freeListSize = maxBuckets * MAX_SL_BUCKETS * sizeof(FreeBlockNode*);
@@ -71,18 +72,20 @@ TlsfAllocator::TlsfAllocator(const uint64_t size)
7172
AddNewBlock(paddedSize, TO_HEADER(data));
7273
}
7374

74-
void TlsfAllocator::CreateHeader(uint8_t* ptr, const uint64_t size, HeaderFlags flags)
75+
template<typename T>
76+
void TlsfAllocator<T>::CreateHeader(uint8_t* ptr, const uint64_t size, HeaderFlags flags)
7577
{
7678
if (!ptr) return;
7779
BlockHeader* header = TO_HEADER(ptr);
7880
header->sizeAndFlags = (size << FLAG_OFFSET) | flags;
7981
}
8082

81-
void* TlsfAllocator::Allocate(const uint64_t& size)
83+
template<typename T>
84+
void* TlsfAllocator<T>::Allocate(const uint64_t& size)
8285
{
8386
uint64_t requiredSize = sizeof(BlockHeader) + size + sizeof(BlockFooter);
8487
if (!data || capacity == 0 || size == 0 || requiredSize < size ||
85-
requiredSize > totalBytesRemaining || size < MIN_ALLOCATION)
88+
requiredSize > totalBytesRemaining || size < MIN_ALLOCATION_SIZE)
8689
return nullptr;
8790

8891
FreeBlockNode* block = FindFreeBlock(requiredSize);
@@ -100,7 +103,43 @@ void* TlsfAllocator::Allocate(const uint64_t& size)
100103
return ptr;
101104
}
102105

103-
TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock(TlsfAllocator::FreeBlockNode* node,
106+
template<typename T>
107+
void TlsfAllocator<T>::Deallocate(void** ptr)
108+
{
109+
uint8_t* raw = (uint8_t*) *ptr;
110+
if (!raw) return;
111+
if (raw < data || raw >= (data + capacity)) return;
112+
113+
BlockHeader* header = GetHeader(raw);
114+
115+
if (IsFree(header)) return;
116+
117+
uint64_t blockSize = GetHeaderSize(header);
118+
119+
uint64_t totalBlockSize = blockSize;
120+
header = TryCoalesce(header, totalBlockSize);
121+
BlockFooter* footer = GetFooter(header);
122+
123+
header->sizeAndFlags = (totalBlockSize << 3) | (header->sizeAndFlags & PREV_IS_FREE) | FREE;
124+
footer->totalBlockSize = totalBlockSize;
125+
126+
BlockHeader* nextHeader = GetNextHeader(header);
127+
128+
if (nextHeader && ((uint8_t*) nextHeader < (data + capacity)))
129+
{
130+
nextHeader->sizeAndFlags |= PREV_IS_FREE;
131+
}
132+
133+
AddNewBlock(totalBlockSize, header);
134+
135+
bytesRemaining += blockSize - sizeof(BlockHeader) - sizeof(BlockFooter);
136+
totalBytesRemaining += blockSize;
137+
138+
*ptr = nullptr;
139+
}
140+
141+
template<typename T>
142+
typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::TrySplitBlock(TlsfAllocator<T>::FreeBlockNode* node,
104143
uint64_t& allocatedSize)
105144
{
106145
if (!node) return nullptr;
@@ -125,7 +164,8 @@ TlsfAllocator::BlockHeader* TlsfAllocator::TrySplitBlock(TlsfAllocator::FreeBloc
125164
return header;
126165
}
127166

128-
void TlsfAllocator::AddNewBlock(const uint64_t size, BlockHeader* header)
167+
template<typename T>
168+
void TlsfAllocator<T>::AddNewBlock(const uint64_t size, BlockHeader* header)
129169
{
130170
uint64_t fl = 0, sl = 0, index;
131171
index = CalculateFreeBlockIndices(size, fl, sl);
@@ -141,7 +181,8 @@ void TlsfAllocator::AddNewBlock(const uint64_t size, BlockHeader* header)
141181
slBitmasks[fl] |= (1 << sl);
142182
}
143183

144-
TlsfAllocator::BlockHeader* TlsfAllocator::TryCoalesce(BlockHeader* header, OUT uint64_t& size)
184+
template<typename T>
185+
typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::TryCoalesce(BlockHeader* header, OUT uint64_t& size)
145186
{
146187
BlockHeader* start = header;
147188
BlockHeader* prev = GetPrevHeader(start);
@@ -163,7 +204,8 @@ TlsfAllocator::BlockHeader* TlsfAllocator::TryCoalesce(BlockHeader* header, OUT
163204
return start;
164205
}
165206

166-
bool TlsfAllocator::RemoveFreeBlock(TlsfAllocator::FreeBlockNode* node)
207+
template<typename T>
208+
bool TlsfAllocator<T>::RemoveFreeBlock(TlsfAllocator::FreeBlockNode* node)
167209
{
168210
BlockHeader* header = GetHeader(node);
169211

@@ -189,19 +231,21 @@ bool TlsfAllocator::RemoveFreeBlock(TlsfAllocator::FreeBlockNode* node)
189231
return true;
190232
}
191233

192-
TlsfAllocator::FreeBlockNode* TlsfAllocator::FindFreeBlock(const uint64_t& size)
234+
template<typename T>
235+
typename TlsfAllocator<T>::FreeBlockNode* TlsfAllocator<T>::FindFreeBlock(const uint64_t& size)
193236
{
194237
uint64_t fl, sl, index;
195238
// 1000 0000 0000 1000
196239
index = CalculateFreeBlockIndices(size, fl, sl);
197240

198241
if (!IsFree(fl, sl)) index = GetNextFreeSlotIndex(fl, sl);
199-
if (index == INVALID_INDEX) return nullptr;
242+
if (index == INVALID_INDEX(T)) return nullptr;
200243

201244
return freeList[index];
202245
}
203246

204-
const uint64_t TlsfAllocator::GetNextFreeSlotIndex(uint64_t& fl, uint64_t& sl)
247+
template<typename T>
248+
const uint64_t TlsfAllocator<T>::GetNextFreeSlotIndex(uint64_t& fl, uint64_t& sl)
205249
{
206250
sl = __builtin_ctz(slBitmasks[fl] & ~(((1 << (sl + 1)) - 1)));
207251

@@ -210,7 +254,7 @@ const uint64_t TlsfAllocator::GetNextFreeSlotIndex(uint64_t& fl, uint64_t& sl)
210254

211255
fl = flBitmask & ~(((1ULL << (fl + 1)) - 1));
212256

213-
if (!fl) return INVALID_INDEX;
257+
if (!fl) return INVALID_INDEX(T);
214258

215259
fl = __builtin_ctzll(fl);
216260
CC_ASSERT(slBitmasks[fl] > 0,
@@ -222,38 +266,43 @@ const uint64_t TlsfAllocator::GetNextFreeSlotIndex(uint64_t& fl, uint64_t& sl)
222266
return fl * MAX_SL_BUCKETS + sl;
223267
}
224268

225-
uint64_t TlsfAllocator::CalculateFreeBlockIndices(uint64_t size, OUT uint64_t& fl, OUT uint64_t& sl)
269+
template<typename T>
270+
uint64_t TlsfAllocator<T>::CalculateFreeBlockIndices(uint64_t size, OUT uint64_t& fl, OUT uint64_t& sl)
226271
{
227272
uint64_t rawFl = FL(size);
228-
fl = rawFl - FL_MIN_INDEX;
273+
fl = rawFl - MIN_SIZE_INDEX;
229274
sl = SL(size, fl);
230275
return fl * MAX_SL_BUCKETS + sl;
231276
}
232277

233-
void TlsfAllocator::CreateFooter(uint8_t* ptr, const uint64_t size)
278+
template<typename T>
279+
void TlsfAllocator<T>::CreateFooter(uint8_t* ptr, const uint64_t size)
234280
{
235281
if (!ptr) return;
236282
BlockFooter* footer = TO_FOOTER(ptr);
237283
footer->totalBlockSize = size;
238284
}
239285

240-
TlsfAllocator::BlockHeader* TlsfAllocator::GetHeader(TlsfAllocator::FreeBlockNode* node)
286+
template<typename T>
287+
typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::GetHeader(TlsfAllocator::FreeBlockNode* node)
241288
{
242289
if (!node) return nullptr;
243290
uint8_t* rawHeader = TO_BYTES(node) - HEADER_SIZE;
244291
if (!IsValid(rawHeader)) return nullptr;
245292
return TO_HEADER(rawHeader);
246293
}
247294

248-
TlsfAllocator::BlockHeader* TlsfAllocator::GetHeader(uint8_t* ptr)
295+
template<typename T>
296+
typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::GetHeader(uint8_t* ptr)
249297
{
250298
if (!ptr) return nullptr;
251299
uint8_t* rawHeader = ptr - HEADER_SIZE;
252300
if (!IsValid(rawHeader)) return nullptr;
253301
return TO_HEADER(rawHeader);
254302
}
255303

256-
TlsfAllocator::BlockHeader* TlsfAllocator::GetPrevHeader(TlsfAllocator::BlockHeader* header)
304+
template<typename T>
305+
typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::GetPrevHeader(TlsfAllocator::BlockHeader* header)
257306
{
258307
if (!header) return nullptr;
259308
uint8_t* rawPrevFooter = TO_BYTES(GetPrevFooter(header));
@@ -263,7 +312,8 @@ TlsfAllocator::BlockHeader* TlsfAllocator::GetPrevHeader(TlsfAllocator::BlockHea
263312
return TO_HEADER(prevHeader);
264313
}
265314

266-
TlsfAllocator::BlockHeader* TlsfAllocator::GetNextHeader(TlsfAllocator::BlockHeader* header)
315+
template<typename T>
316+
typename TlsfAllocator<T>::BlockHeader* TlsfAllocator<T>::GetNextHeader(TlsfAllocator::BlockHeader* header)
267317
{
268318
if (!header) return nullptr;
269319
uint8_t* rawHeader = TO_BYTES(header);
@@ -272,7 +322,8 @@ TlsfAllocator::BlockHeader* TlsfAllocator::GetNextHeader(TlsfAllocator::BlockHea
272322
return TO_HEADER(next);
273323
}
274324

275-
TlsfAllocator::FreeBlockNode* TlsfAllocator::CreateFreeBlock(uint8_t* ptr,
325+
template<typename T>
326+
typename TlsfAllocator<T>::FreeBlockNode* TlsfAllocator<T>::CreateFreeBlock(uint8_t* ptr,
276327
TlsfAllocator::FreeBlockNode* prev,
277328
TlsfAllocator::FreeBlockNode* next)
278329
{
@@ -284,20 +335,23 @@ TlsfAllocator::FreeBlockNode* TlsfAllocator::CreateFreeBlock(uint8_t* ptr,
284335
return node;
285336
}
286337

287-
TlsfAllocator::FreeBlockNode* TlsfAllocator::GetFreeBlock(BlockHeader* header)
338+
template<typename T>
339+
typename TlsfAllocator<T>::FreeBlockNode* TlsfAllocator<T>::GetFreeBlock(BlockHeader* header)
288340
{
289341
if (!header || !IsFree(header)) return nullptr;
290342
uint8_t* rawBlock = TO_BYTES(header) + HEADER_SIZE;
291343
if (!IsValid(rawBlock)) return nullptr;
292344
return TO_FREE_BLOCK(rawBlock);
293345
}
294346

295-
TlsfAllocator::FreeBlockNode* TlsfAllocator::GetFreeBlock(const uint64_t fl, const uint64_t sl)
347+
template<typename T>
348+
typename TlsfAllocator<T>::FreeBlockNode* TlsfAllocator<T>::GetFreeBlock(const uint64_t fl, const uint64_t sl)
296349
{
297350
return freeList[fl * MAX_SL_BUCKETS + sl];
298351
}
299352

300-
TlsfAllocator::BlockFooter* TlsfAllocator::GetFooter(TlsfAllocator::BlockHeader* header)
353+
template<typename T>
354+
typename TlsfAllocator<T>::BlockFooter* TlsfAllocator<T>::GetFooter(TlsfAllocator::BlockHeader* header)
301355
{
302356
if (!header) return nullptr;
303357
uint64_t size = GetHeaderSize(header);
@@ -306,35 +360,41 @@ TlsfAllocator::BlockFooter* TlsfAllocator::GetFooter(TlsfAllocator::BlockHeader*
306360
return TO_FOOTER(rawFooter);
307361
}
308362

309-
TlsfAllocator::BlockFooter* TlsfAllocator::GetPrevFooter(TlsfAllocator::BlockHeader* header)
363+
template<typename T>
364+
typename TlsfAllocator<T>::BlockFooter* TlsfAllocator<T>::GetPrevFooter(TlsfAllocator::BlockHeader* header)
310365
{
311366
if (!header) return nullptr;
312367
uint8_t* rawFooter = TO_BYTES(header) - FOOTER_SIZE;
313368
if (!IsValid(rawFooter)) return nullptr;
314369
return TO_FOOTER(rawFooter);
315370
}
316371

317-
uint8_t* TlsfAllocator::GetBlockData(TlsfAllocator::BlockHeader* header)
372+
template<typename T>
373+
uint8_t* TlsfAllocator<T>::GetBlockData(TlsfAllocator::BlockHeader* header)
318374
{
319375
return TO_BYTES(header) + HEADER_SIZE;
320376
}
321377

322-
const uint64_t TlsfAllocator::GetHeaderSize(BlockHeader* header)
378+
template<typename T>
379+
const uint64_t TlsfAllocator<T>::GetHeaderSize(BlockHeader* header)
323380
{
324381
return header->sizeAndFlags >> FLAG_OFFSET;
325382
}
326383

327-
bool TlsfAllocator::IsFree(BlockHeader* header)
384+
template<typename T>
385+
bool TlsfAllocator<T>::IsFree(BlockHeader* header)
328386
{
329387
return header->sizeAndFlags & FREE;
330388
}
331389

332-
bool TlsfAllocator::IsFree(uint64_t fl, uint64_t sl)
390+
template<typename T>
391+
bool TlsfAllocator<T>::IsFree(uint64_t fl, uint64_t sl)
333392
{
334393
return slBitmasks[fl] & (1 << sl);
335394
}
336395

337-
bool TlsfAllocator::PrevBlockIsFree(BlockHeader* header)
396+
template<typename T>
397+
bool TlsfAllocator<T>::PrevBlockIsFree(BlockHeader* header)
338398
{
339399
uint8_t* raw = TO_BYTES(header);
340400
if (raw == data) return false;
@@ -348,19 +408,26 @@ bool TlsfAllocator::PrevBlockIsFree(BlockHeader* header)
348408
return IsFree(TO_HEADER(rawPrevHeader));
349409
}
350410

351-
bool TlsfAllocator::IsValid(uint8_t* ptr)
411+
template<typename T>
412+
bool TlsfAllocator<T>::IsValid(uint8_t* ptr)
352413
{
353414
return ptr && ptr >= data && ptr < (data + (capacity + HEADER_SIZE + FOOTER_SIZE));
354415
}
355416

356-
const uint64_t TlsfAllocator::Capacity()
417+
template<typename T>
418+
const uint64_t TlsfAllocator<T>::Capacity()
357419
{
358420
return capacity;
359421
}
360422

361-
const uint64_t TlsfAllocator::BytesRemaining()
423+
template<typename T>
424+
const uint64_t TlsfAllocator<T>::BytesRemaining()
362425
{
363426
return bytesRemaining;
364427
}
365428

366-
} // namespace Siege
429+
template class TlsfAllocator<uint16_t>;
430+
template class TlsfAllocator<uint32_t>;
431+
template class TlsfAllocator<uint64_t>;
432+
}
433+

0 commit comments

Comments
 (0)