Reserve icon loading capacity for live demand

Limit speculative icon work to workerCount - 1 consumers so one existing worker slot remains available for a newly realized IconBox. At two workers this deliberately trades half of speculative concurrency for the live-demand guarantee; a single-worker configuration still processes speculative work normally.

Report the configured and retained worker capacity alongside reservation deferrals, and cover the two-worker, four-worker, and single-worker contracts.
This commit is contained in:
Jiří Polášek
2026-08-12 05:30:13 +02:00
parent 4a0f490aec
commit 81a0a64a57
7 changed files with 338 additions and 3 deletions

View File

@@ -247,6 +247,22 @@ internal static class IconLoadDiagnostics
return new DemandedIdleCapacityMeasurement(session, startedAt);
}
internal static SpeculativeDispatchDeferralMeasurement? BeginSpeculativeDispatchDeferral(
int speculativeQueueDepth,
int workerCount,
int reservedWorkerSlots)
{
var session = Volatile.Read(ref _activeSession);
if (session is null)
{
return null;
}
var startedAt = Stopwatch.GetTimestamp();
session.RecordSpeculativeDispatchDeferralStarted(speculativeQueueDepth, workerCount, reservedWorkerSlots);
return new SpeculativeDispatchDeferralMeasurement(session, startedAt, workerCount);
}
private static IconLoadInputKind ClassifyInput(string? iconString, bool hasStream)
{
if (!string.IsNullOrEmpty(iconString))
@@ -415,4 +431,40 @@ internal static class IconLoadDiagnostics
}
}
}
internal sealed class SpeculativeDispatchDeferralMeasurement
{
private readonly IconLoadDiagnosticsSession _session;
private readonly long _startedAt;
private readonly int _workerCount;
private int _completed;
public SpeculativeDispatchDeferralMeasurement(
IconLoadDiagnosticsSession session,
long startedAt,
int workerCount)
{
_session = session;
_startedAt = startedAt;
_workerCount = workerCount;
}
public bool IsForActiveSession => ReferenceEquals(_session, Volatile.Read(ref _activeSession));
public void Observe(int speculativeQueueDepth, int reservedWorkerSlots)
{
_session.RecordSpeculativeDispatchDeferralObserved(
speculativeQueueDepth,
_workerCount,
reservedWorkerSlots);
}
public void Complete()
{
if (Interlocked.Exchange(ref _completed, 1) == 0)
{
_session.RecordSpeculativeDispatchDeferralCompleted(Stopwatch.GetTimestamp() - _startedAt);
}
}
}
}

View File

@@ -66,6 +66,7 @@ internal sealed class IconLoadDiagnosticsSession
private readonly DiagnosticHistogram _workerReadyToDemandedDispatchLatency = new();
private readonly DiagnosticHistogram _workerReadyToSpeculativeDispatchLatency = new();
private readonly DiagnosticHistogram _demandedIdleCapacityDuration = new();
private readonly DiagnosticHistogram _speculativeDispatchDeferralDuration = new();
private readonly InputKindMeasurements[] _inputKindMeasurements = CreateInputKindMeasurements();
private readonly ElementKindMeasurements[] _elementKindMeasurements = CreateElementKindMeasurements();
private readonly ConditionalWeakTable<Task<IconSource?>, IconLoadMeasurement> _loadsByTask = new();
@@ -142,6 +143,11 @@ internal sealed class IconLoadDiagnosticsSession
private long _currentDemandedIdleCapacityIntervals;
private long _maximumDemandedQueueDepthWithIdleCapacity;
private long _maximumAvailableWorkerSlotsWithDemandedWork;
private long _speculativeDispatchDeferralIntervalsStarted;
private long _currentSpeculativeDispatchDeferralIntervals;
private long _maximumSpeculativeQueueDepthDuringDeferral;
private long _maximumWorkerCountDuringSpeculativeDispatchDeferral;
private long _maximumReservedWorkerSlotsDuringDeferral;
private long _activeWorkers;
private long _maximumActiveWorkers;
private long _dispatcherEnqueuedDemanded;
@@ -315,6 +321,34 @@ internal sealed class IconLoadDiagnosticsSession
IconLoadEventSource.Log.DemandedIdleCapacityCompleted(Id, ToMicroseconds(elapsedTicks));
}
public void RecordSpeculativeDispatchDeferralStarted(
int speculativeQueueDepth,
int workerCount,
int reservedWorkerSlots)
{
Interlocked.Increment(ref _speculativeDispatchDeferralIntervalsStarted);
Interlocked.Increment(ref _currentSpeculativeDispatchDeferralIntervals);
RecordSpeculativeDispatchDeferralObserved(speculativeQueueDepth, workerCount, reservedWorkerSlots);
}
public void RecordSpeculativeDispatchDeferralObserved(
int speculativeQueueDepth,
int workerCount,
int reservedWorkerSlots)
{
UpdateMaximum(ref _maximumSpeculativeQueueDepthDuringDeferral, speculativeQueueDepth);
UpdateMaximum(ref _maximumWorkerCountDuringSpeculativeDispatchDeferral, workerCount);
UpdateMaximum(ref _maximumReservedWorkerSlotsDuringDeferral, reservedWorkerSlots);
}
public void RecordSpeculativeDispatchDeferralCompleted(long elapsedTicks)
{
var activeIntervals = Interlocked.Decrement(ref _currentSpeculativeDispatchDeferralIntervals);
Debug.Assert(activeIntervals >= 0, "A speculative-dispatch-deferral interval must start before it completes.");
_speculativeDispatchDeferralDuration.Record(elapsedTicks);
IconLoadEventSource.Log.SpeculativeDispatchDeferralCompleted(Id, ToMicroseconds(elapsedTicks));
}
public IconRequestMeasurement BeginRequest(IconRequestReason reason, double scale, IconRequestOrigin origin)
{
origin = origin.Normalize();
@@ -1590,6 +1624,34 @@ internal sealed class IconLoadDiagnosticsSession
Volatile.Read(ref _maximumAvailableWorkerSlotsWithDemandedWork),
" ");
_demandedIdleCapacityDuration.Append(builder, "Interval duration", " ");
builder.AppendLine(" Speculative dispatch deferred by the demand reserve");
builder.AppendLine(" Definition: a coordinator-state interval with speculative work queued, no demanded work queued, and a worker-ready slot deliberately retained for a future live request.");
AppendValue(
builder,
"Intervals started",
Volatile.Read(ref _speculativeDispatchDeferralIntervalsStarted),
" ");
AppendValue(
builder,
"Intervals active at stop",
Math.Max(0, Volatile.Read(ref _currentSpeculativeDispatchDeferralIntervals)),
" ");
AppendValue(
builder,
"Maximum speculative queue depth during an interval",
Volatile.Read(ref _maximumSpeculativeQueueDepthDuringDeferral),
" ");
AppendValue(
builder,
"Maximum configured worker count during an interval",
Volatile.Read(ref _maximumWorkerCountDuringSpeculativeDispatchDeferral),
" ");
AppendValue(
builder,
"Maximum worker-ready slots retained during an interval",
Volatile.Read(ref _maximumReservedWorkerSlotsDuringDeferral),
" ");
_speculativeDispatchDeferralDuration.Append(builder, "Interval duration", " ");
}
private void AppendLoadDemandMeasurements(StringBuilder builder)

View File

@@ -403,6 +403,17 @@ internal sealed partial class IconLoadEventSource : EventSource
WriteEvent(37, sessionId, elapsedMicroseconds);
}
[Event(38, Level = EventLevel.Informational)]
public void SpeculativeDispatchDeferralCompleted(long sessionId, long elapsedMicroseconds)
{
if (!IsEnabled())
{
return;
}
WriteEvent(38, sessionId, elapsedMicroseconds);
}
// These exact overloads intentionally shadow EventSource.WriteEvent(params object?[]).
// The params overload allocates an array and boxes values while ETW is enabled, which
// would make the icon diagnostics measurably perturb the paths they are observing.

View File

@@ -27,6 +27,7 @@ internal sealed class IconLoadQueue
private readonly Queue<IconLoadDiagnostics.SchedulerCommandMeasurement?> _availableWorkerMeasurements = new();
private readonly TaskCompletionSource<bool> _schedulerCompletion = new(TaskCreationOptions.RunContinuationsAsynchronously);
private readonly Thread _schedulerThread;
private readonly int _workerSlotsReservedForDemand;
private readonly int _workerCount;
private TaskCompletionSource<bool>? _faultedEnqueuePublishersDrained;
@@ -41,11 +42,18 @@ internal sealed class IconLoadQueue
private int _availableWorkerSlots;
private bool _completionRequested;
private IconLoadDiagnostics.DemandedIdleCapacityMeasurement? _demandedIdleCapacityMeasurement;
private IconLoadDiagnostics.SpeculativeDispatchDeferralMeasurement? _speculativeDispatchDeferralMeasurement;
public IconLoadQueue(int workerCount)
{
ArgumentOutOfRangeException.ThrowIfLessThan(workerCount, 1);
_workerCount = workerCount;
// Keep one consumer waiting for live demand while only speculative work is
// queued. At two workers this deliberately halves speculative concurrency:
// reserving no slot would let non-preemptible speculative loads occupy all
// capacity. A single-worker queue must still make progress.
_workerSlotsReservedForDemand = workerCount > 1 ? 1 : 0;
_readyWork = Channel.CreateUnbounded<Operation>(new UnboundedChannelOptions
{
SingleReader = false,
@@ -253,9 +261,12 @@ internal sealed class IconLoadQueue
command.Measurement?.Processed();
Apply(command);
if (command.Measurement is not null || _demandedIdleCapacityMeasurement is not null)
if (command.Measurement is not null
|| _demandedIdleCapacityMeasurement is not null
|| _speculativeDispatchDeferralMeasurement is not null)
{
UpdateDemandedIdleCapacityMeasurement();
UpdateSpeculativeDispatchDeferralMeasurement();
}
commandBeingProcessed = null;
@@ -268,6 +279,10 @@ internal sealed class IconLoadQueue
UpdateDemandedIdleCapacityMeasurement();
}
// Dispatch can consume the last non-reserved slot and begin a
// deferral interval without another command changing state.
UpdateSpeculativeDispatchDeferralMeasurement();
if (measureBatch)
{
wakeMeasurement!.BatchCompleted(
@@ -293,6 +308,7 @@ internal sealed class IconLoadQueue
try
{
CompleteDemandedIdleCapacityMeasurement();
CompleteSpeculativeDispatchDeferralMeasurement();
}
catch (Exception ex)
{
@@ -421,7 +437,7 @@ internal sealed class IconLoadQueue
private int DispatchAvailableWorkers()
{
var dispatchedWorkItemCount = 0;
while (_availableWorkerSlots > 0 && RemoveNext() is { } item)
while (CanDispatchNextWorkItem() && RemoveNext() is { } item)
{
try
{
@@ -448,6 +464,24 @@ internal sealed class IconLoadQueue
return dispatchedWorkItemCount;
}
private bool CanDispatchNextWorkItem()
{
if (_availableWorkerSlots == 0)
{
return false;
}
if (_demandedHigh.Count != 0 || _demandedLow.Count != 0)
{
return true;
}
// Speculative work uses at most workerCount - 1 consumers. Because a
// consumer publishes WorkerReady only after its previous load completes,
// retaining this slot also bounds the number of active speculative loads.
return _availableWorkerSlots > _workerSlotsReservedForDemand;
}
private void UpdateDemandedIdleCapacityMeasurement()
{
var hasDemandedWorkWithIdleCapacity = _availableWorkerSlots > 0
@@ -479,6 +513,43 @@ internal sealed class IconLoadQueue
_demandedIdleCapacityMeasurement = null;
}
private void UpdateSpeculativeDispatchDeferralMeasurement()
{
var speculativeQueueDepth = _speculativeHigh.Count + _speculativeLow.Count;
var reserveIsDeferringWork = _workerSlotsReservedForDemand > 0
&& _availableWorkerSlots > 0
&& _availableWorkerSlots <= _workerSlotsReservedForDemand
&& _demandedHigh.Count == 0
&& _demandedLow.Count == 0
&& speculativeQueueDepth > 0;
if (!reserveIsDeferringWork)
{
CompleteSpeculativeDispatchDeferralMeasurement();
return;
}
if (_speculativeDispatchDeferralMeasurement is null
|| !_speculativeDispatchDeferralMeasurement.IsForActiveSession)
{
CompleteSpeculativeDispatchDeferralMeasurement();
_speculativeDispatchDeferralMeasurement = IconLoadDiagnostics.BeginSpeculativeDispatchDeferral(
speculativeQueueDepth,
_workerCount,
_availableWorkerSlots);
return;
}
_speculativeDispatchDeferralMeasurement.Observe(
speculativeQueueDepth,
_availableWorkerSlots);
}
private void CompleteSpeculativeDispatchDeferralMeasurement()
{
_speculativeDispatchDeferralMeasurement?.Complete();
_speculativeDispatchDeferralMeasurement = null;
}
// Strict order by design: speculative work may starve while demanded work keeps
// arriving, since no live request is waiting on it.
private WorkItem? RemoveNext()

View File

@@ -279,6 +279,58 @@ public class IconLoadDiagnosticsTests
StringAssert.Contains(report.Text, " Interval duration: count=1");
}
[TestMethod]
[Timeout(5_000)]
public async Task SchedulerReportCapturesSpeculativeDemandReserve()
{
IconLoadDiagnostics.Start();
var queue = new IconLoadQueue(workerCount: 4);
var speculativeWork = new TestOperation();
var demandedWork = new TestOperation();
var speculativeDemand = IconLoadDemand.CreateDemanded();
speculativeDemand.RemoveRequester();
Assert.IsTrue(queue.TryEnqueue(
speculativeWork,
IconLoadPriority.Low,
speculativeDemand,
out _));
var reservedDequeue = queue.DequeueAsync().AsTask();
Assert.IsTrue(queue.TryEnqueue(
demandedWork,
IconLoadPriority.Low,
IconLoadDemand.CreateDemanded(),
out _));
Assert.AreSame(demandedWork, await reservedDequeue);
var firstReadyWorker = queue.DequeueAsync().AsTask();
var secondReadyWorker = queue.DequeueAsync().AsTask();
var speculativeDequeue = await Task.WhenAny(firstReadyWorker, secondReadyWorker);
Assert.AreSame(speculativeWork, await speculativeDequeue);
queue.Complete();
var remainingDequeue = ReferenceEquals(speculativeDequeue, firstReadyWorker)
? secondReadyWorker
: firstReadyWorker;
Assert.IsNull(await remainingDequeue);
await queue.Completion;
var report = IconLoadDiagnostics.StopAndCreateReport();
Assert.IsNotNull(report);
var reserveBlock =
$" Speculative dispatch deferred by the demand reserve{Environment.NewLine}" +
$" Definition: a coordinator-state interval with speculative work queued, no demanded work queued, and a worker-ready slot deliberately retained for a future live request.{Environment.NewLine}" +
$" Intervals started: 2{Environment.NewLine}" +
$" Intervals active at stop: 0{Environment.NewLine}" +
$" Maximum speculative queue depth during an interval: 1{Environment.NewLine}" +
$" Maximum configured worker count during an interval: 4{Environment.NewLine}" +
$" Maximum worker-ready slots retained during an interval: 1{Environment.NewLine}" +
$" Interval duration: count=2";
StringAssert.Contains(report.Text, reserveBlock);
}
[TestMethod]
public void SchedulerReportSeparatesEmptyCoalescedBatchWakeLatency()
{

View File

@@ -51,8 +51,9 @@ public sealed class IconLoadEventSourceTests
log.DispatcherUiSliceCompleted(11, 14, 52, 53, isDemanded: true, 54);
log.DispatcherAsyncSuspensionCompleted(11, 14, 55, isDemanded: false, 56);
log.UiResponsivenessProbeCompleted(11, 57);
log.SpeculativeDispatchDeferralCompleted(11, 69);
Assert.AreEqual(30, listener.Events.Count);
Assert.AreEqual(31, listener.Events.Count);
Assert.IsFalse(listener.Events.Any(e => e.EventId == 0), listener.GetEventSourceErrors());
CollectionAssert.AreEqual(
@@ -88,6 +89,9 @@ public sealed class IconLoadEventSourceTests
CollectionAssert.AreEqual(
new object?[] { 11L, 14L, 55, false, 56L },
listener.GetEvent(36).Payload!.ToArray());
CollectionAssert.AreEqual(
new object?[] { 11L, 69L },
listener.GetEvent(38).Payload!.ToArray());
}
private sealed class CollectingEventListener : EventListener

View File

@@ -145,6 +145,89 @@ public class IconLoadQueueTests
await queue.Completion;
}
[TestMethod]
[DataRow(2)]
[DataRow(4)]
[Timeout(5_000)]
public async Task SpeculativeWorkLeavesOneWorkerAvailableForDemand(int workerCount)
{
var queue = new IconLoadQueue(workerCount);
var releaseSpeculativeWork = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
var speculativeCapacityFilled = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
var demandedWorkStarted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
var speculativeStarts = 0;
var workers = new Task[workerCount];
for (var i = 0; i < workers.Length; i++)
{
workers[i] = RunWorkerAsync(queue);
}
try
{
for (var i = 0; i < workerCount; i++)
{
var speculativeDemand = IconLoadDemand.CreateDemanded();
speculativeDemand.RemoveRequester();
Assert.IsTrue(queue.TryEnqueue(
new TestOperation(async () =>
{
if (Interlocked.Increment(ref speculativeStarts) == workerCount - 1)
{
speculativeCapacityFilled.TrySetResult(true);
}
await releaseSpeculativeWork.Task;
}),
IconLoadPriority.Low,
speculativeDemand,
out _));
}
await speculativeCapacityFilled.Task.WaitAsync(TimeSpan.FromSeconds(1));
Assert.IsTrue(queue.TryEnqueue(
new TestOperation(() =>
{
demandedWorkStarted.TrySetResult(true);
return Task.CompletedTask;
}),
IconLoadPriority.Low,
IconLoadDemand.CreateDemanded(),
out _));
await demandedWorkStarted.Task.WaitAsync(TimeSpan.FromSeconds(1));
Assert.AreEqual(workerCount - 1, Volatile.Read(ref speculativeStarts));
}
finally
{
queue.Complete();
releaseSpeculativeWork.TrySetResult(true);
await Task.WhenAll(workers);
await queue.Completion;
}
Assert.AreEqual(workerCount, speculativeStarts);
}
[TestMethod]
[Timeout(5_000)]
public async Task SingleWorkerStillProcessesSpeculativeWork()
{
var queue = new IconLoadQueue(workerCount: 1);
var work = new TestOperation();
var speculativeDemand = IconLoadDemand.CreateDemanded();
speculativeDemand.RemoveRequester();
var dequeue = queue.DequeueAsync().AsTask();
Assert.IsTrue(queue.TryEnqueue(work, IconLoadPriority.Low, speculativeDemand, out _));
Assert.AreSame(work, await dequeue);
queue.Complete();
Assert.IsNull(await queue.DequeueAsync());
await queue.Completion;
}
[TestMethod]
[Timeout(10_000)]
public async Task DemandChurnDuringDequeueRunsEveryWorkExactlyOnce()