hlsf gong on rewrite again

This commit is contained in:
Youmu Liu
2025-11-27 20:13:09 +08:00
parent 83537c7be7
commit a3570bf20a
7 changed files with 267 additions and 242 deletions
@@ -60,134 +60,112 @@ namespace StgSharp.HighPerformance.Memory
}
}
if (handle != null) {
SliceMemory(handle, (segmentIndex + 1) * levelSizeArray[level]);
if (handle != null)
{
int requestedOffset = (segmentIndex + 1) * levelSizeArray[level];
if ((ulong)requestedOffset > handle->Size)
{
// spare返回的块不足以切出目标大小,避免进入切片导致下溢/越界
throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
}
Entry* extra = (Entry*)_entries.Allocate();
extra->Position = handle->Position + (nuint)requestedOffset;
extra->Size = handle->Size - (uint)requestedOffset;
extra->State = EntryState.Empty;
extra->NextNear = handle->NextNear;
extra->PreviousNear = handle;
extra->NextNear->PreviousNear = extra;
extra->PreviousNear->NextNear = extra;
SliceMemory(extra);
}
handle->State = EntryState.Allocated;
handle->Level = level;
return new hlsfHandle(handle, size);
}
private void SliceMemory(Entry* e, int offset)
private void SliceMemory(Entry* e)
{
Entry* current = e;
Entry* next = e->NextNear;
ulong originOffset = e->Position - (ulong)m_Buffer;
ulong finalOffset = originOffset + (ulong)offset;
ulong finalOffset = originOffset;
ulong end = e->Position + e->Size;
ulong endOffset = end - (ulong)m_Buffer;
ulong remainSize = (ulong)e->Size - (ulong)offset;
ulong remainSize = e->Size;
if (finalOffset >= endOffset || remainSize == 0) {
return;
}
// get level of left edge
int minLevel = int.Max((BitOperations.TrailingZeroCount(finalOffset) - 6) / 2, 0);
int i = minLevel >= levelSizeArray.Length ? levelSizeArray.Length - 1 : minLevel;
try
for (; i < levelSizeArray.Length; i++)
{
for (; i < levelSizeArray.Length; i++)
int levelSize = levelSizeArray[i];
ulong levelLong = (ulong)levelSize;
ulong levelUpper = levelLong * 4;
// smallest board that is larger than finalOffset
ulong board = (finalOffset + levelUpper - 1) / levelUpper * levelUpper;
long span = (long)ulong.Min(board, endOffset) - (long)finalOffset;
int blockCount = (span <= 0) ? 0 : (int)(span / (long)levelLong);
if (blockCount == 0)
{
int levelSize = levelSizeArray[i];
ulong levelLong = (ulong)levelSize;
ulong levelUpper = levelLong * 4;
// smallest board that is larger than finalOffset
ulong board = (finalOffset + levelUpper - 1) / levelUpper * levelUpper;
int blockCount = (int)((long)ulong.Min(board, endOffset) - (long)finalOffset) / (int)levelLong;
if (blockCount == 0)
{
continue;
}
int s = blockCount * levelSize;
// create and init new entry
Entry* newEntry = (Entry*)_entries.Allocate();
newEntry->State = EntryState.Empty;
newEntry->Position = (nuint)m_Buffer + (nuint)finalOffset;
newEntry->Size = (uint)s;
BucketNode* bucket = (BucketNode*)newEntry->Position;
bucket->EntryRef = newEntry;
// link new entry
newEntry->PreviousNear = current;
newEntry->NextNear = next;
current->NextNear = newEntry;
next->PreviousNear = newEntry;
// set new entry
// Entry* old = current;
current = newEntry;
newEntry->Level = i;
PushLevel(i, Math.Min(blockCount - 1, 2), bucket);
// Console.WriteLine($"{(ulong)current->PreviousNear}<->{(ulong)current->NextNear},\t{current->Size}");
finalOffset += (ulong)s;
remainSize -= (ulong)s;
if (remainSize <= (ulong)levelSize)
{
break;
}
if (remainSize <= 0) {
return;
}
continue;
}
int s = blockCount * levelSize;
if (i >= 10)
// create and init new entry
Entry* newEntry = (Entry*)_entries.Allocate();
newEntry->State = EntryState.Empty;
newEntry->Position = (nuint)m_Buffer + (nuint)finalOffset;
newEntry->Size = (uint)s;
BucketNode* bucket = (BucketNode*)newEntry->Position;
bucket->EntryRef = newEntry;
newEntry->Level = i;
// link new entry
newEntry->PreviousNear = current;
newEntry->NextNear = next;
current->NextNear = newEntry;
next->PreviousNear = newEntry;
// set new entry
current = newEntry;
PushLevel(i, Math.Min(blockCount - 1, 2), bucket);
finalOffset += (ulong)s;
remainSize -= (ulong)s;
if (remainSize <= (ulong)levelSize)
{
int levelSize = levelSizeArray[^1] * 4;
ulong levelLong = (ulong)levelSize;
ulong board = endOffset / levelLong * levelLong;
int blockCount = (int)((board - finalOffset) / (ulong)levelSize);
if (blockCount > 0)
{
int s = blockCount * levelSize;
Entry* newEntry = (Entry*)_entries.Allocate();
newEntry->State = EntryState.Empty;
newEntry->Position = (nuint)((ulong)m_Buffer + finalOffset);
newEntry->Size = (uint)s;
BucketNode* bucket = (BucketNode*)newEntry->Position;
bucket->EntryRef = newEntry;
// link new entry
newEntry->PreviousNear = current;
newEntry->NextNear = next;
current->NextNear = newEntry;
if (next != null) {
next->PreviousNear = newEntry;
}
newEntry->Level = i;
PushLevel(i, Math.Min(blockCount - 1, 2), bucket);
// update lock and data
finalOffset += (ulong)s;
remainSize -= (ulong)s;
}
if (remainSize <= 0) {
return;
}
break;
}
if (remainSize == 0) {
return;
}
}
for (i -= 1; i >= 0; i--)
if (i >= 10)
{
int levelSize = levelSizeArray[^1] * 4;
ulong levelLong = (ulong)levelSize;
ulong board = endOffset / levelLong * levelLong;
long span = (long)board - (long)finalOffset;
int blockCount = span > 0 ? (int)(span / (long)levelSize) : 0;
if (blockCount > 0)
{
int levelSize = levelSizeArray[i];
ulong levelLong = (ulong)levelSize;
ulong board = endOffset / levelLong * levelLong;
int blockCount = (int)(board - finalOffset) / levelSize;
if (blockCount <= 0)
{
continue;
}
int s = blockCount * levelSize;
System.Diagnostics.Debug.Assert(finalOffset + (ulong)s <= endOffset);
// create and init new entry
Entry* newEntry = (Entry*)_entries.Allocate();
newEntry->State = EntryState.Empty;
newEntry->Position = (nuint)((ulong)m_Buffer + finalOffset);
newEntry->Size = (uint)s;
BucketNode* bucket = (BucketNode*)newEntry->Position;
bucket->EntryRef = newEntry;
newEntry->Level = 10;
// link new entry
newEntry->PreviousNear = current;
@@ -200,28 +178,59 @@ namespace StgSharp.HighPerformance.Memory
newEntry->Level = i;
PushLevel(i, Math.Min(blockCount - 1, 2), bucket);
// set new entry
// Entry* old = current;
current = newEntry;
// Console.WriteLine($"{(ulong)current->PreviousNear}<->{(ulong)current->NextNear},\t{current->Size}");
// update lock and data
finalOffset += (ulong)s;
remainSize -= (ulong)s;
if (remainSize <= 0)
{
break;
}
}
if (remainSize == 0) {
return;
}
}
finally
{
e->Size = (uint)(offset);
e->Level = GetLevelFromSize((uint)offset);
// Console.WriteLine("Alloc ok");
for (i -= 1; i >= 0; i--)
{
int levelSize = levelSizeArray[i];
ulong levelLong = (ulong)levelSize;
ulong board = endOffset / levelLong * levelLong;
long span = (long)board - (long)finalOffset;
int blockCount = span > 0 ? (int)(span / levelSize) : 0;
if (blockCount <= 0)
{
continue;
}
int s = blockCount * levelSize;
System.Diagnostics.Debug.Assert(finalOffset + (ulong)s <= endOffset);
// create and init new entry
Entry* newEntry = (Entry*)_entries.Allocate();
newEntry->State = EntryState.Empty;
newEntry->Position = (nuint)((ulong)m_Buffer + finalOffset);
newEntry->Size = (uint)s;
BucketNode* bucket = (BucketNode*)newEntry->Position;
bucket->EntryRef = newEntry;
// link new entry
newEntry->PreviousNear = current;
newEntry->NextNear = next;
current->NextNear = newEntry;
if (next != null) {
next->PreviousNear = newEntry;
}
newEntry->Level = i;
PushLevel(i, Math.Min(blockCount - 1, 2), bucket);
// set new entry
current = newEntry;
// update lock and data
finalOffset += (ulong)s;
remainSize -= (ulong)s;
if (remainSize == 0)
{
break;
}
}
RemoveFromPositionChain(e);
}
/// <summary>
@@ -236,42 +245,49 @@ namespace StgSharp.HighPerformance.Memory
private bool TryAllocateNew16MBBlock(out Entry* handle)
{
nuint pos = _spareMemory->Position;
nuint blockSize = (nuint)levelSizeArray[^1] * 2; // Use last level size (16MB)
nuint bufferEnd = (nuint)m_Buffer + _size;
Entry* previous;
previous = _spareMemory->PreviousNear;
if (_spareMemory->Size <= 0)
if (pos >= bufferEnd || _spareMemory->Size == 0)
{
handle = null;
return false; // No spare memory available
}
nuint newPos = pos + blockSize;
// Check if we have enough space
if (newPos > ((nuint)m_Buffer) + _size)
nuint desired = (nuint)levelSizeArray[^1] * 4;
nuint remain = bufferEnd - pos;
nuint blockSize = desired <= remain ? desired : remain;
if (blockSize == 0)
{
newPos = (nuint)m_Buffer + _size; // Clamp to maximum buffer size
blockSize = _spareMemory->Size;
previous = null;
handle = null;
return false;
}
nuint newPos = pos + blockSize;
// Try to allocate new Entry from slab allocator
handle = (Entry*)_entries.Allocate();
handle->Position = pos;
handle->Size = (uint)blockSize;
handle->Level = GetLevelFromSize((uint)blockSize);
// Update spare memory position
// Update spare memory position & remaining size
_spareMemory->Position = newPos;
_spareMemory->Size = (uint)(bufferEnd - newPos);
BucketNode* b = (BucketNode*)handle->Position;
b->EntryRef = handle;
// update position linked list
Entry* previous = _spareMemory->PreviousNear;
handle->NextNear = _spareMemory;
handle->PreviousNear = previous;
_spareMemory->PreviousNear = handle; // Replace Volatile.Write with direct access
if (previous != null) {
if (previous != null)
{
previous->NextNear = handle;
} else
{
_positionHead = handle;
}
return true;