From 91cf6a43cdcb62b2315d61e3949d3562d0074d99 Mon Sep 17 00:00:00 2001 From: Youmu Liu <105042599+Nitload-NSI@users.noreply.github.com> Date: Thu, 15 Oct 2026 18:15:38 +0800 Subject: [PATCH] Add L4 predictor queue skeleton --- .../Memory/L4.PredictorQueue.cs | 101 +++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/src/Nitload.Common/HighPerformance/Memory/L4.PredictorQueue.cs b/src/Nitload.Common/HighPerformance/Memory/L4.PredictorQueue.cs index a9e83119..a01ef41a 100644 --- a/src/Nitload.Common/HighPerformance/Memory/L4.PredictorQueue.cs +++ b/src/Nitload.Common/HighPerformance/Memory/L4.PredictorQueue.cs @@ -1,4 +1,11 @@ -using System; +// ----------------------------------------------------------------------------- +// file="L4.PredictorQueue" +// Project: StgSharp +// Copyright (c) Nitload. +// SPDX-License-Identifier: MIT +// ----------------------------------------------------------------------------- + +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +13,97 @@ using System.Threading.Tasks; namespace Nitload.Common.HighPerformance.Memory { - public class L4 + public partial class L4 { + + private readonly IL4Predictor[] _ring = new IL4Predictor[256]; + private volatile int _consume; + private volatile int _enter; + private volatile int _predict; + + private int _queue_sync; + + internal void DropPredictor( + IL4Predictor predictor + ) + { + if (predictor is null) { + return; + } + SpinWait sp = new(); + while (Interlocked.CompareExchange(ref _queue_sync, 1, 0) != 0) { + sp.SpinOnce(); + } + + try + { + unchecked + { + for (int i = _consume; i < _predict; i++) + { + byte idx = (byte)i; + if (ReferenceEquals(predictor, _ring[idx])) + { + int end = _predict; + for (int move = i; move < end - 1; move++) + { + _ring[(byte)move] = _ring[(byte)(move + 1)]; + } + _ring[(byte)(end - 1)] = default!; + _predict = end - 1; + return; + } + } + } + } + finally + { + Interlocked.Exchange(ref _queue_sync, 0); + } + } + + internal void RegistPredictor( + IL4Predictor predictor + ) + { + if (predictor is null) { + return; + } + SpinWait sp = new(); + while (Interlocked.CompareExchange(ref _queue_sync, 1, 0) != 0) { + sp.SpinOnce(); + } + + WaitForSpare(); + + _consume++; + + byte idx = (byte)_consume; + _ring[idx] = predictor; + } + + private void WaitForSpare() + { + int spin_count = 0; + + // wait until the queue has space + while (_enter - _consume >= 256) + { + switch (spin_count) + { + case < 1024: + spin_count++; + break; + case < 65536: + spin_count++; + Thread.SpinWait(1); + break; + default: + Thread.Sleep(1); + break; + } + } + } + } }