TLSF in l4 use a shorter head, but may be useless

Signed-off-by: Nitload <YoumuLiu_NSI@whv0t.onmicrosoft.com>
This commit is contained in:
Nitload
2026-06-01 00:36:46 +08:00
parent ddb59c38ce
commit 9a09d32960
3 changed files with 62 additions and 108 deletions
@@ -2,8 +2,8 @@
// -----------------------------------------------------------------------
// file="L4.CacheLine"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
// AuthorGroup: Nitload Space
// Copyright (c) Nitload Space. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -66,20 +66,23 @@ namespace StgSharp.HighPerformance.Memory
#region tlsf area
// TLSF area use only 24 bytes
internal const ulong Mask48Bits = 0x0000FFFFFFFFFFFF;
[FieldOffset(0)] private readonly M512 FillingMask;
[FieldOffset(16)] private ulong PositionMask;
[FieldOffset(24)] private ulong SizeMask;
[FieldOffset(8)] private ulong PositionMask;
[FieldOffset(16)] private ulong SizeMask;
[FieldOffset(30)] internal AllocationState State;
[FieldOffset(31)] internal sbyte Level;
[FieldOffset(14)] internal AllocationState State;
[FieldOffset(0)] public int NextLevel;
[FieldOffset(4)] public int NextNear;
[FieldOffset(8)] public int PreviousLevel;
[FieldOffset(12)] public int PreviousNear;
// [FieldOffset(15)] internal sbyte Level;
[FieldOffset(0)] public short NextLevel;
[FieldOffset(2)] public short NextNear;
[FieldOffset(4)] public short PreviousLevel;
[FieldOffset(6)] public short PreviousNear;
public Ptr64 Position
{
@@ -106,13 +109,12 @@ namespace StgSharp.HighPerformance.Memory
#region reference counting and state information
[FieldOffset(24)] internal int RefCount;
[FieldOffset(28)] internal readonly int Id;
[FieldOffset(28)] internal readonly short Id;
#endregion
#region cache line information
[FieldOffset(32)] internal short Predictor;
[FieldOffset(34)] internal ushort Profile;
[FieldOffset(36)] internal nuint Origin;
@@ -126,10 +128,7 @@ namespace StgSharp.HighPerformance.Memory
private CacheLineMetadata* _head;
private nuint _handle;
private Handle(
nuint handle,
CacheLineMetadata* cacheRefCount
)
private Handle(nuint handle, CacheLineMetadata* cacheRefCount)
{
_handle = handle;
_head = cacheRefCount;
@@ -2,8 +2,8 @@
// -----------------------------------------------------------------------
// file="L4.Tlsf"
// Project: StgSharp
// AuthorGroup: Nitload
// Copyright (c) Nitload. All rights reserved.
// AuthorGroup: Nitload Space
// Copyright (c) Nitload Space. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -46,7 +46,7 @@ namespace StgSharp.HighPerformance.Memory
public static readonly nuint RequestedAllocation = (nuint)MaxCacheLineCount * CacheLineMetadata.SizeOf;
private readonly int[] _bucket;
private readonly short[] _bucket;
private readonly CacheLineMetadata* _spareMemory;
private readonly int _align;
private readonly int _maxLevel;
@@ -56,11 +56,7 @@ namespace StgSharp.HighPerformance.Memory
private readonly ulong _maxAllocSize;
private readonly ulong _totalSize;
internal TLSF(
nuint byteSize,
ulong maxBlockSize,
void* externalPointer
)
internal TLSF(nuint byteSize, ulong maxBlockSize, void* externalPointer)
{
_totalSize = byteSize;
_basePtr = (Ptr64)(ulong)externalPointer;
@@ -83,9 +79,7 @@ namespace StgSharp.HighPerformance.Memory
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetLevel(
ulong size
)
private int GetLevel(ulong size)
{
int origin = 57 - BitOperations.LeadingZeroCount(size);
return int.Min(origin, _maxLevel);
@@ -97,19 +91,17 @@ namespace StgSharp.HighPerformance.Memory
/// <param name="node">
///
/// </param>
private void RecycleNode(
CacheLineMetadata* node
)
private void RecycleNode(CacheLineMetadata* node)
{
int nodeIdx = (int)(_spareMemory - node);
short nodeIdx = (short)(_spareMemory - node);
int level = GetLevel(node->SizeForAllocator);
int nextLevelIdx = node->NextLevel;
int prevLevelIdx = node->PreviousLevel;
short nextLevelIdx = node->NextLevel;
short prevLevelIdx = node->PreviousLevel;
RemoveFromBucket(level, node, nodeIdx);
// remove from position chain
int prevNearIdx = node->PreviousNear;
int nextNearIdx = node->NextNear;
short prevNearIdx = node->PreviousNear;
short nextNearIdx = node->NextNear;
CacheLineMetadata* prevNear = &_spareMemory[prevNearIdx];
prevNear->NextNear = nextNearIdx;
if (nextNearIdx != 0)
@@ -128,7 +120,7 @@ namespace StgSharp.HighPerformance.Memory
node->State = AllocationState.SpareOrCollect;
node->PreviousLevel = 0;
int nextIdx = _spareMemory->NextLevel;
short nextIdx = _spareMemory->NextLevel;
if (nextIdx != 0)
{
CacheLineMetadata* next = &_spareMemory[nextIdx];
@@ -139,23 +131,16 @@ namespace StgSharp.HighPerformance.Memory
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void RemoveFromBucket(
CacheLineMetadata* node,
int nodeIdx
)
private void RemoveFromBucket(CacheLineMetadata* node, int nodeIdx)
{
RemoveFromBucket(GetLevel(node->SizeForAllocator), node, nodeIdx);
}
private void RemoveFromBucket(
int level,
CacheLineMetadata* node,
int nodeIdx
)
private void RemoveFromBucket(int level, CacheLineMetadata* node, int nodeIdx)
{
int currentLevel = level;
int currentNextLevelIdx = node->NextLevel;
int currentPrevLevelIdx = node->PreviousLevel;
short currentNextLevelIdx = node->NextLevel;
short currentPrevLevelIdx = node->PreviousLevel;
if (_bucket[currentLevel] == nodeIdx)
{
@@ -175,11 +160,7 @@ namespace StgSharp.HighPerformance.Memory
}
// Assuming node to remove is head f bucket
private void RemoveFromBucketHead(
int level,
CacheLineMetadata* node,
int nodeIdx
)
private void RemoveFromBucketHead(int level, CacheLineMetadata* node, int nodeIdx)
{
int currentLevel = level;
int currentNextLevelIdx = node->NextLevel;
@@ -206,12 +187,9 @@ namespace StgSharp.HighPerformance.Memory
node->NextLevel = 0;
}
private bool TryAllocNewChunk(
ulong size,
out CacheLineMetadata* meta
)
private bool TryAllocNewChunk(ulong size, out CacheLineMetadata* meta)
{
int idx = _spareMemory->NextLevel;
short idx = _spareMemory->NextLevel;
ulong spareSize = _spareMemory->SizeForAllocator;
if (idx != 0)
{
@@ -221,7 +199,7 @@ namespace StgSharp.HighPerformance.Memory
return false;
}
meta = &_spareMemory[idx];
int nextSpareIdx = meta->NextLevel;
short nextSpareIdx = meta->NextLevel;
if (nextSpareIdx != 0)
{
CacheLineMetadata* nextSpare = &_spareMemory[nextSpareIdx];
@@ -242,7 +220,7 @@ namespace StgSharp.HighPerformance.Memory
_spareMemory->Position += size;
// insert the new chunk to position chain
int nearIdx = _spareMemory->PreviousNear;
short nearIdx = _spareMemory->PreviousNear;
CacheLineMetadata* near = &_spareMemory[nearIdx];
near->NextNear = idx;
meta->PreviousNear = nearIdx;
@@ -251,9 +229,7 @@ namespace StgSharp.HighPerformance.Memory
return true;
}
private bool TryGetNewMetadata(
out CacheLineMetadata* meta
)
private bool TryGetNewMetadata(out CacheLineMetadata* meta)
{
ulong spareSize = _spareMemory->SizeForAllocator;
if (_metadataEnd >= MaxCacheLineCount)
@@ -266,10 +242,7 @@ namespace StgSharp.HighPerformance.Memory
return true;
}
private bool TryTakeBucketEntry(
ulong minimumSize,
out CacheLineMetadata* entry
)
private bool TryTakeBucketEntry(ulong minimumSize, out CacheLineMetadata* entry)
{
int level = GetLevel(minimumSize);
@@ -306,9 +279,7 @@ namespace StgSharp.HighPerformance.Memory
#region alloc and free
public int Alloc(
nuint size
)
public int Alloc(nuint size)
{
ulong allocSize = ulong.Max(64, (~63UL) & ((ulong)size + 63));
if (allocSize > _maxAllocSize) {
@@ -318,7 +289,7 @@ namespace StgSharp.HighPerformance.Memory
!TryAllocNewChunk(allocSize, out entry)) {
throw new OverflowException("No available ");
}
int entryIdx = (int)(_spareMemory - entry);
short entryIdx = (short)(_spareMemory - entry);
ulong entrySize = entry->SizeForAllocator;
if (entrySize < allocSize) {
throw new OverflowException("Bucket returned an undersized block.");
@@ -326,15 +297,14 @@ namespace StgSharp.HighPerformance.Memory
ulong remain = entrySize - allocSize;
// slice tail
if (remain > ulong.Min(4096UL, entrySize >> 7) &&
TryGetNewMetadata(out CacheLineMetadata* newEntry))
if (remain > ulong.Min(4096UL, entrySize >> 7) && TryGetNewMetadata(out CacheLineMetadata* newEntry))
{
int newEntryIdx = (int)(_spareMemory - newEntry);
short newEntryIdx = (short)(_spareMemory - newEntry);
newEntry->Position = entry->Position + allocSize;
newEntry->SizeForAllocator = remain;
newEntry->State = AllocationState.Free;
int newLevel = GetLevel(remain);
int bucketHeadIdx = _bucket[newLevel];
short bucketHeadIdx = _bucket[newLevel];
if (bucketHeadIdx != 0)
{
// if there is already an entry in the bucket, link it to the new entry
@@ -347,7 +317,7 @@ namespace StgSharp.HighPerformance.Memory
_bucket[newLevel] = newEntryIdx;
// push to position chain
int afterIdx = entry->NextNear;
short afterIdx = entry->NextNear;
CacheLineMetadata* after = &_spareMemory[afterIdx];
newEntry->NextNear = afterIdx;
after->PreviousNear = newEntryIdx;
@@ -363,7 +333,7 @@ namespace StgSharp.HighPerformance.Memory
public void Collect()
{
int currentIdx = _spareMemory->NextNear;
short currentIdx = _spareMemory->NextNear;
do
{
if (currentIdx == 0)
@@ -392,7 +362,7 @@ namespace StgSharp.HighPerformance.Memory
current->SizeForAllocator += size;
RemoveFromBucket(current, currentIdx);
int newLevel = GetLevel(current->SizeForAllocator);
int bucketHeadIdx = _bucket[newLevel];
short bucketHeadIdx = _bucket[newLevel];
if (bucketHeadIdx != 0)
{
CacheLineMetadata* bucketHead = &_spareMemory[bucketHeadIdx];
@@ -407,13 +377,10 @@ namespace StgSharp.HighPerformance.Memory
} while (true);
}
public void Free(
int handle,
int collectScanWindow = 4
)
public void Free(int handle, int collectScanWindow = 4)
{
CacheLineMetadata* head = &_spareMemory[handle];
int headIdx = (int)(_spareMemory - head);
short headIdx = (short)(_spareMemory - head);
Ptr64 size = head->SizeForAllocator;
for (int i = 0; i < collectScanWindow; i++)
{
@@ -454,7 +421,7 @@ namespace StgSharp.HighPerformance.Memory
head->State = AllocationState.Free;
head->PreviousLevel = 0;
int level = GetLevel(head->SizeForAllocator);
int bucketHeadIdx = _bucket[level];
short bucketHeadIdx = _bucket[level];
head->NextLevel = 0;
if (bucketHeadIdx != 0)
{
@@ -466,10 +433,7 @@ namespace StgSharp.HighPerformance.Memory
return;
}
public bool TryAlloc(
nuint size,
out int h
)
public bool TryAlloc(nuint size, out int h)
{
ulong allocSize = ulong.Max(64, (~63UL) & ((ulong)size + 63));
if (allocSize > _maxAllocSize)
@@ -483,7 +447,7 @@ namespace StgSharp.HighPerformance.Memory
h = -1;
return false;
}
int entryIdx = (int)(_spareMemory - entry);
short entryIdx = (short)(_spareMemory - entry);
ulong entrySize = entry->SizeForAllocator;
if (entrySize < allocSize)
{
@@ -495,12 +459,12 @@ namespace StgSharp.HighPerformance.Memory
// slice tail
if (remain > (entrySize >> 7) && TryGetNewMetadata(out CacheLineMetadata* newEntry))
{
int newEntryIdx = (int)(_spareMemory - newEntry);
short newEntryIdx = (short)(_spareMemory - newEntry);
newEntry->Position = entry->Position + allocSize;
newEntry->SizeForAllocator = remain;
newEntry->State = AllocationState.Free;
int newLevel = GetLevel(remain);
int bucketHeadIdx = _bucket[newLevel];
short bucketHeadIdx = _bucket[newLevel];
if (bucketHeadIdx != 0)
{
// if there is already an entry in the bucket, link it to the new entry
@@ -515,7 +479,7 @@ namespace StgSharp.HighPerformance.Memory
_bucket[newLevel] = newEntryIdx;
// push to position chain
int afterIdx = entry->NextNear;
short afterIdx = entry->NextNear;
CacheLineMetadata* after = &_spareMemory[afterIdx];
newEntry->NextNear = afterIdx;
after->PreviousNear = newEntryIdx;