Skip to content

Commit e86b7d7

Browse files
authored
Feat: add governance execution and version resolution benchmarks (#81)
2 parents f9a4dc0 + bff6015 commit e86b7d7

5 files changed

Lines changed: 442 additions & 0 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using BenchmarkDotNet.Attributes;
2+
using ModularityKit.Mutator.Governance.Abstractions.Execution.Model;
3+
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Model;
4+
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Strategies;
5+
using ModularityKit.Mutator.Benchmarks.Governance.Execution.Support;
6+
7+
namespace ModularityKit.Mutator.Benchmarks.Governance.Execution;
8+
9+
/// <summary>
10+
/// Benchmarks governed execution orchestration paths in the governance runtime.
11+
/// </summary>
12+
[BenchmarkCategory("Governance")]
13+
[MemoryDiagnoser]
14+
[InProcess]
15+
public class GovernedExecutionOrchestrationBenchmarks
16+
{
17+
private const string ApprovedRequestId = "governance-execution-approved";
18+
private const string StaleRequestId = "governance-execution-stale";
19+
private const string RevalidateRequestId = "governance-execution-revalidate";
20+
21+
private GovernedExecutionBenchmarkSupport.GovernedExecutionBenchmarkFixture _approvedFixture = null!;
22+
private GovernedExecutionBenchmarkSupport.GovernedExecutionBenchmarkFixture _staleFixture = null!;
23+
private GovernedExecutionBenchmarkSupport.GovernedExecutionBenchmarkFixture _revalidateFixture = null!;
24+
25+
/// <summary>
26+
/// Prepares fresh fixtures for each benchmark iteration.
27+
/// </summary>
28+
[IterationSetup]
29+
public void Setup()
30+
{
31+
_approvedFixture = GovernedExecutionBenchmarkSupport.CreateFixture(
32+
ApprovedRequestId,
33+
currentStateVersion: "v10",
34+
nextStateVersion: "v11");
35+
36+
_staleFixture = GovernedExecutionBenchmarkSupport.CreateFixture(
37+
StaleRequestId,
38+
currentStateVersion: "v15",
39+
nextStateVersion: "v16");
40+
41+
_revalidateFixture = GovernedExecutionBenchmarkSupport.CreateFixture(
42+
RevalidateRequestId,
43+
currentStateVersion: "v15",
44+
nextStateVersion: "v16");
45+
}
46+
47+
/// <summary>
48+
/// Measures an approved request executing through governed orchestration with matching state version.
49+
/// </summary>
50+
[Benchmark(Baseline = true)]
51+
public async Task ExecuteApproved_MatchingVersion()
52+
{
53+
var result = await _approvedFixture.ExecutionManager.ExecuteApproved(
54+
_approvedFixture.Request.RequestId,
55+
_approvedFixture.Mutation,
56+
_approvedFixture.State,
57+
governanceContext: _approvedFixture.Mutation.Context,
58+
strategy: VersionedRequestResolutionStrategy.RejectStale).ConfigureAwait(false);
59+
60+
GC.KeepAlive(result);
61+
}
62+
63+
/// <summary>
64+
/// Measures an approved request being rejected as stale before the core engine executes.
65+
/// </summary>
66+
[Benchmark]
67+
public async Task ExecuteApproved_RejectStale()
68+
{
69+
var result = await _staleFixture.ExecutionManager.ExecuteApproved(
70+
_staleFixture.Request.RequestId,
71+
_staleFixture.Mutation,
72+
_staleFixture.State,
73+
governanceContext: _staleFixture.Mutation.Context,
74+
strategy: VersionedRequestResolutionStrategy.RejectStale).ConfigureAwait(false);
75+
76+
GC.KeepAlive(result);
77+
}
78+
79+
/// <summary>
80+
/// Measures an approved request being revalidated against the latest state and then executed.
81+
/// </summary>
82+
[Benchmark]
83+
public async Task ExecuteApproved_RevalidateAndExecute()
84+
{
85+
var result = await _revalidateFixture.ExecutionManager.ExecuteApproved(
86+
_revalidateFixture.Request.RequestId,
87+
_revalidateFixture.Mutation,
88+
_revalidateFixture.State,
89+
governanceContext: _revalidateFixture.Mutation.Context,
90+
strategy: VersionedRequestResolutionStrategy.RevalidateOnLatestState).ConfigureAwait(false);
91+
92+
GC.KeepAlive(result);
93+
}
94+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using ModularityKit.Mutator.Abstractions.Changes;
2+
using ModularityKit.Mutator.Abstractions.Context;
3+
using ModularityKit.Mutator.Abstractions;
4+
using ModularityKit.Mutator.Abstractions.Engine;
5+
using ModularityKit.Mutator.Abstractions.Intent;
6+
using ModularityKit.Mutator.Abstractions.Policies;
7+
using ModularityKit.Mutator.Abstractions.Results;
8+
using ModularityKit.Mutator.Benchmarks.Engine;
9+
using ModularityKit.Mutator.Governance.Abstractions.Execution.Contracts;
10+
using ModularityKit.Mutator.Governance.Abstractions.Lifecycle.Model;
11+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
12+
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
13+
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Strategies;
14+
using ModularityKit.Mutator.Governance.Runtime.Execution.Orchestration;
15+
using ModularityKit.Mutator.Governance.Runtime.Resolution.Execution;
16+
using ModularityKit.Mutator.Governance.Runtime.Storage;
17+
18+
namespace ModularityKit.Mutator.Benchmarks.Governance.Execution.Support;
19+
20+
/// <summary>
21+
/// Builds repeatable governed execution benchmark fixtures.
22+
/// </summary>
23+
internal static class GovernedExecutionBenchmarkSupport
24+
{
25+
public const string StateId = "governance-benchmark:execution";
26+
27+
/// <summary>
28+
/// Creates a fresh execution fixture for a single scenario run.
29+
/// </summary>
30+
public static GovernedExecutionBenchmarkFixture CreateFixture(
31+
string requestId,
32+
string currentStateVersion,
33+
string nextStateVersion)
34+
{
35+
var engine = MutationEngineBenchmarkSupport.BuildEngine(MutationEngineOptions.Strict);
36+
var store = new InMemoryMutationRequestStore();
37+
var resolutionManager = new MutationRequestVersionResolutionManager(store, new MutationRequestVersionResolver());
38+
var executionManager = new GovernanceExecutionManager(store, resolutionManager, engine);
39+
var request = store.Create(CreateApprovedRequest<GovernedExecutionState, IncrementValueMutation>(requestId))
40+
.GetAwaiter()
41+
.GetResult();
42+
43+
return new GovernedExecutionBenchmarkFixture(
44+
ExecutionManager: executionManager,
45+
Request: request,
46+
State: new GovernedExecutionState(StateId, 42, currentStateVersion),
47+
Mutation: new IncrementValueMutation(
48+
MutationContext.User("operator", "Operator", "Execute governed request"),
49+
nextStateVersion));
50+
}
51+
52+
/// <summary>
53+
/// Creates the approved request used by governed execution benchmarks.
54+
/// </summary>
55+
private static MutationRequest CreateApprovedRequest<TState, TMutation>(string requestId)
56+
where TMutation : IMutation<TState>
57+
=> MutationRequestFactory.Approved<TState, TMutation>(
58+
stateId: StateId,
59+
intent: CreateIntent(),
60+
context: MutationContext.User("requester", "Requester", "Need governed execution"),
61+
expectedStateVersion: "v10")
62+
with
63+
{
64+
RequestId = requestId
65+
};
66+
67+
/// <summary>
68+
/// Creates the intent used by governed execution scenarios.
69+
/// </summary>
70+
private static MutationIntent CreateIntent()
71+
=> new()
72+
{
73+
OperationName = "ExecuteGovernedRequest",
74+
Category = "Governance",
75+
Description = "Execute a governed request through orchestration",
76+
RiskLevel = MutationRiskLevel.Low,
77+
IsReversible = true
78+
};
79+
80+
/// <summary>
81+
/// Minimal versioned state used by governed execution benchmarks.
82+
/// </summary>
83+
/// <param name="StateId">Stable state identifier.</param>
84+
/// <param name="Value">Benchmark counter value.</param>
85+
/// <param name="Version">Current state version.</param>
86+
internal sealed record GovernedExecutionState(string StateId, int Value, string Version) : IVersionedState;
87+
88+
/// <summary>
89+
/// Minimal mutation used to measure governed execution orchestration.
90+
/// </summary>
91+
internal sealed class IncrementValueMutation(MutationContext context, string nextVersion)
92+
: IMutation<GovernedExecutionState>
93+
{
94+
public MutationIntent Intent { get; } = new()
95+
{
96+
OperationName = "IncrementGovernedValue",
97+
Category = "Governance",
98+
Description = "Increment a governed benchmark value",
99+
RiskLevel = MutationRiskLevel.Low,
100+
IsReversible = true
101+
};
102+
103+
public MutationContext Context { get; } = context;
104+
105+
public MutationResult<GovernedExecutionState> Apply(GovernedExecutionState state)
106+
{
107+
var next = state with
108+
{
109+
Value = state.Value + 1,
110+
Version = nextVersion
111+
};
112+
113+
return MutationResult<GovernedExecutionState>.Success(
114+
next,
115+
ChangeSet.Single(StateChange.Modified(nameof(GovernedExecutionState.Value), state.Value, next.Value)));
116+
}
117+
118+
public ValidationResult Validate(GovernedExecutionState state)
119+
{
120+
return state.Value < 0
121+
? ValidationResult.WithError(nameof(GovernedExecutionState.Value), "Value must be non-negative.")
122+
: ValidationResult.Success();
123+
}
124+
125+
public MutationResult<GovernedExecutionState> Simulate(GovernedExecutionState state) => Apply(state);
126+
}
127+
128+
/// <summary>
129+
/// Shared execution fixture for a benchmark scenario.
130+
/// </summary>
131+
internal sealed record GovernedExecutionBenchmarkFixture(
132+
GovernanceExecutionManager ExecutionManager,
133+
MutationRequest Request,
134+
GovernedExecutionState State,
135+
IncrementValueMutation Mutation);
136+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using BenchmarkDotNet.Attributes;
2+
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Model;
3+
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Strategies;
4+
using ModularityKit.Mutator.Benchmarks.Governance.Resolution.Support;
5+
6+
namespace ModularityKit.Mutator.Benchmarks.Governance.Resolution;
7+
8+
/// <summary>
9+
/// Benchmarks governance version resolution paths in the governance runtime.
10+
/// </summary>
11+
[BenchmarkCategory("Governance")]
12+
[MemoryDiagnoser]
13+
[InProcess]
14+
public class GovernanceVersionResolutionBenchmarks
15+
{
16+
private const string MatchingRequestId = "governance-resolution-matching";
17+
private const string StaleRequestId = "governance-resolution-stale";
18+
private const string RevalidateRequestId = "governance-resolution-revalidate";
19+
20+
private GovernanceVersionResolutionBenchmarkSupport.GovernanceVersionResolutionBenchmarkFixture _matchingFixture = null!;
21+
private GovernanceVersionResolutionBenchmarkSupport.GovernanceVersionResolutionBenchmarkFixture _staleFixture = null!;
22+
private GovernanceVersionResolutionBenchmarkSupport.GovernanceVersionResolutionBenchmarkFixture _revalidateFixture = null!;
23+
24+
/// <summary>
25+
/// Prepares fresh fixtures for each benchmark iteration.
26+
/// </summary>
27+
[IterationSetup]
28+
public void Setup()
29+
{
30+
_matchingFixture = GovernanceVersionResolutionBenchmarkSupport.CreateFixture(
31+
MatchingRequestId,
32+
expectedStateVersion: "v10",
33+
currentStateVersion: "v10");
34+
35+
_staleFixture = GovernanceVersionResolutionBenchmarkSupport.CreateFixture(
36+
StaleRequestId,
37+
expectedStateVersion: "v10",
38+
currentStateVersion: "v15");
39+
40+
_revalidateFixture = GovernanceVersionResolutionBenchmarkSupport.CreateFixture(
41+
RevalidateRequestId,
42+
expectedStateVersion: "v10",
43+
currentStateVersion: "v15");
44+
}
45+
46+
/// <summary>
47+
/// Measures version comparison when approved request matches the current state version.
48+
/// </summary>
49+
[Benchmark(Baseline = true)]
50+
public async Task ResolveApproved_MatchingVersion()
51+
{
52+
var result = await _matchingFixture.ResolutionManager.ResolveAndStore(
53+
_matchingFixture.Request.RequestId,
54+
currentStateVersion: _matchingFixture.CurrentStateVersion,
55+
resolutionContext: _matchingFixture.ResolutionContext,
56+
strategy: VersionedRequestResolutionStrategy.RejectStale).ConfigureAwait(false);
57+
58+
GC.KeepAlive(result);
59+
}
60+
61+
/// <summary>
62+
/// Measures stale request detection and classification during version resolution.
63+
/// </summary>
64+
[Benchmark]
65+
public async Task ResolveApproved_RejectStale()
66+
{
67+
var result = await _staleFixture.ResolutionManager.ResolveAndStore(
68+
_staleFixture.Request.RequestId,
69+
currentStateVersion: _staleFixture.CurrentStateVersion,
70+
resolutionContext: _staleFixture.ResolutionContext,
71+
strategy: VersionedRequestResolutionStrategy.RejectStale).ConfigureAwait(false);
72+
73+
GC.KeepAlive(result);
74+
}
75+
76+
/// <summary>
77+
/// Measures revalidation-driven request resolution against the latest state version.
78+
/// </summary>
79+
[Benchmark]
80+
public async Task ResolveApproved_Revalidate()
81+
{
82+
var result = await _revalidateFixture.ResolutionManager.ResolveAndStore(
83+
_revalidateFixture.Request.RequestId,
84+
currentStateVersion: _revalidateFixture.CurrentStateVersion,
85+
resolutionContext: _revalidateFixture.ResolutionContext,
86+
strategy: VersionedRequestResolutionStrategy.RevalidateOnLatestState).ConfigureAwait(false);
87+
88+
GC.KeepAlive(result);
89+
}
90+
}

0 commit comments

Comments
 (0)