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
// 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
}
}
/// <summary>
///
/// </summary>
/// <param name="count">
///
/// </param>
/// <returns>
/// Count of lines not evicted
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private unsafe void Evict(
int count = 1
)
private unsafe int Evict(int count = 1)
{
int remain = count;
Vector128<byte> 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>((byte*)head->_address, Unsafe.SizeOf<CacheLineData>()));
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;
}
}
@@ -36,11 +36,50 @@ namespace StgSharp.HighPerformance.Memory
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"
// 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<CacheLinePrediction> 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>((byte*)head->_address, Unsafe.SizeOf<CacheLineData>()));
_ = _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))
{
+15 -27
View File
@@ -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;