110 lines
3.0 KiB
C#
110 lines
3.0 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 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|