Files
stgsharp/src/Nitload.Common/HighPerformance/Memory/L4.PredictorQueue.cs
T

146 lines
3.8 KiB
C#

// -----------------------------------------------------------------------------
// file="L4.PredictorQueue"
// Project: StgSharp
// Copyright (c) Nitload.
// SPDX-License-Identifier: MIT
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nitload.Common.HighPerformance.Memory
{
public partial class L4
{
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 bool MoveNextPredictor()
{
int cur = Interlocked.Increment(ref _predict);
return cur < _enter;
}
internal void RegistPredictor(
IL4Predictor predictor
)
{
if (predictor is null) {
return;
}
SpinWait sp = new();
wait_for_spare:
WaitForSpare();
while (Interlocked.CompareExchange(ref _queue_sync, 1, 0) != 0) {
sp.SpinOnce();
}
if (_enter - _consume >= PredictorRingCapacity)
{
_ = Interlocked.Exchange(ref _queue_sync, 0);
goto wait_for_spare;
}
try
{
unchecked
{
byte idx = (byte)_enter;
_enter++;
_ring[idx] = predictor;
}
}
finally
{
_ = Interlocked.Exchange(ref _queue_sync, 0);
}
}
internal bool TryGetCurrentPredictor(
out IL4Predictor predictor
)
{
int cur = _predict;
if (cur >= _enter)
{
predictor = default!;
return false;
}
unchecked
{
predictor = _ring[(byte)cur];
return true;
}
}
private void WaitForSpare()
{
int spin_count = 0;
while (_enter - _consume >= PredictorRingCapacity)
{
switch (spin_count)
{
case < 1024:
spin_count++;
break;
case < 65536:
spin_count++;
Thread.SpinWait(1);
break;
default:
Thread.Sleep(1);
break;
}
}
}
}
}