hlsf error is solving
This commit is contained in:
@@ -26,8 +26,10 @@
|
||||
// -----------------------------------------------------------------------
|
||||
// -----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.Tracing;
|
||||
using System.Numerics;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using hlsfHandle = StgSharp.HighPerformance.Memory.HybridLayerSegregatedFitAllocationHandle;
|
||||
|
||||
namespace StgSharp.HighPerformance.Memory
|
||||
@@ -37,7 +39,15 @@ namespace StgSharp.HighPerformance.Memory
|
||||
|
||||
public hlsfHandle Alloc(uint size)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThan<nuint>(size, (nuint)levelSizeArray[^1] * 2);
|
||||
if (size > 32U * 1024U * 1024U)
|
||||
{
|
||||
Entry* e = (Entry*)_entries.Allocate();
|
||||
e->Size = size;
|
||||
e->Position = (nuint)NativeMemory.AlignedAlloc(size, (nuint)_align);
|
||||
e->State = EntryState.Large;
|
||||
return new hlsfHandle(e, size);
|
||||
}
|
||||
|
||||
int level = GetLevelFromSize(size);
|
||||
int segmentIndex = DetermineSegmentIndex(size, level);
|
||||
|
||||
@@ -63,174 +73,144 @@ namespace StgSharp.HighPerformance.Memory
|
||||
if (handle != null)
|
||||
{
|
||||
int requestedOffset = (segmentIndex + 1) * levelSizeArray[level];
|
||||
if ((ulong)requestedOffset > handle->Size)
|
||||
{
|
||||
// spare返回的块不足以切出目标大小,避免进入切片导致下溢/越界
|
||||
if (requestedOffset > handle->Size) {
|
||||
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);
|
||||
long remainder = handle->Size - requestedOffset;
|
||||
if (remainder > 0)
|
||||
{
|
||||
Entry* extra = (Entry*)_entries.Allocate();
|
||||
extra->Position = handle->Position + (nuint)requestedOffset;
|
||||
extra->Size = (uint)remainder;
|
||||
extra->State = EntryState.Empty;
|
||||
extra->NextNear = handle->NextNear;
|
||||
extra->PreviousNear = handle;
|
||||
extra->NextNear->PreviousNear = extra;
|
||||
extra->PreviousNear->NextNear = extra;
|
||||
SliceMemory(extra);
|
||||
}
|
||||
handle->State = EntryState.Alloc;
|
||||
handle->Size = requestedOffset;
|
||||
handle->Level = level;
|
||||
}
|
||||
handle->State = EntryState.Allocated;
|
||||
handle->Level = level;
|
||||
return new hlsfHandle(handle, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slice the memory block into smaller blocks and add them to the appropriate buckets
|
||||
/// Notice: this method is not responsible for freeing the original BucketNode
|
||||
/// </summary>
|
||||
/// <param name="e">
|
||||
///
|
||||
/// </param>
|
||||
private void SliceMemory(Entry* e)
|
||||
{
|
||||
Entry* current = e;
|
||||
Entry* cur = e->PreviousNear;
|
||||
Entry* next = e->NextNear;
|
||||
ulong originOffset = e->Position - (ulong)m_Buffer;
|
||||
ulong finalOffset = originOffset;
|
||||
ulong end = e->Position + e->Size;
|
||||
ulong endOffset = end - (ulong)m_Buffer;
|
||||
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;
|
||||
long remain = e->Size;
|
||||
long offset = (long)e->Position - (long)m_Buffer;
|
||||
long end = offset + remain;
|
||||
_entries.Free((nuint)e);
|
||||
|
||||
int i = (BitOperations.TrailingZeroCount(remain) - 6) / 2;
|
||||
i = int.Min(10, 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 size = levelSizeArray[i];
|
||||
int upper = size * 4;
|
||||
long edge = (offset + upper - 1) / upper * upper;
|
||||
int count = (int)((long.Min(edge, end) - offset) / size);
|
||||
if (count > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int s = blockCount * levelSize;
|
||||
int newSize = count * size;
|
||||
|
||||
// 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)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (remainSize == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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 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;
|
||||
newEntry->Level = 10;
|
||||
|
||||
// link new entry
|
||||
newEntry->PreviousNear = current;
|
||||
newEntry->PreviousNear = cur;
|
||||
newEntry->NextNear = next;
|
||||
current->NextNear = newEntry;
|
||||
if (next != null) {
|
||||
next->PreviousNear = newEntry;
|
||||
}
|
||||
|
||||
cur->NextNear = newEntry;
|
||||
next->PreviousNear = newEntry;
|
||||
newEntry->Position = (nuint)offset + (nuint)m_Buffer;
|
||||
newEntry->State = EntryState.Empty;
|
||||
newEntry->Size = (uint)newSize;
|
||||
newEntry->Level = i;
|
||||
PushLevel(i, Math.Min(blockCount - 1, 2), bucket);
|
||||
|
||||
finalOffset += (ulong)s;
|
||||
remainSize -= (ulong)s;
|
||||
BucketNode* b = (BucketNode*)newEntry->Position;
|
||||
b->EntryRef = newEntry;
|
||||
PushLevel(i, count - 1, b);
|
||||
offset += newSize;
|
||||
remain -= (long)newSize;
|
||||
cur = newEntry;
|
||||
}
|
||||
if (remainSize == 0) {
|
||||
if (remain <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i -= 1; i >= 0; i--)
|
||||
if (i > MaxLevel)
|
||||
{
|
||||
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)
|
||||
int size = levelSizeArray[^1];
|
||||
int upper = size * 4;
|
||||
long edge = end / upper * upper;
|
||||
int count = (int)((long.Min(edge, end) - offset) / upper);
|
||||
if (count > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int s = blockCount * levelSize;
|
||||
System.Diagnostics.Debug.Assert(finalOffset + (ulong)s <= endOffset);
|
||||
int newSize = count * upper;
|
||||
|
||||
// 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) {
|
||||
Entry* newEntry = (Entry*)_entries.Allocate();
|
||||
newEntry->PreviousNear = cur;
|
||||
newEntry->NextNear = next;
|
||||
cur->NextNear = newEntry;
|
||||
next->PreviousNear = newEntry;
|
||||
}
|
||||
newEntry->Position = (nuint)offset + (nuint)m_Buffer;
|
||||
newEntry->State = EntryState.Empty;
|
||||
newEntry->Size = (uint)newSize;
|
||||
newEntry->Level = i;
|
||||
|
||||
newEntry->Level = i;
|
||||
PushLevel(i, Math.Min(blockCount - 1, 2), bucket);
|
||||
BucketNode* b = (BucketNode*)newEntry->Position;
|
||||
b->EntryRef = newEntry;
|
||||
PushLevel(i, count - 1, b);
|
||||
cur = newEntry;
|
||||
offset += newSize;
|
||||
remain -= (long)newSize;
|
||||
if (remain <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set new entry
|
||||
current = newEntry;
|
||||
for (i--; i >= 0; i--)
|
||||
{
|
||||
int size = levelSizeArray[i];
|
||||
long edge = end / size * size;
|
||||
int count = (int)((long.Min(edge, end) - offset) / size);
|
||||
if (count > 0)
|
||||
{
|
||||
int newSize = count * size;
|
||||
|
||||
Entry* newEntry = (Entry*)_entries.Allocate();
|
||||
newEntry->PreviousNear = cur;
|
||||
newEntry->NextNear = next;
|
||||
cur->NextNear = newEntry;
|
||||
next->PreviousNear = newEntry;
|
||||
newEntry->Position = (nuint)offset + (nuint)m_Buffer;
|
||||
newEntry->State = EntryState.Empty;
|
||||
newEntry->Size = (uint)newSize;
|
||||
newEntry->Level = i;
|
||||
|
||||
// update lock and data
|
||||
finalOffset += (ulong)s;
|
||||
remainSize -= (ulong)s;
|
||||
if (remainSize == 0)
|
||||
{
|
||||
break;
|
||||
BucketNode* b = (BucketNode*)newEntry->Position;
|
||||
b->EntryRef = newEntry;
|
||||
b->NextLevel = null;
|
||||
b->PreviousLevel = null;
|
||||
PushLevel(i, count - 1, b);
|
||||
|
||||
cur = newEntry;
|
||||
offset += newSize;
|
||||
remain -= (long)newSize;
|
||||
}
|
||||
if (remain <= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
RemoveFromPositionChain(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -245,51 +225,32 @@ namespace StgSharp.HighPerformance.Memory
|
||||
private bool TryAllocateNew16MBBlock(out Entry* handle)
|
||||
{
|
||||
nuint pos = _spareMemory->Position;
|
||||
nuint bufferEnd = (nuint)m_Buffer + _size;
|
||||
|
||||
if (pos >= bufferEnd || _spareMemory->Size == 0)
|
||||
{
|
||||
handle = null;
|
||||
return false; // No spare memory available
|
||||
}
|
||||
|
||||
nuint desired = (nuint)levelSizeArray[^1] * 4;
|
||||
nuint remain = bufferEnd - pos;
|
||||
nuint blockSize = desired <= remain ? desired : remain;
|
||||
if (blockSize == 0)
|
||||
long remain = _spareMemory->Size;
|
||||
if (remain <= 0)
|
||||
{
|
||||
handle = null;
|
||||
return false;
|
||||
}
|
||||
long size = remain > 16 * 1024 * 1024L ? 16 * 1024 * 1024L : remain;
|
||||
|
||||
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);
|
||||
// build new entry
|
||||
Entry* e = (Entry*)_entries.Allocate();
|
||||
e->Position = pos;
|
||||
e->Size = size;
|
||||
Entry* prev = _spareMemory->PreviousNear;
|
||||
e->NextNear = _spareMemory;
|
||||
e->PreviousNear = prev;
|
||||
prev->NextNear = e;
|
||||
_spareMemory->PreviousNear = e;
|
||||
e->State = EntryState.Empty;
|
||||
e->Level = GetLevelFromSize(size);
|
||||
|
||||
// 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)
|
||||
{
|
||||
previous->NextNear = handle;
|
||||
} else
|
||||
{
|
||||
_positionHead = handle;
|
||||
}
|
||||
// set fields of spare memory
|
||||
_spareMemory->Size -= size;
|
||||
_spareMemory->Position += (nuint)size;
|
||||
|
||||
handle = e;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user