fix sever L4 errors

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