HLSf use nuint rather than long, L4 now uses hlsf rather than array to alloc cache line.

This commit is contained in:
Youmu Liu
2026-04-20 18:10:14 +08:00
parent 1b7c929be4
commit 2e2d64a2ce
38 changed files with 796 additions and 465 deletions
@@ -1,43 +1,43 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
// file="HLSFAllocator.Alloc.cs"
// file="HLSFAllocator.Alloc"
// Project: StgSharp
// AuthorGroup: Nitload Space
// Copyright (c) Nitload Space. All rights reserved.
// AuthorGroup: Nitload
// Copyright (c) Nitload. 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 in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and
// this permission notice shall be included in all copies
// or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”,
// WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using System;
using System.Numerics;
using hlsfHandle = StgSharp.Mathematics.Memory.hlsfHandle;
using System.Reflection.Metadata;
using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle;
namespace StgSharp.Mathematics.Memory
namespace StgSharp.HighPerformance.Memory
{
public unsafe partial class HybridLayerSegregatedFitAllocator
{
public partial hlsfHandle Alloc(long size)
public partial HlsfHandle Alloc(
nuint size
)
{
if (size > _maxSize) {
throw new InvalidOperationException("Requested size exceeds maximum allocatable size.");
@@ -70,18 +70,72 @@ namespace StgSharp.Mathematics.Memory
if (handle != null)
{
int requestedOffset = (segmentIndex + 1) * _levelSizeArray[level];
if (requestedOffset > handle->Size) {
int requestedOffset = (segmentIndex + 1) * ((int)_levelSizeArray[level]);
if (requestedOffset > (int)handle->Size) {
throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
}
long remainder = handle->Size - requestedOffset;
nuint remainder = handle->Size - ((nuint)requestedOffset);
SetEntryLevel(handle, handle->Position, (uint)requestedOffset);
handle->State = EntryState.Alloc;
if (remainder > 0) {
SliceMemory(handle->NextNear, remainder);
}
}
return new hlsfHandle(handle, size);
return new(handle, size);
}
public bool TryAlloc(
nuint size,
out HlsfHandle handle
)
{
if (size > _maxSize)
{
handle = default;
return false;
}
int level = GetLevelFromSize(size);
int segmentIndex = DetermineSegmentIndex(_levelSizeArray, size, level);
int i = level, s = segmentIndex;
Entry* entry;
while (!TryPopLevelForAllocation(i, s, out entry))
{
if (++s >= 3)
{
s = 0;
i++;
}
if (i > MaxLevel)
{
if (TryPopLevelForAllocation(10, 1, out entry))
{
break;
} else if (TryAllocateNew32MBBlock(out entry))
{
break;
}
handle = default;
return false;
}
}
if (entry != null)
{
int requestedOffset = (segmentIndex + 1) * ((int)_levelSizeArray[level]);
if (requestedOffset > (int)entry->Size) {
throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
}
nuint remainder = entry->Size - ((nuint)requestedOffset);
SetEntryLevel(entry, entry->Position, (uint)requestedOffset);
entry->State = EntryState.Alloc;
if (remainder > 0) {
SliceMemory(entry->NextNear, remainder);
}
}
handle = new(entry, size);
return true;
}
/// <summary>
@@ -94,28 +148,31 @@ namespace StgSharp.Mathematics.Memory
/// <param name="sizeToSlice">
///
/// </param>
private void SliceMemory(Entry* e, long sizeToSlice)
private void SliceMemory(
Entry* e,
nuint sizeToSlice
)
{
Entry* next = e;
long remain = sizeToSlice; // remained size to slice
long offset = (long)e->Position - sizeToSlice - (long)m_Buffer; // offset of buffer to slice
long end = (long)e->Position - (long)m_Buffer; // end offset of buffer to slice
nuint remain = sizeToSlice; // remained size to slice
nuint offset = e->Position - sizeToSlice - ((nuint)m_Buffer); // offset of buffer to slice
nuint end = e->Position - ((nuint)m_Buffer); // end offset of buffer to slice
int i = (BitOperations.TrailingZeroCount(offset) - 6) / 2;
i = int.Min(10, i);
for (; i < _levelSizeArray.Length; i++)
{
int size = _levelSizeArray[i];
int upper = size * 4;
long edge = (offset + upper - 1) / upper * upper;
int count = (int)((long.Min(edge, end) - offset) / size);
uint size = _levelSizeArray[i];
nuint upper = size * 4;
nuint edge = (((offset + upper) - 1U) / upper) * upper;
int count = (int)((nuint.Min(edge, end) - offset) / size);
if (count > 0)
{
long newSize = count * size;
nuint newSize = ((nuint)count) * size;
Entry* newEntry = (Entry*)_entries.Allocate();
InsertEntryBefore(newEntry, next);
SetEntryLevel(newEntry, (nuint)offset + (nuint)m_Buffer, newSize);
SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize);
newEntry->State = EntryState.Empty;
BucketNode* b = (BucketNode*)newEntry->Position;
@@ -131,17 +188,17 @@ namespace StgSharp.Mathematics.Memory
if (i > MaxLevel)
{
int size = _levelSizeArray[^1];
int upper = size * 4;
long edge = end / upper * upper;
int count = (int)((long.Min(edge, end) - offset) / upper);
uint size = _levelSizeArray[^1];
nuint upper = size * 4;
nuint edge = (end / upper) * upper;
int count = (int)((nuint.Min(edge, end) - offset) / upper);
if (count > 0)
{
long newSize = (long)count * (long)upper;
nuint newSize = ((nuint)count) * upper;
Entry* newEntry = (Entry*)_entries.Allocate();
InsertEntryBefore(newEntry, next);
SetEntryLevel(newEntry, (nuint)offset + (nuint)m_Buffer, newSize);
SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize);
newEntry->State = EntryState.Empty;
BucketNode* b = (BucketNode*)newEntry->Position;
@@ -157,16 +214,16 @@ namespace StgSharp.Mathematics.Memory
for (i--; i >= 0; i--)
{
int size = _levelSizeArray[i];
long edge = end / size * size;
int count = (int)((long.Min(edge, end) - offset) / size);
uint size = _levelSizeArray[i];
nuint edge = (end / size) * size;
int count = (int)((nuint.Min(edge, end) - offset) / size);
if (count > 0)
{
long newSize = count * size;
nuint newSize = ((nuint)count) * size;
Entry* newEntry = (Entry*)_entries.Allocate();
InsertEntryBefore(newEntry, next);
SetEntryLevel(newEntry, (nuint)offset + (nuint)m_Buffer, newSize);
SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize);
newEntry->State = EntryState.Empty;
BucketNode* b = (BucketNode*)newEntry->Position;
@@ -192,16 +249,18 @@ namespace StgSharp.Mathematics.Memory
/// <returns>
/// True if allocation succeeded
/// </returns>
private bool TryAllocateNew32MBBlock(out Entry* handle)
private bool TryAllocateNew32MBBlock(
out Entry* handle
)
{
nuint pos = _spareMemory->Position;
long remain = _spareMemory->Size;
nuint remain = _spareMemory->Size;
if (remain <= 0)
{
handle = null;
return false;
}
long size = remain > 32 * 1024 * 1024L ? 32 * 1024 * 1024L : remain;
nuint size = (remain > 32 * 1024 * 1024L) ? (32 * 1024 * 1024U) : remain;
// build new entry
@@ -212,7 +271,7 @@ namespace StgSharp.Mathematics.Memory
// set fields of spare memory
_spareMemory->Size -= size;
_spareMemory->Position += (nuint)size;
_spareMemory->Position += size;
handle = e;
@@ -222,7 +281,11 @@ namespace StgSharp.Mathematics.Memory
/// <summary>
/// Helper method for allocation - converts BucketNode to Entry
/// </summary>
private bool TryPopLevelForAllocation(int levelIndex, int sizeIndex, out Entry* entry)
private bool TryPopLevelForAllocation(
int levelIndex,
int sizeIndex,
out Entry* entry
)
{
if (TryPopLevel(levelIndex, sizeIndex, out BucketNode* bucketNode))
{