going on reconstruct of HLSF
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Reflection.Metadata;
|
using System.Reflection.Metadata;
|
||||||
using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle;
|
using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle;
|
||||||
@@ -42,46 +43,37 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
if (size > _maxAllocSize) {
|
if (size > _maxAllocSize) {
|
||||||
throw new InvalidOperationException("Requested size exceeds maximum allocatable size.");
|
throw new InvalidOperationException("Requested size exceeds maximum allocatable size.");
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
int level = GetLevelFromSize(size);
|
int level = GetLevelFromSize(size);
|
||||||
int segmentIndex = DetermineSegmentIndex(_levelSizeArray, size, level);
|
int segmentIndex = GetSegmentFromLevel(size, level);
|
||||||
|
|
||||||
int i = level, s = segmentIndex;
|
int i = level, s = segmentIndex;
|
||||||
Entry* handle;
|
/**/
|
||||||
while (!TryPopLevelForAllocation(i, s, out handle))
|
|
||||||
{
|
Entry* entry = null;
|
||||||
if (++s >= 3)
|
nuint requestedOffset = GetAllocSize(size);
|
||||||
{
|
(int level, int segment) = GetIndexPairOnce(size);
|
||||||
s = 0;
|
int index = (3 * level) + segment;
|
||||||
|
int i = index;
|
||||||
|
while ((i < _bucketHeads.Length) && !TryPopLevelForAllocation(index, out entry)) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i > MaxLevel)
|
if ((i > _maxLevel) && !TryAllocateNewBlock(requestedOffset, out entry)) {
|
||||||
{
|
|
||||||
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.");
|
throw new OverflowException("Out of memory: Unable to allocate new 16MB block or find suitable bucket for allocation.");
|
||||||
}
|
}
|
||||||
}
|
if (entry != null)
|
||||||
|
|
||||||
if (handle != null)
|
|
||||||
{
|
{
|
||||||
int requestedOffset = (segmentIndex + 1) * ((int)_levelSizeArray[level]);
|
if (requestedOffset > entry->Size) {
|
||||||
if (requestedOffset > (int)handle->Size) {
|
|
||||||
throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
|
throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
|
||||||
}
|
}
|
||||||
nuint remainder = handle->Size - ((nuint)requestedOffset);
|
nuint remainder = entry->Size - requestedOffset;
|
||||||
SetEntryLevel(handle, handle->Position, (uint)requestedOffset);
|
SetEntryLevel(entry, entry->Position, (uint)requestedOffset);
|
||||||
handle->State = EntryState.Alloc;
|
entry->State = EntryState.Alloc;
|
||||||
if (remainder > 0) {
|
if (remainder > 0) {
|
||||||
SliceMemory(handle->NextNear, remainder);
|
OrganizeMemory(entry->NextNear, remainder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new(handle, size);
|
return new(entry, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAlloc(
|
public bool TryAlloc(
|
||||||
@@ -94,44 +86,35 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
handle = default;
|
handle = default;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
int level = GetLevelFromSize(size);
|
int level = GetLevelFromSize(size);
|
||||||
int segmentIndex = DetermineSegmentIndex(_levelSizeArray, size, level);
|
int segmentIndex = GetSegmentFromLevel(size, level);
|
||||||
|
|
||||||
int i = level, s = segmentIndex;
|
int i = level, s = segmentIndex;
|
||||||
Entry* entry;
|
/**/
|
||||||
while (!TryPopLevelForAllocation(i, s, out entry))
|
|
||||||
{
|
Entry* entry = null;
|
||||||
if (++s >= 3)
|
nuint requestedOffset = GetAllocSize(size);
|
||||||
{
|
(int level, int segment) = GetIndexPairOnce(size);
|
||||||
s = 0;
|
int index = (3 * level) + segment;
|
||||||
|
int i = index;
|
||||||
|
while ((i < _bucketHeads.Length) && !TryPopLevelForAllocation(index, out entry)) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (i > MaxLevel)
|
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 (TryPopLevelForAllocation(10, 1, out entry))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
} else if (TryAllocateNew32MBBlock(out entry))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
handle = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
{
|
{
|
||||||
int requestedOffset = (segmentIndex + 1) * ((int)_levelSizeArray[level]);
|
if (requestedOffset > entry->Size) {
|
||||||
if (requestedOffset > (int)entry->Size) {
|
|
||||||
throw new OverflowException("Out of memory: insufficient block size returned from spare memory.");
|
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);
|
SetEntryLevel(entry, entry->Position, (uint)requestedOffset);
|
||||||
entry->State = EntryState.Alloc;
|
entry->State = EntryState.Alloc;
|
||||||
if (remainder > 0) {
|
if (remainder > 0) {
|
||||||
SliceMemory(entry->NextNear, remainder);
|
OrganizeMemory(entry->NextNear, remainder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handle = new(entry, size);
|
handle = new(entry, size);
|
||||||
@@ -139,16 +122,16 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <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
|
/// Notice: this method is not responsible for freeing the original BucketNode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="e">
|
/// <param name="e">
|
||||||
///
|
/// The next entry nearby the part to slice
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="sizeToSlice">
|
/// <param name="sizeToSlice">
|
||||||
///
|
///
|
||||||
/// </param>
|
/// </param>
|
||||||
private void SliceMemory(
|
private void OrganizeMemory(
|
||||||
Entry* e,
|
Entry* e,
|
||||||
nuint sizeToSlice
|
nuint sizeToSlice
|
||||||
)
|
)
|
||||||
@@ -159,97 +142,22 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
nuint end = e->Position - ((nuint)m_Buffer); // end 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;
|
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>
|
/// <summary>
|
||||||
/// Try to allocate a new 16MB block when all buckets are empty
|
/// Try to allocate a new 16MB block when all buckets are empty
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="size">
|
||||||
|
/// Size of memory block to be allocated. Notice: Size is assumed as times of 64.
|
||||||
|
/// </param>
|
||||||
/// <param name="handle">
|
/// <param name="handle">
|
||||||
/// Output handle to the allocated Entry
|
/// Output handle to the allocated Entry
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// True if allocation succeeded
|
/// True if allocation succeeded
|
||||||
/// </returns>
|
/// </returns>
|
||||||
private bool TryAllocateNew32MBBlock(
|
private bool TryAllocateNewBlock(
|
||||||
|
nuint size,
|
||||||
out Entry* handle
|
out Entry* handle
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -260,7 +168,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
handle = null;
|
handle = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
nuint size = (remain > 32 * 1024 * 1024L) ? (32 * 1024 * 1024U) : remain;
|
size = nuint.Min(size, remain);
|
||||||
|
|
||||||
|
|
||||||
// build new entry
|
// build new entry
|
||||||
@@ -278,6 +186,23 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
return true;
|
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>
|
/// <summary>
|
||||||
/// Helper method for allocation - converts BucketNode to Entry
|
/// Helper method for allocation - converts BucketNode to Entry
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
public unsafe partial class HybridLayerSegregatedFitAllocator
|
public unsafe partial class HybridLayerSegregatedFitAllocator
|
||||||
{
|
{
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void PushBucketToLevel(
|
private void PushBucketToLevel(
|
||||||
int levelIndex,
|
int levelIndex,
|
||||||
int sizeIndex,
|
int sizeIndex,
|
||||||
@@ -45,7 +46,16 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Index index = (levelIndex > MaxLevel) ? (^1) : ((3 * levelIndex) + sizeIndex);
|
int index = (3 * levelIndex) + sizeIndex;
|
||||||
|
PushNodeToBucket(index, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PushNodeToBucket(
|
||||||
|
int index,
|
||||||
|
BucketNode* node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
index = (index >= _bucketHeads.Length) ? _bucketHeads.Length : index;
|
||||||
if (_bucketHeads[index] is null)
|
if (_bucketHeads[index] is null)
|
||||||
{
|
{
|
||||||
_bucketHeads[index] = node;
|
_bucketHeads[index] = node;
|
||||||
@@ -79,10 +89,11 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
BucketNode* node
|
BucketNode* node
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Index index = (levelIndex > MaxLevel) ? (^1) : ((3 * levelIndex) + sizeIndex);
|
int index = (3 * levelIndex) + sizeIndex;
|
||||||
|
index = (index >= _bucketHeads.Length) ? _bucketHeads.Length : index;
|
||||||
if (_bucketHeads[index] == node)
|
if (_bucketHeads[index] == node)
|
||||||
{
|
{
|
||||||
if (TryPopLevel(levelIndex, sizeIndex, out _)) {
|
if (TryPopBucket(index, out _)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,14 +113,16 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryPopLevel(
|
private bool TryPopBucket(
|
||||||
int levelIndex,
|
int index,
|
||||||
int sizeIndex,
|
|
||||||
out BucketNode* node
|
out BucketNode* node
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Index index = (levelIndex > MaxLevel) ? (^1) : ((3 * levelIndex) + sizeIndex);
|
/*
|
||||||
|
* Attention:
|
||||||
|
* This method is UNSAFE. Index may exceed range of _bucketHeads.
|
||||||
|
* Be careful when calling this method.
|
||||||
|
*/
|
||||||
BucketNode* head = _bucketHeads[index];
|
BucketNode* head = _bucketHeads[index];
|
||||||
|
|
||||||
if (head == null)
|
if (head == null)
|
||||||
@@ -126,24 +139,37 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
_bucketHeads[index] = null;
|
_bucketHeads[index] = null;
|
||||||
node = head;
|
node = head;
|
||||||
return true;
|
return true;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
next->PreviousLevel = null;
|
||||||
}
|
}
|
||||||
_bucketHeads[index] = head->NextLevel;
|
_bucketHeads[index] = head->NextLevel;
|
||||||
node = head;
|
node = head;
|
||||||
node->IsInBucket = false;
|
node->IsInBucket = false;
|
||||||
node->NextLevel = null;
|
node->NextLevel = null;
|
||||||
if (next != null) {
|
|
||||||
next->PreviousLevel = null;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private bool TryPopLevel(
|
||||||
|
int levelIndex,
|
||||||
|
int sizeIndex,
|
||||||
|
out BucketNode* node
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int index = (3 * levelIndex) + sizeIndex;
|
||||||
|
index = (index >= _bucketHeads.Length) ? (_bucketHeads.Length - 1) : index;
|
||||||
|
return TryPopBucket(index, out node);
|
||||||
|
}
|
||||||
|
|
||||||
private bool TryRemoveFromBucket(
|
private bool TryRemoveFromBucket(
|
||||||
int levelIndex,
|
int levelIndex,
|
||||||
int sizeIndex,
|
int sizeIndex,
|
||||||
BucketNode* node
|
BucketNode* node
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Index index = (levelIndex > 9) ? (^1) : ((3 * levelIndex) + sizeIndex);
|
int index = (3 * levelIndex) + sizeIndex;
|
||||||
|
index = (index >= _bucketHeads.Length) ? _bucketHeads.Length : index;
|
||||||
if (_bucketHeads[index] == node)
|
if (_bucketHeads[index] == node)
|
||||||
{
|
{
|
||||||
bool ok = TryPopLevel(levelIndex, sizeIndex, out _);
|
bool ok = TryPopLevel(levelIndex, sizeIndex, out _);
|
||||||
@@ -169,7 +195,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// BucketNode structure - specialized node for bucket linked lists Stored in main
|
/// BucketNode structure - specialized node for bucket linked lists Stored in main
|
||||||
/// allocation area (user-overwritable region)
|
/// allocation area (user-writable region)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
internal struct BucketNode
|
internal struct BucketNode
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// file="HLSFAllocator.Debug"
|
// file="HLSFAllocator.Debug"
|
||||||
// Project: StgSharp
|
// Project: StgSharp
|
||||||
// AuthorGroup: Nitload Space
|
// AuthorGroup: Nitload
|
||||||
// Copyright (c) Nitload Space. All rights reserved.
|
// Copyright (c) Nitload. 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
|
||||||
@@ -36,7 +36,8 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
public sealed class HLSFPositionChainBreakException : Exception
|
public sealed class HLSFPositionChainBreakException : Exception
|
||||||
{
|
{
|
||||||
|
|
||||||
public HLSFPositionChainBreakException() : base("Position chain of an HLSF allocator is broken") { }
|
public HLSFPositionChainBreakException()
|
||||||
|
: base("Position chain of an HLSF allocator is broken") { }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +46,9 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
|
|
||||||
private object _lock = new object();
|
private object _lock = new object();
|
||||||
|
|
||||||
public void DisplayEntryLayout(bool singleStep)
|
public void DisplayEntryLayout(
|
||||||
|
bool singleStep
|
||||||
|
)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
@@ -61,7 +64,10 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DumpPositionChain(bool singleStep = false, int maxCount = 4096)
|
public void DumpPositionChain(
|
||||||
|
bool singleStep = false,
|
||||||
|
int maxCount = 4096
|
||||||
|
)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
@@ -73,7 +79,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
cur = cur->NextNear;
|
cur = cur->NextNear;
|
||||||
}
|
}
|
||||||
Console.WriteLine(EntryToString(_spareMemory));
|
Console.WriteLine(EntryToString(_spareMemory));
|
||||||
while (cur != null && cur != _spareMemory && cnt < maxCount)
|
while ((cur != null) && (cur != _spareMemory) && (cnt < maxCount))
|
||||||
{
|
{
|
||||||
Console.WriteLine(EntryToString(cur));
|
Console.WriteLine(EntryToString(cur));
|
||||||
cnt++;
|
cnt++;
|
||||||
@@ -112,7 +118,9 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string EntryToString(Entry* e)
|
private static string EntryToString(
|
||||||
|
Entry* e
|
||||||
|
)
|
||||||
{
|
{
|
||||||
BucketNode* b = (BucketNode*)e->Position;
|
BucketNode* b = (BucketNode*)e->Position;
|
||||||
return $"{(ulong)e->PreviousNear}<-prev- Position:{(ulong)e} Bucket:{{{(ulong)e->Position},{e->Level},{e->Size}}} -next->{(ulong)e->NextNear}";
|
return $"{(ulong)e->PreviousNear}<-prev- Position:{(ulong)e} Bucket:{{{(ulong)e->Position},{e->Level},{e->Size}}} -next->{(ulong)e->NextNear}";
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
cur = next;
|
cur = next;
|
||||||
} while ((cur != null) && (cur != _spareMemory) && (cur->State == EntryState.Empty));
|
} while ((cur != null) && (cur != _spareMemory) && (cur->State == EntryState.Empty));
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
SliceMemory(cur, size);
|
OrganizeMemory(cur, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Security;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -38,31 +39,51 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
public unsafe partial class HybridLayerSegregatedFitAllocator
|
public unsafe partial class HybridLayerSegregatedFitAllocator
|
||||||
{
|
{
|
||||||
|
|
||||||
private const int MaxLevel = 9;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private nuint GetAllocSize(
|
||||||
private uint[] _levelSizeArray = [
|
nuint size
|
||||||
64U,
|
|
||||||
256U,
|
|
||||||
1024U,
|
|
||||||
4096U,
|
|
||||||
16384U,
|
|
||||||
65536U,
|
|
||||||
262144U,
|
|
||||||
1048576U,
|
|
||||||
4194304U,
|
|
||||||
16777216U
|
|
||||||
];
|
|
||||||
|
|
||||||
public int AlignOfLevel(
|
|
||||||
int bucketLevel
|
|
||||||
)
|
)
|
||||||
|
|
||||||
{
|
{
|
||||||
uint blockSize = _levelSizeArray[bucketLevel];
|
return (size + 63u) & (~63u);
|
||||||
return Math.Min((int)blockSize, _align);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int GetLevelFromSize(
|
private int GetBucketIndexOnce(
|
||||||
|
nuint size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int log2Size = 63 - BitOperations.LeadingZeroCount((ulong)size);
|
||||||
|
|
||||||
|
// Calculate level: level = max(0, (log2Size - 6) / 2)
|
||||||
|
int level = Math.Max(0, (log2Size - 6) / 2);
|
||||||
|
|
||||||
|
// caller is responsible for ensuring level is within bounds
|
||||||
|
level = Math.Min(level, _maxLevel);
|
||||||
|
uint levelSize = 1u << (log2Size & (~1));
|
||||||
|
int segment = ((int)(size / levelSize)) - 1;
|
||||||
|
return (level * 3) + segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private (int level, int segment) GetIndexPairOnce(
|
||||||
|
nuint size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int log2Size = 63 - BitOperations.LeadingZeroCount((ulong)size);
|
||||||
|
|
||||||
|
// Calculate level: level = max(0, (log2Size - 6) / 2)
|
||||||
|
int level = Math.Max(0, (log2Size - 6) / 2);
|
||||||
|
|
||||||
|
// caller is responsible for ensuring level is within bounds
|
||||||
|
level = Math.Min(level, _maxLevel);
|
||||||
|
uint levelSize = 1u << (log2Size & (~1));
|
||||||
|
int segment = ((int)(size / levelSize)) - 1;
|
||||||
|
return (level, segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private int GetLevelFromSize(
|
||||||
nuint size
|
nuint size
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -83,27 +104,38 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
int level = Math.Max(0, (log2Size - 6) / 2);
|
int level = Math.Max(0, (log2Size - 6) / 2);
|
||||||
|
|
||||||
// caller is responsible for ensuring level is within bounds
|
// caller is responsible for ensuring level is within bounds
|
||||||
return level;
|
return Math.Min(level, _maxLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static int GetLevelFromSize(
|
private static uint GetLevelSizeFromLevel(
|
||||||
uint size
|
int level
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return GetLevelFromSize(size);
|
return 1u << (6 + (2 * level));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static uint GetLevelSizeFromSize(
|
||||||
public enum CommonMemoryAlign : int
|
nuint size
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
int log2Size = 63 - BitOperations.LeadingZeroCount((ulong)size);
|
||||||
|
return 1u << (log2Size & (~1));
|
||||||
|
}
|
||||||
|
|
||||||
XMMLevel = 16,
|
/// <summary>
|
||||||
YMMLevel = 32,
|
/// Determine segment index based on size and originLevel. Input level value is regarded
|
||||||
ZMMLevel = 64,
|
/// safe.
|
||||||
|
/// </summary>
|
||||||
ArmNEONLevel = 16,
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private int GetSegmentFromLevel(
|
||||||
|
ulong size,
|
||||||
|
int level
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return ((int)(size / GetLevelSizeFromLevel(level))) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check if two Entries are adjacent in memory
|
/// Check if two Entries are adjacent in memory
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// True if two mem blocks are adjacent.
|
||||||
|
/// </returns>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool AssertAdjacentTo(
|
private static bool AssertAdjacentTo(
|
||||||
Entry* current,
|
Entry* current,
|
||||||
@@ -48,36 +51,6 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
(current->Position + current->Size == other->Position);
|
(current->Position + current->Size == other->Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// check out if a bucket is within the same higher-level boundary as currentOffset
|
|
||||||
/// </summary>
|
|
||||||
private bool AssertBoundary(
|
|
||||||
Entry* previous,
|
|
||||||
Entry* current,
|
|
||||||
int level
|
|
||||||
)
|
|
||||||
{
|
|
||||||
level = int.Min(level, MaxLevel);
|
|
||||||
uint nextLevelSize = _levelSizeArray[level] * 4;
|
|
||||||
ulong prevHead = previous->Position - ((ulong)m_Buffer),
|
|
||||||
currHead = current->Position - ((ulong)m_Buffer);
|
|
||||||
return currHead / nextLevelSize == prevHead / nextLevelSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Determine segment index based on size and originLevel
|
|
||||||
/// </summary>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static int DetermineSegmentIndex(
|
|
||||||
uint[] levelSizeArray,
|
|
||||||
ulong size,
|
|
||||||
int level
|
|
||||||
)
|
|
||||||
{
|
|
||||||
level = int.Min(level, MaxLevel);
|
|
||||||
return (int)((size - 1) / levelSizeArray[level]);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void InsertEntryAfter(
|
private static void InsertEntryAfter(
|
||||||
Entry* entry,
|
Entry* entry,
|
||||||
@@ -120,7 +93,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
|
|
||||||
nuint size = entry->Size;
|
nuint size = entry->Size;
|
||||||
int originLevel = entry->Level;
|
int originLevel = entry->Level;
|
||||||
int segment = DetermineSegmentIndex(_levelSizeArray, size, originLevel);
|
int segment = GetSegmentFromLevel(size, originLevel);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// previous direction merge
|
// previous direction merge
|
||||||
@@ -129,7 +102,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
(p == _spareMemory) ||
|
(p == _spareMemory) ||
|
||||||
(p->State != EntryState.Empty) ||
|
(p->State != EntryState.Empty) ||
|
||||||
(p->Level != entry->Level) ||
|
(p->Level != entry->Level) ||
|
||||||
!AssertBoundary(p, entry, originLevel))
|
!AssertAdjacentTo(p, entry))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -137,7 +110,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
// Console.WriteLine($"{(ulong)p->Size} merged to {(ulong)entry->Size} previous");
|
// Console.WriteLine($"{(ulong)p->Size} merged to {(ulong)entry->Size} previous");
|
||||||
entry->Size += p->Size;
|
entry->Size += p->Size;
|
||||||
entry->Position = p->Position;
|
entry->Position = p->Position;
|
||||||
RemoveFromBucket(originLevel, DetermineSegmentIndex(_levelSizeArray, p->Size, originLevel), (BucketNode*)p->Position);
|
RemoveFromBucket(originLevel, GetSegmentFromLevel(p->Size, originLevel), (BucketNode*)p->Position);
|
||||||
RemoveFromPositionChain(p);
|
RemoveFromPositionChain(p);
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
@@ -149,19 +122,18 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
(n == _spareMemory) ||
|
(n == _spareMemory) ||
|
||||||
(n->State != EntryState.Empty) ||
|
(n->State != EntryState.Empty) ||
|
||||||
(n->Level != entry->Level) ||
|
(n->Level != entry->Level) ||
|
||||||
!AssertBoundary(n, entry, originLevel))
|
!AssertAdjacentTo(n, entry))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Console.WriteLine($"{(ulong)n->Size} merged to {(ulong)entry->Size} next");
|
// Console.WriteLine($"{(ulong)n->Size} merged to {(ulong)entry->Size} next");
|
||||||
entry->Size += n->Size;
|
entry->Size += n->Size;
|
||||||
RemoveFromBucket(originLevel, DetermineSegmentIndex(_levelSizeArray, n->Size, originLevel), (BucketNode*)n->Position);
|
RemoveFromBucket(originLevel, GetSegmentFromLevel(n->Size, originLevel), (BucketNode*)n->Position);
|
||||||
RemoveFromPositionChain(n);
|
RemoveFromPositionChain(n);
|
||||||
} while (true);
|
} while (true);
|
||||||
originLevel = int.Min(9, originLevel);
|
originLevel = int.Min(9, originLevel);
|
||||||
entry->Level += (entry->Size >= _levelSizeArray[originLevel] * 4) ? 1 : 0;
|
entry->Level = GetLevelFromSize(entry->Size);
|
||||||
entry->Level &= 15;
|
|
||||||
|
|
||||||
BucketNode* bucket = (BucketNode*)entry->Position;
|
BucketNode* bucket = (BucketNode*)entry->Position;
|
||||||
bucket->EntryRef = entry;
|
bucket->EntryRef = entry;
|
||||||
@@ -190,7 +162,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void SetEntryLevel(
|
private void SetEntryLevel(
|
||||||
Entry* entry,
|
Entry* entry,
|
||||||
nuint position,
|
nuint position,
|
||||||
nuint size
|
nuint size
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ using System.Buffers;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using hlsfHandle = StgSharp.HighPerformance.Memory.HlsfHandle;
|
|
||||||
|
|
||||||
namespace StgSharp.HighPerformance.Memory
|
namespace StgSharp.HighPerformance.Memory
|
||||||
{
|
{
|
||||||
@@ -47,6 +46,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
private readonly Action<nuint> _freeHandle;
|
private readonly Action<nuint> _freeHandle;
|
||||||
private bool disposedValue;
|
private bool disposedValue;
|
||||||
private readonly int _align;
|
private readonly int _align;
|
||||||
|
private readonly int _maxLevel;
|
||||||
private readonly nuint _maxAllocSize;
|
private readonly nuint _maxAllocSize;
|
||||||
private readonly nuint _size;
|
private readonly nuint _size;
|
||||||
private readonly SlabAllocator<Entry> _entries;
|
private readonly SlabAllocator<Entry> _entries;
|
||||||
@@ -88,16 +88,8 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
_spareMemory->Position = (nuint)m_Buffer;
|
_spareMemory->Position = (nuint)m_Buffer;
|
||||||
_spareMemory->Size = byteSize;
|
_spareMemory->Size = byteSize;
|
||||||
|
|
||||||
int levelCountOrigin = _levelSizeArray.Length;
|
_maxLevel = GetLevelFromSize(maxBlockSize) + 1;
|
||||||
int levelCount = GetLevelFromSize(maxBlockSize) + 1;
|
_bucketHeads = new BucketNode*[(_maxLevel * 3) + 1];
|
||||||
Array.Resize(ref _levelSizeArray, levelCount);
|
|
||||||
_bucketHeads = new BucketNode*[(levelCount * 3) + 1];
|
|
||||||
uint size = _levelSizeArray[^1];
|
|
||||||
for (int i = levelCountOrigin; i < levelCount; i++)
|
|
||||||
{
|
|
||||||
size *= 4;
|
|
||||||
_levelSizeArray[i] = size;
|
|
||||||
}
|
|
||||||
_maxAllocSize = maxBlockSize;
|
_maxAllocSize = maxBlockSize;
|
||||||
_freeHandle = freeHandle ?? (static _ => { });
|
_freeHandle = freeHandle ?? (static _ => { });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace StgSharp.HighPerformance.Memory
|
|||||||
private const int PredictionCount = 2048;
|
private const int PredictionCount = 2048;
|
||||||
private const int PredictionLeastAhead = 1024;
|
private const int PredictionLeastAhead = 1024;
|
||||||
|
|
||||||
private static readonly IIntrinsicKernel _intrinsic = IIntrinsicKernel.Instance;
|
// private static readonly IIntrinsicKernel _intrinsic = IIntrinsicKernel.Instance;
|
||||||
private readonly CacheLineHead* _head;
|
private readonly CacheLineHead* _head;
|
||||||
private readonly MapArray* _mapCount;
|
private readonly MapArray* _mapCount;
|
||||||
private readonly PredictionArray* _predictCount;
|
private readonly PredictionArray* _predictCount;
|
||||||
|
|||||||
Reference in New Issue
Block a user