going on reconstruct of HLSF

This commit is contained in:
Youmu Liu
2026-05-07 18:03:33 +08:00
parent c343e763ed
commit 8aa319a120
8 changed files with 220 additions and 265 deletions
@@ -26,6 +26,7 @@
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
using System;
using System.IO;
using System.Numerics;
using System.Reflection.Metadata;
using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle;
@@ -42,46 +43,37 @@ namespace StgSharp.HighPerformance.Memory
if (size > _maxAllocSize) {
throw new InvalidOperationException("Requested size exceeds maximum allocatable size.");
}
/*
int level = GetLevelFromSize(size);
int segmentIndex = DetermineSegmentIndex(_levelSizeArray, size, level);
int segmentIndex = GetSegmentFromLevel(size, level);
int i = level, s = segmentIndex;
Entry* handle;
while (!TryPopLevelForAllocation(i, s, out handle))
{
if (++s >= 3)
{
s = 0;
i++;
}
if (i > MaxLevel)
{
if (TryPopLevelForAllocation(10, 1, out handle))
{
break;
} else if (TryAllocateNew32MBBlock(out handle))
{
break;
}
throw new OverflowException("Out of memory: Unable to allocate new 16MB block or find suitable bucket for allocation.");
}
}
/**/
if (handle != null)
Entry* entry = null;
nuint requestedOffset = GetAllocSize(size);
(int level, int segment) = GetIndexPairOnce(size);
int index = (3 * level) + segment;
int i = index;
while ((i < _bucketHeads.Length) && !TryPopLevelForAllocation(index, out entry)) {
i++;
}
if ((i > _maxLevel) && !TryAllocateNewBlock(requestedOffset, out entry)) {
throw new OverflowException("Out of memory: Unable to allocate new 16MB block or find suitable bucket for allocation.");
}
if (entry != null)
{
int requestedOffset = (segmentIndex + 1) * ((int)_levelSizeArray[level]);
if (requestedOffset > (int)handle->Size) {
if (requestedOffset > entry->Size) {
throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
}
nuint remainder = handle->Size - ((nuint)requestedOffset);
SetEntryLevel(handle, handle->Position, (uint)requestedOffset);
handle->State = EntryState.Alloc;
nuint remainder = entry->Size - requestedOffset;
SetEntryLevel(entry, entry->Position, (uint)requestedOffset);
entry->State = EntryState.Alloc;
if (remainder > 0) {
SliceMemory(handle->NextNear, remainder);
OrganizeMemory(entry->NextNear, remainder);
}
}
return new(handle, size);
return new(entry, size);
}
public bool TryAlloc(
@@ -94,44 +86,35 @@ namespace StgSharp.HighPerformance.Memory
handle = default;
return false;
}
/*
int level = GetLevelFromSize(size);
int segmentIndex = DetermineSegmentIndex(_levelSizeArray, size, level);
int segmentIndex = GetSegmentFromLevel(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;
}
/**/
Entry* entry = null;
nuint requestedOffset = GetAllocSize(size);
(int level, int segment) = GetIndexPairOnce(size);
int index = (3 * level) + segment;
int i = index;
while ((i < _bucketHeads.Length) && !TryPopLevelForAllocation(index, out entry)) {
i++;
}
if ((i > _maxLevel) && !TryAllocateNewBlock(requestedOffset, out entry)) {
throw new OverflowException("Out of memory: Unable to allocate new 16MB block or find suitable bucket for allocation.");
}
if (entry != null)
{
int requestedOffset = (segmentIndex + 1) * ((int)_levelSizeArray[level]);
if (requestedOffset > (int)entry->Size) {
if (requestedOffset > entry->Size) {
throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
}
nuint remainder = entry->Size - ((nuint)requestedOffset);
nuint remainder = entry->Size - requestedOffset;
SetEntryLevel(entry, entry->Position, (uint)requestedOffset);
entry->State = EntryState.Alloc;
if (remainder > 0) {
SliceMemory(entry->NextNear, remainder);
OrganizeMemory(entry->NextNear, remainder);
}
}
handle = new(entry, size);
@@ -139,16 +122,16 @@ namespace StgSharp.HighPerformance.Memory
}
/// <summary>
/// Slice the memory block into smaller blocks and add them to the appropriate buckets
/// 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">
///
/// The next entry nearby the part to slice
/// </param>
/// <param name="sizeToSlice">
///
/// </param>
private void SliceMemory(
private void OrganizeMemory(
Entry* e,
nuint sizeToSlice
)
@@ -159,97 +142,22 @@ namespace StgSharp.HighPerformance.Memory
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++)
{
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)
{
nuint newSize = ((nuint)count) * size;
Entry* newEntry = (Entry*)_entries.Allocate();
InsertEntryBefore(newEntry, next);
SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize);
newEntry->State = EntryState.Empty;
BucketNode* b = (BucketNode*)newEntry->Position;
b->EntryRef = newEntry;
PushBucketToLevel(i, count - 1, b);
offset += newSize;
remain -= newSize;
}
if (remain <= 0) {
return;
}
}
if (i > MaxLevel)
{
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)
{
nuint newSize = ((nuint)count) * upper;
Entry* newEntry = (Entry*)_entries.Allocate();
InsertEntryBefore(newEntry, next);
SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize);
newEntry->State = EntryState.Empty;
BucketNode* b = (BucketNode*)newEntry->Position;
b->EntryRef = newEntry;
PushBucketToLevel(i, count - 1, b);
offset += newSize;
remain -= newSize;
if (remain <= 0) {
return;
}
}
}
for (i--; i >= 0; i--)
{
uint size = _levelSizeArray[i];
nuint edge = (end / size) * size;
int count = (int)((nuint.Min(edge, end) - offset) / size);
if (count > 0)
{
nuint newSize = ((nuint)count) * size;
Entry* newEntry = (Entry*)_entries.Allocate();
InsertEntryBefore(newEntry, next);
SetEntryLevel(newEntry, offset + ((nuint)m_Buffer), newSize);
newEntry->State = EntryState.Empty;
BucketNode* b = (BucketNode*)newEntry->Position;
b->EntryRef = newEntry;
b->NextLevel = null;
b->PreviousLevel = null;
PushBucketToLevel(i, count - 1, b);
offset += newSize;
remain -= newSize;
}
if (remain <= 0) {
return;
}
}
}
/// <summary>
/// Try to allocate a new 16MB block when all buckets are empty
/// </summary>
/// <param name="size">
/// Size of memory block to be allocated. Notice: Size is assumed as times of 64.
/// </param>
/// <param name="handle">
/// Output handle to the allocated Entry
/// </param>
/// <returns>
/// True if allocation succeeded
/// </returns>
private bool TryAllocateNew32MBBlock(
private bool TryAllocateNewBlock(
nuint size,
out Entry* handle
)
{
@@ -260,7 +168,7 @@ namespace StgSharp.HighPerformance.Memory
handle = null;
return false;
}
nuint size = (remain > 32 * 1024 * 1024L) ? (32 * 1024 * 1024U) : remain;
size = nuint.Min(size, remain);
// build new entry
@@ -278,6 +186,23 @@ namespace StgSharp.HighPerformance.Memory
return true;
}
/// <summary>
/// Helper method for allocation - converts BucketNode to Entry
/// </summary>
private bool TryPopLevelForAllocation(
int bucketIndex,
out Entry* entry
)
{
if (TryPopBucket(bucketIndex, out BucketNode* bucketNode))
{
entry = bucketNode->EntryRef;
return entry != null;
}
entry = null;
return false;
}
/// <summary>
/// Helper method for allocation - converts BucketNode to Entry
/// </summary>