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" // file="L4.CacheLine"
// Project: StgSharp // Project: StgSharp
// AuthorGroup: Nitload // AuthorGroup: Nitload Space
// Copyright (c) Nitload. All rights reserved. // Copyright (c) Nitload Space. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -66,20 +66,23 @@ namespace StgSharp.HighPerformance.Memory
#region tlsf area #region tlsf area
// TLSF area use only 24 bytes
internal const ulong Mask48Bits = 0x0000FFFFFFFFFFFF; internal const ulong Mask48Bits = 0x0000FFFFFFFFFFFF;
[FieldOffset(0)] private readonly M512 FillingMask; [FieldOffset(0)] private readonly M512 FillingMask;
[FieldOffset(16)] private ulong PositionMask; [FieldOffset(8)] private ulong PositionMask;
[FieldOffset(24)] private ulong SizeMask; [FieldOffset(16)] private ulong SizeMask;
[FieldOffset(30)] internal AllocationState State; [FieldOffset(14)] internal AllocationState State;
[FieldOffset(31)] internal sbyte Level;
[FieldOffset(0)] public int NextLevel; // [FieldOffset(15)] internal sbyte Level;
[FieldOffset(4)] public int NextNear;
[FieldOffset(8)] public int PreviousLevel; [FieldOffset(0)] public short NextLevel;
[FieldOffset(12)] public int PreviousNear; [FieldOffset(2)] public short NextNear;
[FieldOffset(4)] public short PreviousLevel;
[FieldOffset(6)] public short PreviousNear;
public Ptr64 Position public Ptr64 Position
{ {
@@ -106,13 +109,12 @@ namespace StgSharp.HighPerformance.Memory
#region reference counting and state information #region reference counting and state information
[FieldOffset(24)] internal int RefCount; [FieldOffset(24)] internal int RefCount;
[FieldOffset(28)] internal readonly int Id; [FieldOffset(28)] internal readonly short Id;
#endregion #endregion
#region cache line information #region cache line information
[FieldOffset(32)] internal short Predictor;
[FieldOffset(34)] internal ushort Profile; [FieldOffset(34)] internal ushort Profile;
[FieldOffset(36)] internal nuint Origin; [FieldOffset(36)] internal nuint Origin;
@@ -126,10 +128,7 @@ namespace StgSharp.HighPerformance.Memory
private CacheLineMetadata* _head; private CacheLineMetadata* _head;
private nuint _handle; private nuint _handle;
private Handle( private Handle(nuint handle, CacheLineMetadata* cacheRefCount)
nuint handle,
CacheLineMetadata* cacheRefCount
)
{ {
_handle = handle; _handle = handle;
_head = cacheRefCount; _head = cacheRefCount;
@@ -2,8 +2,8 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// file="L4.Tlsf" // file="L4.Tlsf"
// Project: StgSharp // Project: StgSharp
// AuthorGroup: Nitload // AuthorGroup: Nitload Space
// Copyright (c) Nitload. All rights reserved. // Copyright (c) Nitload Space. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // 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; public static readonly nuint RequestedAllocation = (nuint)MaxCacheLineCount * CacheLineMetadata.SizeOf;
private readonly int[] _bucket; private readonly short[] _bucket;
private readonly CacheLineMetadata* _spareMemory; private readonly CacheLineMetadata* _spareMemory;
private readonly int _align; private readonly int _align;
private readonly int _maxLevel; private readonly int _maxLevel;
@@ -56,11 +56,7 @@ namespace StgSharp.HighPerformance.Memory
private readonly ulong _maxAllocSize; private readonly ulong _maxAllocSize;
private readonly ulong _totalSize; private readonly ulong _totalSize;
internal TLSF( internal TLSF(nuint byteSize, ulong maxBlockSize, void* externalPointer)
nuint byteSize,
ulong maxBlockSize,
void* externalPointer
)
{ {
_totalSize = byteSize; _totalSize = byteSize;
_basePtr = (Ptr64)(ulong)externalPointer; _basePtr = (Ptr64)(ulong)externalPointer;
@@ -83,9 +79,7 @@ namespace StgSharp.HighPerformance.Memory
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetLevel( private int GetLevel(ulong size)
ulong size
)
{ {
int origin = 57 - BitOperations.LeadingZeroCount(size); int origin = 57 - BitOperations.LeadingZeroCount(size);
return int.Min(origin, _maxLevel); return int.Min(origin, _maxLevel);
@@ -97,19 +91,17 @@ namespace StgSharp.HighPerformance.Memory
/// <param name="node"> /// <param name="node">
/// ///
/// </param> /// </param>
private void RecycleNode( private void RecycleNode(CacheLineMetadata* node)
CacheLineMetadata* node
)
{ {
int nodeIdx = (int)(_spareMemory - node); short nodeIdx = (short)(_spareMemory - node);
int level = GetLevel(node->SizeForAllocator); int level = GetLevel(node->SizeForAllocator);
int nextLevelIdx = node->NextLevel; short nextLevelIdx = node->NextLevel;
int prevLevelIdx = node->PreviousLevel; short prevLevelIdx = node->PreviousLevel;
RemoveFromBucket(level, node, nodeIdx); RemoveFromBucket(level, node, nodeIdx);
// remove from position chain // remove from position chain
int prevNearIdx = node->PreviousNear; short prevNearIdx = node->PreviousNear;
int nextNearIdx = node->NextNear; short nextNearIdx = node->NextNear;
CacheLineMetadata* prevNear = &_spareMemory[prevNearIdx]; CacheLineMetadata* prevNear = &_spareMemory[prevNearIdx];
prevNear->NextNear = nextNearIdx; prevNear->NextNear = nextNearIdx;
if (nextNearIdx != 0) if (nextNearIdx != 0)
@@ -128,7 +120,7 @@ namespace StgSharp.HighPerformance.Memory
node->State = AllocationState.SpareOrCollect; node->State = AllocationState.SpareOrCollect;
node->PreviousLevel = 0; node->PreviousLevel = 0;
int nextIdx = _spareMemory->NextLevel; short nextIdx = _spareMemory->NextLevel;
if (nextIdx != 0) if (nextIdx != 0)
{ {
CacheLineMetadata* next = &_spareMemory[nextIdx]; CacheLineMetadata* next = &_spareMemory[nextIdx];
@@ -139,23 +131,16 @@ namespace StgSharp.HighPerformance.Memory
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void RemoveFromBucket( private void RemoveFromBucket(CacheLineMetadata* node, int nodeIdx)
CacheLineMetadata* node,
int nodeIdx
)
{ {
RemoveFromBucket(GetLevel(node->SizeForAllocator), node, nodeIdx); RemoveFromBucket(GetLevel(node->SizeForAllocator), node, nodeIdx);
} }
private void RemoveFromBucket( private void RemoveFromBucket(int level, CacheLineMetadata* node, int nodeIdx)
int level,
CacheLineMetadata* node,
int nodeIdx
)
{ {
int currentLevel = level; int currentLevel = level;
int currentNextLevelIdx = node->NextLevel; short currentNextLevelIdx = node->NextLevel;
int currentPrevLevelIdx = node->PreviousLevel; short currentPrevLevelIdx = node->PreviousLevel;
if (_bucket[currentLevel] == nodeIdx) if (_bucket[currentLevel] == nodeIdx)
{ {
@@ -175,11 +160,7 @@ namespace StgSharp.HighPerformance.Memory
} }
// Assuming node to remove is head f bucket // Assuming node to remove is head f bucket
private void RemoveFromBucketHead( private void RemoveFromBucketHead(int level, CacheLineMetadata* node, int nodeIdx)
int level,
CacheLineMetadata* node,
int nodeIdx
)
{ {
int currentLevel = level; int currentLevel = level;
int currentNextLevelIdx = node->NextLevel; int currentNextLevelIdx = node->NextLevel;
@@ -206,12 +187,9 @@ namespace StgSharp.HighPerformance.Memory
node->NextLevel = 0; node->NextLevel = 0;
} }
private bool TryAllocNewChunk( private bool TryAllocNewChunk(ulong size, out CacheLineMetadata* meta)
ulong size,
out CacheLineMetadata* meta
)
{ {
int idx = _spareMemory->NextLevel; short idx = _spareMemory->NextLevel;
ulong spareSize = _spareMemory->SizeForAllocator; ulong spareSize = _spareMemory->SizeForAllocator;
if (idx != 0) if (idx != 0)
{ {
@@ -221,7 +199,7 @@ namespace StgSharp.HighPerformance.Memory
return false; return false;
} }
meta = &_spareMemory[idx]; meta = &_spareMemory[idx];
int nextSpareIdx = meta->NextLevel; short nextSpareIdx = meta->NextLevel;
if (nextSpareIdx != 0) if (nextSpareIdx != 0)
{ {
CacheLineMetadata* nextSpare = &_spareMemory[nextSpareIdx]; CacheLineMetadata* nextSpare = &_spareMemory[nextSpareIdx];
@@ -242,7 +220,7 @@ namespace StgSharp.HighPerformance.Memory
_spareMemory->Position += size; _spareMemory->Position += size;
// insert the new chunk to position chain // insert the new chunk to position chain
int nearIdx = _spareMemory->PreviousNear; short nearIdx = _spareMemory->PreviousNear;
CacheLineMetadata* near = &_spareMemory[nearIdx]; CacheLineMetadata* near = &_spareMemory[nearIdx];
near->NextNear = idx; near->NextNear = idx;
meta->PreviousNear = nearIdx; meta->PreviousNear = nearIdx;
@@ -251,9 +229,7 @@ namespace StgSharp.HighPerformance.Memory
return true; return true;
} }
private bool TryGetNewMetadata( private bool TryGetNewMetadata(out CacheLineMetadata* meta)
out CacheLineMetadata* meta
)
{ {
ulong spareSize = _spareMemory->SizeForAllocator; ulong spareSize = _spareMemory->SizeForAllocator;
if (_metadataEnd >= MaxCacheLineCount) if (_metadataEnd >= MaxCacheLineCount)
@@ -266,10 +242,7 @@ namespace StgSharp.HighPerformance.Memory
return true; return true;
} }
private bool TryTakeBucketEntry( private bool TryTakeBucketEntry(ulong minimumSize, out CacheLineMetadata* entry)
ulong minimumSize,
out CacheLineMetadata* entry
)
{ {
int level = GetLevel(minimumSize); int level = GetLevel(minimumSize);
@@ -306,9 +279,7 @@ namespace StgSharp.HighPerformance.Memory
#region alloc and free #region alloc and free
public int Alloc( public int Alloc(nuint size)
nuint size
)
{ {
ulong allocSize = ulong.Max(64, (~63UL) & ((ulong)size + 63)); ulong allocSize = ulong.Max(64, (~63UL) & ((ulong)size + 63));
if (allocSize > _maxAllocSize) { if (allocSize > _maxAllocSize) {
@@ -318,7 +289,7 @@ namespace StgSharp.HighPerformance.Memory
!TryAllocNewChunk(allocSize, out entry)) { !TryAllocNewChunk(allocSize, out entry)) {
throw new OverflowException("No available "); throw new OverflowException("No available ");
} }
int entryIdx = (int)(_spareMemory - entry); short entryIdx = (short)(_spareMemory - entry);
ulong entrySize = entry->SizeForAllocator; ulong entrySize = entry->SizeForAllocator;
if (entrySize < allocSize) { if (entrySize < allocSize) {
throw new OverflowException("Bucket returned an undersized block."); throw new OverflowException("Bucket returned an undersized block.");
@@ -326,15 +297,14 @@ namespace StgSharp.HighPerformance.Memory
ulong remain = entrySize - allocSize; ulong remain = entrySize - allocSize;
// slice tail // slice tail
if (remain > ulong.Min(4096UL, entrySize >> 7) && if (remain > ulong.Min(4096UL, entrySize >> 7) && TryGetNewMetadata(out CacheLineMetadata* newEntry))
TryGetNewMetadata(out CacheLineMetadata* newEntry))
{ {
int newEntryIdx = (int)(_spareMemory - newEntry); short newEntryIdx = (short)(_spareMemory - newEntry);
newEntry->Position = entry->Position + allocSize; newEntry->Position = entry->Position + allocSize;
newEntry->SizeForAllocator = remain; newEntry->SizeForAllocator = remain;
newEntry->State = AllocationState.Free; newEntry->State = AllocationState.Free;
int newLevel = GetLevel(remain); int newLevel = GetLevel(remain);
int bucketHeadIdx = _bucket[newLevel]; short bucketHeadIdx = _bucket[newLevel];
if (bucketHeadIdx != 0) if (bucketHeadIdx != 0)
{ {
// if there is already an entry in the bucket, link it to the new entry // 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; _bucket[newLevel] = newEntryIdx;
// push to position chain // push to position chain
int afterIdx = entry->NextNear; short afterIdx = entry->NextNear;
CacheLineMetadata* after = &_spareMemory[afterIdx]; CacheLineMetadata* after = &_spareMemory[afterIdx];
newEntry->NextNear = afterIdx; newEntry->NextNear = afterIdx;
after->PreviousNear = newEntryIdx; after->PreviousNear = newEntryIdx;
@@ -363,7 +333,7 @@ namespace StgSharp.HighPerformance.Memory
public void Collect() public void Collect()
{ {
int currentIdx = _spareMemory->NextNear; short currentIdx = _spareMemory->NextNear;
do do
{ {
if (currentIdx == 0) if (currentIdx == 0)
@@ -392,7 +362,7 @@ namespace StgSharp.HighPerformance.Memory
current->SizeForAllocator += size; current->SizeForAllocator += size;
RemoveFromBucket(current, currentIdx); RemoveFromBucket(current, currentIdx);
int newLevel = GetLevel(current->SizeForAllocator); int newLevel = GetLevel(current->SizeForAllocator);
int bucketHeadIdx = _bucket[newLevel]; short bucketHeadIdx = _bucket[newLevel];
if (bucketHeadIdx != 0) if (bucketHeadIdx != 0)
{ {
CacheLineMetadata* bucketHead = &_spareMemory[bucketHeadIdx]; CacheLineMetadata* bucketHead = &_spareMemory[bucketHeadIdx];
@@ -407,13 +377,10 @@ namespace StgSharp.HighPerformance.Memory
} while (true); } while (true);
} }
public void Free( public void Free(int handle, int collectScanWindow = 4)
int handle,
int collectScanWindow = 4
)
{ {
CacheLineMetadata* head = &_spareMemory[handle]; CacheLineMetadata* head = &_spareMemory[handle];
int headIdx = (int)(_spareMemory - head); short headIdx = (short)(_spareMemory - head);
Ptr64 size = head->SizeForAllocator; Ptr64 size = head->SizeForAllocator;
for (int i = 0; i < collectScanWindow; i++) for (int i = 0; i < collectScanWindow; i++)
{ {
@@ -454,7 +421,7 @@ namespace StgSharp.HighPerformance.Memory
head->State = AllocationState.Free; head->State = AllocationState.Free;
head->PreviousLevel = 0; head->PreviousLevel = 0;
int level = GetLevel(head->SizeForAllocator); int level = GetLevel(head->SizeForAllocator);
int bucketHeadIdx = _bucket[level]; short bucketHeadIdx = _bucket[level];
head->NextLevel = 0; head->NextLevel = 0;
if (bucketHeadIdx != 0) if (bucketHeadIdx != 0)
{ {
@@ -466,10 +433,7 @@ namespace StgSharp.HighPerformance.Memory
return; return;
} }
public bool TryAlloc( public bool TryAlloc(nuint size, out int h)
nuint size,
out int h
)
{ {
ulong allocSize = ulong.Max(64, (~63UL) & ((ulong)size + 63)); ulong allocSize = ulong.Max(64, (~63UL) & ((ulong)size + 63));
if (allocSize > _maxAllocSize) if (allocSize > _maxAllocSize)
@@ -483,7 +447,7 @@ namespace StgSharp.HighPerformance.Memory
h = -1; h = -1;
return false; return false;
} }
int entryIdx = (int)(_spareMemory - entry); short entryIdx = (short)(_spareMemory - entry);
ulong entrySize = entry->SizeForAllocator; ulong entrySize = entry->SizeForAllocator;
if (entrySize < allocSize) if (entrySize < allocSize)
{ {
@@ -495,12 +459,12 @@ namespace StgSharp.HighPerformance.Memory
// slice tail // slice tail
if (remain > (entrySize >> 7) && TryGetNewMetadata(out CacheLineMetadata* newEntry)) if (remain > (entrySize >> 7) && TryGetNewMetadata(out CacheLineMetadata* newEntry))
{ {
int newEntryIdx = (int)(_spareMemory - newEntry); short newEntryIdx = (short)(_spareMemory - newEntry);
newEntry->Position = entry->Position + allocSize; newEntry->Position = entry->Position + allocSize;
newEntry->SizeForAllocator = remain; newEntry->SizeForAllocator = remain;
newEntry->State = AllocationState.Free; newEntry->State = AllocationState.Free;
int newLevel = GetLevel(remain); int newLevel = GetLevel(remain);
int bucketHeadIdx = _bucket[newLevel]; short bucketHeadIdx = _bucket[newLevel];
if (bucketHeadIdx != 0) if (bucketHeadIdx != 0)
{ {
// if there is already an entry in the bucket, link it to the new entry // 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; _bucket[newLevel] = newEntryIdx;
// push to position chain // push to position chain
int afterIdx = entry->NextNear; short afterIdx = entry->NextNear;
CacheLineMetadata* after = &_spareMemory[afterIdx]; CacheLineMetadata* after = &_spareMemory[afterIdx];
newEntry->NextNear = afterIdx; newEntry->NextNear = afterIdx;
after->PreviousNear = newEntryIdx; after->PreviousNear = newEntryIdx;
@@ -2,8 +2,8 @@
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// file="MatrixParallelThread" // file="MatrixParallelThread"
// Project: StgSharp // Project: StgSharp
// AuthorGroup: Nitload // AuthorGroup: Nitload Space
// Copyright (c) Nitload. All rights reserved. // Copyright (c) Nitload Space. All rights reserved.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@@ -59,9 +59,7 @@ namespace StgSharp.Mathematics.Numeric
private volatile MatrixThreadState _target; private volatile MatrixThreadState _target;
private Thread _managedThread; private Thread _managedThread;
internal MatrixParallelThread( internal MatrixParallelThread(LogicalCore binded)
LogicalCore binded
)
{ {
_resetEvent = new ManualResetEventSlim(false); _resetEvent = new ManualResetEventSlim(false);
_managedThread = new Thread(MatrixParallelWorkLoad); _managedThread = new Thread(MatrixParallelWorkLoad);
@@ -101,9 +99,7 @@ namespace StgSharp.Mathematics.Numeric
_managedThread.Join(); _managedThread.Join();
} }
protected virtual void Dispose( protected virtual void Dispose(bool disposing)
bool disposing
)
{ {
if (!_disposed) if (!_disposed)
{ {
@@ -183,14 +179,9 @@ namespace StgSharp.Mathematics.Numeric
[LibraryImport(Native.LibName, EntryPoint = "load_intrinsic_function")] [LibraryImport(Native.LibName, EntryPoint = "load_intrinsic_function")]
[UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])] [UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
[DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)] [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory)]
private static unsafe partial void LoadIntrinsicFunction( private static unsafe partial void LoadIntrinsicFunction(IntrinsicContext* context, ulong id);
IntrinsicContext* context,
ulong id
);
public bool Equals( public bool Equals(MatrixParallelThread? other)
MatrixParallelThread? other
)
{ {
return (other is not null) && ReferenceEquals(this, other); return (other is not null) && ReferenceEquals(this, other);
} }