From 98d711a3caab9d7ab5a8611e85c63a3488e72a2b Mon Sep 17 00:00:00 2001 From: Nitload Date: Tue, 17 Mar 2026 00:31:52 +0800 Subject: [PATCH] fix sever L4 errors --- .../HighPerformance/Memory/L4.Evict.cs | 31 +++++++------ .../HighPerformance/Memory/L4.Predict.cs | 45 +++++++++++++++++-- .../HighPerformance/Memory/L4.Prefetch.cs | 39 +++++++++++----- StgSharp.Common/HighPerformance/Memory/L4.cs | 42 +++++++---------- 4 files changed, 104 insertions(+), 53 deletions(-) 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;