diff --git a/StgSharp.Common/HighPerformance/Memory/L4.Evict.cs b/StgSharp.Common/HighPerformance/Memory/L4.Evict.cs
index 1d878efa..57d22f1e 100644
--- a/StgSharp.Common/HighPerformance/Memory/L4.Evict.cs
+++ b/StgSharp.Common/HighPerformance/Memory/L4.Evict.cs
@@ -1,9 +1,9 @@
//-----------------------------------------------------------------------
// -----------------------------------------------------------------------
-// file="L4.InternalOp"
+// file="L4.Evict"
// Project: StgSharp
-// AuthorGroup: Nitload
-// Copyright (c) Nitload. All rights reserved.
+// AuthorGroup: Nitload Space
+// Copyright (c) Nitload Space. 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
@@ -54,10 +54,17 @@ namespace StgSharp.HighPerformance.Memory
}
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Count of lines not evicted
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private unsafe void Evict(
- int count = 1
- )
+ private unsafe int Evict(int count = 1)
{
int remain = count;
Vector128 one = Vector128.Create((byte)0x01);
@@ -77,32 +84,30 @@ namespace StgSharp.HighPerformance.Memory
{
// EvictLine(i + index);
_ = _map.TryRemove(head->_origin, out _);
+ PrefetchPredict.WriteBack(head->_address, head->_profile, new ReadOnlySpan((byte*)head->_address, Unsafe.SizeOf()));
RecycleLine(index);
remain--;
}
evictMask &= evictMask - 1;
}
}
+ return remain;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void RecycleLine(
- int id
- )
+ private void RecycleLine(int id)
{
_idMux.Push(id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool TryGetEmptyLine(
- out int index
- )
+ private bool TryGetEmptyLine(out int index)
{
if (_idMux.TryPop(out index)) {
return true;
}
index = _maxId;
- return Interlocked.Increment(ref _maxId) >= CacheLineCount;
+ return Interlocked.Increment(ref _maxId) <= CacheLineCount;
}
}
diff --git a/StgSharp.Common/HighPerformance/Memory/L4.Predict.cs b/StgSharp.Common/HighPerformance/Memory/L4.Predict.cs
index 651aa891..388f7fa3 100644
--- a/StgSharp.Common/HighPerformance/Memory/L4.Predict.cs
+++ b/StgSharp.Common/HighPerformance/Memory/L4.Predict.cs
@@ -36,11 +36,50 @@ namespace StgSharp.HighPerformance.Memory
public interface IPrefetchPredict
{
- int Predict(Span node);
+ ///
+ /// Writes predicted cache line descriptors into .
+ ///
+ ///
+ /// Prediction output buffer.
+ ///
+ ///
+ /// When this method returns, contains the number of valid entries written to . The value must not exceed .Length.
+ ///
+ ///
+ /// if any prediction data was produced; otherwise, .
+ ///
+ bool Predict(Span node, out int count);
- bool Prefetch(nuint origin, ulong policy, nuint cache);
+ ///
+ /// Materializes the cache line identified by into .
+ ///
+ ///
+ /// Source address associated with the cache line.
+ ///
+ ///
+ /// Mapping policy associated with the cache line.
+ ///
+ ///
+ /// Destination cache line buffer.
+ ///
+ void Prefetch(nuint origin, ulong policy, Span cache);
- void WriteBack(nuint origin, ulong policy, nuint cache);
+ ///
+ /// Writes the cache line in back to .
+ ///
+ ///
+ /// Source address associated with the cache line.
+ ///
+ ///
+ /// Mapping policy associated with the cache line.
+ ///
+ ///
+ /// Source cache line buffer.
+ ///
+ void WriteBack(nuint origin, ulong policy, ReadOnlySpan cache);
}
diff --git a/StgSharp.Common/HighPerformance/Memory/L4.Prefetch.cs b/StgSharp.Common/HighPerformance/Memory/L4.Prefetch.cs
index 0a96cb6a..fc5d8f12 100644
--- a/StgSharp.Common/HighPerformance/Memory/L4.Prefetch.cs
+++ b/StgSharp.Common/HighPerformance/Memory/L4.Prefetch.cs
@@ -2,8 +2,8 @@
// -----------------------------------------------------------------------
// file="L4.Prefetch"
// Project: StgSharp
-// AuthorGroup: Nitload
-// Copyright (c) Nitload. All rights reserved.
+// AuthorGroup: Nitload Space
+// Copyright (c) Nitload Space. 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
@@ -25,18 +25,27 @@
//
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
+using System.ComponentModel;
+
namespace StgSharp.HighPerformance.Memory
{
public unsafe partial class L4
{
+ public const int MaxActivateCacheLineCount = 1024;
+
private partial void Prefetch()
{
if (PrefetchPredict is null) {
return;
}
+ if (_activeCount > MaxActivateCacheLineCount) {
+ throw new OverflowException("Too many activated cache line in external reference.");
+ }
Span span = new(_prediction, PredictionCount);
- int actualCount = PrefetchPredict.Predict(span);
+ if (!(PrefetchPredict.Predict(span, out int actualCount) && actualCount > 0)) {
+ return;
+ }
int missIndex = 0;
AgeAll();
for (int i = 0; i < actualCount; i++)
@@ -61,21 +70,31 @@ namespace StgSharp.HighPerformance.Memory
continue;
}
- // TODO 未经初始化的_idMux可能会导致TryGetEmptyLine失败,导致无法预取,最好添加末尾指针计数
- if (!TryGetEmptyLine(out int index))
+ int retryCount = 0, index, remain = missIndex - i;
+ const int maxRetry = 1024;
+ while (!TryGetEmptyLine(out index))
{
- throw new OverflowException("L4 has no empty cache line.");
+ missIndex = Evict(missIndex);
+ retryCount++;
+ if (retryCount > maxRetry) {
+ throw new OverflowException($"Failed to evict cache line after {maxRetry} retries.");
+ }
}
CacheLineHead* head = &_head[index];
+ head->_id = index;
+ head->_origin = address;
+ head->_profile = handle.MapPolicy;
+ head->_refCount = 0;
+ head->_address = (nuint)(&_data[index]);
// pre fetch them here
- _ = PrefetchPredict.Prefetch(head->_origin, head->_profile, head->_address);
+ PrefetchPredict.Prefetch(head->_origin, head->_profile, new Span((byte*)head->_address, Unsafe.SizeOf()));
+ _ = _map.TryAddOrSet(address, (nuint)head, out _);
}
+ _ = Interlocked.Add(ref _aheadCount, actualCount);
}
- private partial bool TestHit(
- nuint origin
- )
+ private partial bool TestHit(nuint origin)
{
if (_map.TryGet(origin, out nuint handle))
{
diff --git a/StgSharp.Common/HighPerformance/Memory/L4.cs b/StgSharp.Common/HighPerformance/Memory/L4.cs
index 5b80839a..5d1db6e0 100644
--- a/StgSharp.Common/HighPerformance/Memory/L4.cs
+++ b/StgSharp.Common/HighPerformance/Memory/L4.cs
@@ -2,8 +2,8 @@
// -----------------------------------------------------------------------
// file="L4"
// Project: StgSharp
-// AuthorGroup: Nitload
-// Copyright (c) Nitload. All rights reserved.
+// AuthorGroup: Nitload Space
+// Copyright (c) Nitload Space. 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
@@ -108,31 +108,24 @@ namespace StgSharp.HighPerformance.Memory
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public CacheLine Map(
- nuint origin
- )
+ public CacheLine Map(nuint origin)
{
if (_aheadCount < PredictionLeastAhead)
{
- while (true)
+ if (Interlocked.CompareExchange(ref _prefetching, 1, 0) == 0)
{
- if (Interlocked.CompareExchange(ref _prefetching, 1, 0) == 0)
+ try
{
- try
+ if (_aheadCount < PredictionLeastAhead)
{
- if (_aheadCount < PredictionLeastAhead)
- {
- // do prefetch in work load now, sync
- Prefetch();
- break;
- }
- }
- finally
- {
- _prefetching = 0;
+ // do prefetch in work load now, sync
+ Prefetch();
}
}
- Thread.Sleep(0);
+ finally
+ {
+ _prefetching = 0;
+ }
}
}
while (true)
@@ -145,6 +138,7 @@ namespace StgSharp.HighPerformance.Memory
{
(*_eviction)[entry->_id] = 0;
_ = Interlocked.Increment(ref _activeCount);
+ _ = Interlocked.Decrement(ref _aheadCount);
return new CacheLine(entry->_address, ref _activeCount, ref entry->_refCount);
} else
{
@@ -157,9 +151,7 @@ namespace StgSharp.HighPerformance.Memory
private partial void Prefetch();
- private partial bool TestHit(
- nuint origin
- );
+ private partial bool TestHit(nuint origin);
public ref struct CacheLine : IDisposable
{
@@ -168,11 +160,7 @@ namespace StgSharp.HighPerformance.Memory
private ref int _refCount;
private nuint _handle;
- internal CacheLine(
- nuint handle,
- ref int activeCount,
- ref int cacheRefCount
- )
+ internal CacheLine(nuint handle, ref int activeCount, ref int cacheRefCount)
{
_handle = handle;
_refCount = ref cacheRefCount;