perf(headless): establish K4 resource telemetry
This commit is contained in:
parent
827a039760
commit
cb512fd091
5 changed files with 662 additions and 4 deletions
|
|
@ -77,6 +77,158 @@ public sealed class HeadlessProcessSchedulerTests
|
|||
scheduler.CaptureSnapshot().CatchUpCollapseCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SchedulerMeasuresDeadlineLatenessWithoutAllocatingPerTurn()
|
||||
{
|
||||
var time = new ManualTimeProvider();
|
||||
var operations = new FixtureSessionOperations();
|
||||
using HeadlessSessionHost first =
|
||||
CreateSession("late-first", time, operations);
|
||||
using HeadlessSessionHost second =
|
||||
CreateSession("late-second", time, operations);
|
||||
Assert.Equal(
|
||||
RuntimeSessionStartStatus.Connected,
|
||||
first.Start().Status);
|
||||
Assert.Equal(
|
||||
RuntimeSessionStartStatus.Connected,
|
||||
second.Start().Status);
|
||||
var scheduler = new HeadlessProcessScheduler(
|
||||
[first, second],
|
||||
time);
|
||||
|
||||
time.Advance(TimeSpan.FromMilliseconds(20));
|
||||
Assert.True(scheduler.DispatchDue(time.GetTimestamp()));
|
||||
|
||||
HeadlessSchedulerSnapshot snapshot =
|
||||
scheduler.CaptureSnapshot();
|
||||
Assert.Equal(2L, snapshot.LateDeadlineCount);
|
||||
Assert.Equal(5d, snapshot.MeanLatenessMilliseconds);
|
||||
Assert.Equal(5d, snapshot.MaximumLatenessMilliseconds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessObservationUsesOneAbsoluteDeadlineAndCollapsesPauses()
|
||||
{
|
||||
var time = new ManualTimeProvider();
|
||||
var operations = new FixtureSessionOperations();
|
||||
using HeadlessSessionHost session =
|
||||
CreateSession("observation", time, operations);
|
||||
Assert.Equal(
|
||||
RuntimeSessionStartStatus.Connected,
|
||||
session.Start().Status);
|
||||
int observationCount = 0;
|
||||
var scheduler = new HeadlessProcessScheduler(
|
||||
[session],
|
||||
time,
|
||||
observation: _ => observationCount++,
|
||||
observationPeriod: TimeSpan.FromSeconds(1));
|
||||
|
||||
time.Advance(TimeSpan.FromMilliseconds(999));
|
||||
Assert.False(
|
||||
scheduler.DispatchObservationDue(time.GetTimestamp()));
|
||||
time.Advance(TimeSpan.FromMilliseconds(1));
|
||||
Assert.True(
|
||||
scheduler.DispatchObservationDue(time.GetTimestamp()));
|
||||
Assert.False(
|
||||
scheduler.DispatchObservationDue(time.GetTimestamp()));
|
||||
time.Advance(TimeSpan.FromMilliseconds(2500));
|
||||
Assert.True(
|
||||
scheduler.DispatchObservationDue(time.GetTimestamp()));
|
||||
Assert.False(
|
||||
scheduler.DispatchObservationDue(time.GetTimestamp()));
|
||||
Assert.Equal(2, observationCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SessionStartupRebaseExcludesSequentialConnectTime()
|
||||
{
|
||||
var time = new ManualTimeProvider();
|
||||
var operations = new FixtureSessionOperations();
|
||||
using HeadlessSessionHost first =
|
||||
CreateSession("rebase-first", time, operations);
|
||||
using HeadlessSessionHost second =
|
||||
CreateSession("rebase-second", time, operations);
|
||||
var scheduler = new HeadlessProcessScheduler(
|
||||
[first, second],
|
||||
time);
|
||||
|
||||
time.Advance(TimeSpan.FromSeconds(4));
|
||||
Assert.Equal(
|
||||
RuntimeSessionStartStatus.Connected,
|
||||
first.Start().Status);
|
||||
time.Advance(TimeSpan.FromSeconds(6));
|
||||
Assert.Equal(
|
||||
RuntimeSessionStartStatus.Connected,
|
||||
second.Start().Status);
|
||||
scheduler.RebaseDeadlinesAfterSessionStart();
|
||||
|
||||
Assert.False(scheduler.DispatchDue(time.GetTimestamp()));
|
||||
time.Advance(TimeSpan.FromMilliseconds(15));
|
||||
Assert.True(scheduler.DispatchDue(time.GetTimestamp()));
|
||||
HeadlessSchedulerSnapshot snapshot =
|
||||
scheduler.CaptureSnapshot();
|
||||
Assert.Equal(2L, snapshot.TurnCount);
|
||||
Assert.Equal(0L, snapshot.LateDeadlineCount);
|
||||
Assert.Equal(0L, snapshot.CatchUpCollapseCount);
|
||||
Assert.Throws<InvalidOperationException>(
|
||||
scheduler.RebaseDeadlinesAfterSessionStart);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0, 0)]
|
||||
[InlineData(1, TimeSpan.TicksPerMillisecond)]
|
||||
[InlineData(
|
||||
TimeSpan.TicksPerMillisecond - 1,
|
||||
TimeSpan.TicksPerMillisecond)]
|
||||
[InlineData(
|
||||
TimeSpan.TicksPerMillisecond,
|
||||
TimeSpan.TicksPerMillisecond)]
|
||||
[InlineData(
|
||||
TimeSpan.TicksPerMillisecond + 1,
|
||||
TimeSpan.TicksPerMillisecond + 1)]
|
||||
public void SchedulerNeverBusyLoopsOnSubMillisecondTimerDelay(
|
||||
long sourceTicks,
|
||||
long expectedTicks)
|
||||
{
|
||||
TimeSpan normalized =
|
||||
HeadlessProcessScheduler.NormalizeTimerDelay(
|
||||
TimeSpan.FromTicks(sourceTicks));
|
||||
|
||||
Assert.Equal(expectedTicks, normalized.Ticks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SystemTimerCadenceDoesNotBusyLoopBetweenTurns()
|
||||
{
|
||||
var operations = new FixtureSessionOperations();
|
||||
using HeadlessSessionHost session =
|
||||
CreateSession(
|
||||
"system-timer",
|
||||
TimeProvider.System,
|
||||
operations);
|
||||
Assert.Equal(
|
||||
RuntimeSessionStartStatus.Connected,
|
||||
session.Start().Status);
|
||||
var scheduler = new HeadlessProcessScheduler([session]);
|
||||
scheduler.RebaseDeadlinesAfterSessionStart();
|
||||
using var cancellation =
|
||||
new CancellationTokenSource(TimeSpan.FromMilliseconds(250));
|
||||
|
||||
try
|
||||
{
|
||||
await scheduler.RunAsync(cancellation.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
when (cancellation.IsCancellationRequested)
|
||||
{
|
||||
}
|
||||
|
||||
HeadlessSchedulerSnapshot snapshot =
|
||||
scheduler.CaptureSnapshot();
|
||||
Assert.InRange(snapshot.WaitCount, 1L, 1000L);
|
||||
Assert.True(snapshot.TurnCount > 0L);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReconnectQuiescenceIsAMonotonicDeadlineNotABlockingWait()
|
||||
{
|
||||
|
|
@ -185,6 +337,25 @@ public sealed class HeadlessProcessSchedulerTests
|
|||
"password",
|
||||
diagnostics.ToString(),
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"\"kind\":\"resources\"",
|
||||
diagnostics.ToString(),
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"\"configuredCount\":2",
|
||||
diagnostics.ToString(),
|
||||
StringComparison.Ordinal);
|
||||
|
||||
host.Dispose();
|
||||
|
||||
Assert.Contains(
|
||||
"\"state\":\"disposed\"",
|
||||
diagnostics.ToString(),
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"\"convergedRuntimeCount\":2",
|
||||
diagnostics.ToString(),
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue