Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using BenchmarkDotNet.Attributes;
using ModularityKit.Mutator.Abstractions.Audit;
using ModularityKit.Mutator.Abstractions.History;
using ModularityKit.Mutator.Governance.Abstractions.Queries.Model.Decisions;
using ModularityKit.Mutator.Benchmarks.Governance.Materialization.Support;

namespace ModularityKit.Mutator.Benchmarks.Governance.Materialization;

/// <summary>
/// Benchmarks governance output materialization paths in the governance runtime.
/// </summary>
[BenchmarkCategory("Governance")]
[MemoryDiagnoser]
[InProcess]
public class GovernanceMaterializationOutputBenchmarks
{
private GovernanceMaterializationBenchmarkSupport.GovernanceMaterializationBenchmarkFixture _fixture = null!;

/// <summary>
/// Prepares a representative governed execution result for output materialization benchmarks.
/// </summary>
[GlobalSetup]
public void Setup()
{
_fixture = GovernanceMaterializationBenchmarkSupport.CreateFixture();
}

/// <summary>
/// Measures materialization of the history entry, including copied side effects from governed execution.
/// </summary>
[Benchmark(Baseline = true)]
public MutationHistoryEntry HistoryEntry_FromGovernedExecution()
{
return new MutationHistoryEntry
{
ExecutionId = _fixture.Result.Request.RequestId,
StateId = _fixture.Result.Request.StateId,
Intent = _fixture.Mutation.Intent,
Context = _fixture.Mutation.Context,
Changes = _fixture.Result.MutationResult!.Changes,
SideEffects = _fixture.Result.Request.SideEffects.ToList(),
Timestamp = _fixture.Result.Request.Versioning.ExecutedAt ?? DateTimeOffset.UtcNow,
ExecutionTime = TimeSpan.FromMilliseconds(2)
};
}

/// <summary>
/// Measures materialization of the audit entry produced from the same governed execution output.
/// </summary>
[Benchmark]
public MutationAuditEntry AuditEntry_FromGovernedExecution()
{
return new MutationAuditEntry
{
ExecutionId = _fixture.Result.Request.RequestId,
StateId = _fixture.Result.Request.StateId,
StateType = _fixture.Result.Request.StateType,
MutationIntent = _fixture.Mutation.Intent,
Context = _fixture.Mutation.Context,
Changes = _fixture.Result.MutationResult!.Changes,
IsSuccess = _fixture.Result.MutationResult.IsSuccess,
ErrorMessage = null,
PolicyDecisions = _fixture.Result.MutationResult.PolicyDecisions,
SideEffects = _fixture.Result.Request.SideEffects.ToList(),
Timestamp = _fixture.Result.Request.Versioning.ExecutedAt ?? DateTimeOffset.UtcNow,
Duration = TimeSpan.FromMilliseconds(2),
Metadata = new Dictionary<string, object>
{
["ExecutionKind"] = _fixture.Result.ExecutionKind.ToString(),
["RequestStatus"] = _fixture.Result.Request.Status.ToString()
}
};
}

/// <summary>
/// Measures request decision materialization for downstream consumers.
/// </summary>
[Benchmark]
public IReadOnlyList<MutationRequestDecisionView> DecisionViews_FromGovernedRequest()
{
var request = _fixture.Result.Request;
var views = request.Decisions.Select(decision => new MutationRequestDecisionView
{
Request = request,
Decision = decision
}).ToList();

GC.KeepAlive(views);
return views;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using ModularityKit.Mutator.Abstractions;
using ModularityKit.Mutator.Abstractions.Context;
using ModularityKit.Mutator.Abstractions.Engine;
using ModularityKit.Mutator.Benchmarks.Engine;
using ModularityKit.Mutator.Governance.Abstractions.Execution.Model;
using ModularityKit.Mutator.Governance.Abstractions.Requests.Factory;
using ModularityKit.Mutator.Governance.Abstractions.Requests.Model;
using ModularityKit.Mutator.Governance.Abstractions.Resolution.Strategies;
using ModularityKit.Mutator.Governance.Runtime.Execution.Orchestration;
using ModularityKit.Mutator.Governance.Runtime.Resolution.Execution;
using ModularityKit.Mutator.Governance.Runtime.Storage;

namespace ModularityKit.Mutator.Benchmarks.Governance.Materialization.Support;

/// <summary>
/// Builds repeatable governance materialization benchmark fixtures.
/// </summary>
internal static class GovernanceMaterializationBenchmarkSupport
{
public const string StateId = "governance-benchmark:materialization";

/// <summary>
/// Creates a fresh execution result fixture for a single scenario run.
/// </summary>
public static GovernanceMaterializationBenchmarkFixture CreateFixture()
{
var engine = MutationEngineBenchmarkSupport.BuildEngine(MutationEngineOptions.Strict);
var store = new InMemoryMutationRequestStore();
var resolutionManager = new MutationRequestVersionResolutionManager(store, new MutationRequestVersionResolver());
var executionManager = new GovernanceExecutionManager(store, resolutionManager, engine);
var request = store.Create(CreateApprovedRequest<GovernanceMaterializationState, MaterializeGovernanceOutputMutation>("governance-materialization-request"))
.GetAwaiter()
.GetResult();
var mutation = new MaterializeGovernanceOutputMutation(
MutationContext.User("operator", "Operator", "Execute governance materialization benchmark"),
nextVersion: "v11");

var result = executionManager.ExecuteApproved(
request.RequestId,
mutation,
new GovernanceMaterializationState(StateId, 10, "v10"),
governanceContext: mutation.Context,
strategy: VersionedRequestResolutionStrategy.RejectStale)
.GetAwaiter()
.GetResult();

return new GovernanceMaterializationBenchmarkFixture(result, mutation);
}

private static MutationRequest CreateApprovedRequest<TState, TMutation>(string requestId)
where TMutation : IMutation<TState>
=> MutationRequestFactory.Approved<TState, TMutation>(
stateId: StateId,
intent: GovernanceMaterializationScenarioFactory.CreateIntent(),
context: MutationContext.User("requester", "Requester", "Need governance output materialization"),
expectedStateVersion: "v10")
with
{
RequestId = requestId
};

/// <summary>
/// Shared execution result fixture for a governance materialization scenario.
/// </summary>
internal sealed record GovernanceMaterializationBenchmarkFixture(
GovernedExecutionResult<GovernanceMaterializationState> Result,
MaterializeGovernanceOutputMutation Mutation);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using ModularityKit.Mutator.Abstractions.Intent;

namespace ModularityKit.Mutator.Benchmarks.Governance.Materialization.Support;

/// <summary>
/// Creates governance materialization benchmark intent metadata.
/// </summary>
internal static class GovernanceMaterializationScenarioFactory
{
/// <summary>
/// Creates the intent used by governance materialization scenarios.
/// </summary>
public static MutationIntent CreateIntent()
=> new()
{
OperationName = "MaterializeGovernanceOutput",
Category = "Governance",
Description = "Materialize governance output for audit, history, and downstream consumers",
RiskLevel = MutationRiskLevel.Low,
IsReversible = true
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using ModularityKit.Mutator.Abstractions.Effects;

namespace ModularityKit.Mutator.Benchmarks.Governance.Materialization.Support;

/// <summary>
/// Typed payload used to give governance side effects realistic materialization shape.
/// </summary>
/// <param name="Token">A stable payload token.</param>
/// <param name="Index">The ordinal of the side effect.</param>
[SideEffectDataContract("governance.materialization.side-effect", 1)]
internal sealed record GovernanceMaterializationSideEffectData(string Token, int Index);
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using ModularityKit.Mutator.Governance.Abstractions.Execution.Contracts;

namespace ModularityKit.Mutator.Benchmarks.Governance.Materialization.Support;

/// <summary>
/// Minimal versioned state used by governance materialization benchmarks.
/// </summary>
/// <param name="StateId">Stable state identifier.</param>
/// <param name="Value">Benchmark counter value.</param>
/// <param name="Version">Current state version.</param>
internal sealed record GovernanceMaterializationState(string StateId, int Value, string Version) : IVersionedState;
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using ModularityKit.Mutator.Abstractions.Changes;
using ModularityKit.Mutator.Abstractions.Context;
using ModularityKit.Mutator.Abstractions.Effects;
using ModularityKit.Mutator.Abstractions.Engine;
using ModularityKit.Mutator.Abstractions.Intent;
using ModularityKit.Mutator.Abstractions.Results;

namespace ModularityKit.Mutator.Benchmarks.Governance.Materialization.Support;

/// <summary>
/// Minimal mutation used to produce executed governance output with side effects.
/// </summary>
internal sealed class MaterializeGovernanceOutputMutation(MutationContext context, string nextVersion)
: IMutation<GovernanceMaterializationState>
{
/// <summary>
/// Gets the intent associated with the materialization mutation.
/// </summary>
public MutationIntent Intent { get; } = new()
{
OperationName = "MaterializeGovernanceOutputMutation",
Category = "Governance",
Description = "Produce governed execution output for materialization benchmarks",
RiskLevel = MutationRiskLevel.Low,
IsReversible = true
};

/// <summary>
/// Gets the invocation context for the mutation.
/// </summary>
public MutationContext Context { get; } = context;

/// <summary>
/// Applies the mutation and emits governance side effects.
/// </summary>
public MutationResult<GovernanceMaterializationState> Apply(GovernanceMaterializationState state)
{
var next = state with
{
Value = state.Value + 1,
Version = nextVersion
};

return MutationResult<GovernanceMaterializationState>.Success(
next,
ChangeSet.FromChanges(
StateChange.Modified(nameof(GovernanceMaterializationState.Value), state.Value, next.Value),
StateChange.Modified(nameof(GovernanceMaterializationState.Version), state.Version, next.Version)),
CreateSideEffects());
}

/// <summary>
/// Validates the provided state before mutation execution.
/// </summary>
public ValidationResult Validate(GovernanceMaterializationState state)
{
return state.Value < 0
? ValidationResult.WithError(nameof(GovernanceMaterializationState.Value), "Value must be non-negative.")
: ValidationResult.Success();
}

/// <summary>
/// Simulates the mutation using the same state transition as execution.
/// </summary>
public MutationResult<GovernanceMaterializationState> Simulate(GovernanceMaterializationState state) => Apply(state);

private static IReadOnlyList<SideEffect> CreateSideEffects()
=> [
SideEffect.Create(
"GovernanceOutputMaterialized",
"Governed execution output materialized for history and audit consumers",
new GovernanceMaterializationSideEffectData("history-audit", 1),
SideEffectSeverity.Info),
SideEffect.Critical(
"GovernanceOutputLinked",
"Governed execution output linked for downstream request consumers",
new GovernanceMaterializationSideEffectData("request-link", 2))
];
}
63 changes: 63 additions & 0 deletions Benchmarks/Governance/Queries/GovernanceQueryReadBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using BenchmarkDotNet.Attributes;
using ModularityKit.Mutator.Governance.Abstractions.Queries.Model.Decisions;
using ModularityKit.Mutator.Governance.Abstractions.Queries.Model.Requests;
using ModularityKit.Mutator.Benchmarks.Governance.Queries.Support;

namespace ModularityKit.Mutator.Benchmarks.Governance.Queries;

/// <summary>
/// Benchmarks governance query and read paths in the governance runtime.
/// </summary>
[BenchmarkCategory("Governance")]
[MemoryDiagnoser]
[InProcess]
public class GovernanceQueryReadBenchmarks
{
private GovernanceQueryReadBenchmarkSupport.GovernanceQueryReadBenchmarkFixture _fixture = null!;

/// <summary>
/// Prepares a seeded query store for the read benchmarks.
/// </summary>
[GlobalSetup]
public void Setup()
{
_fixture = GovernanceQueryReadBenchmarkSupport.CreateFixture();
}

/// <summary>
/// Measures listing pending governance requests.
/// </summary>
[Benchmark(Baseline = true)]
public async Task GetPendingRequests()
{
var result = await _fixture.RequestStore.GetPendingRequestsAsync(
MutationRequestQueries.Pending()).ConfigureAwait(false);

GC.KeepAlive(result);
}

/// <summary>
/// Measures listing pending approval queue entries.
/// </summary>
[Benchmark]
public async Task GetPendingApprovalQueue()
{
var result = await _fixture.ApprovalStore.GetPendingApprovalQueueAsync(
MutationRequestQueries.PendingApprovalQueue()).ConfigureAwait(false);

GC.KeepAlive(result);
}

/// <summary>
/// Measures reading recent execution outcome decisions.
/// </summary>
[Benchmark]
public async Task GetRecentExecutionOutcomes()
{
var result = await _fixture.DecisionStore.GetRecentDecisionsAsync(
MutationRequestDecisionQuery.RecentExecutionOutcomes(),
take: 64).ConfigureAwait(false);

GC.KeepAlive(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using ModularityKit.Mutator.Governance.Runtime.Storage;

namespace ModularityKit.Mutator.Benchmarks.Governance.Queries.Support;

/// <summary>
/// Builds repeatable governance query benchmark fixtures.
/// </summary>
internal static class GovernanceQueryReadBenchmarkSupport
{
/// <summary>
/// Creates a seeded fixture for query and read benchmarks.
/// </summary>
public static GovernanceQueryReadBenchmarkFixture CreateFixture()
=> new(
RequestStore: PendingRequestQueryBenchmarkSeed.CreateStore(),
ApprovalStore: PendingApprovalQueryBenchmarkSeed.CreateStore(),
DecisionStore: RecentDecisionQueryBenchmarkSeed.CreateStore());

/// <summary>
/// Shared fixture for governance query and read scenarios.
/// </summary>
internal sealed record GovernanceQueryReadBenchmarkFixture(
InMemoryMutationRequestStore RequestStore,
InMemoryMutationRequestStore ApprovalStore,
InMemoryMutationRequestStore DecisionStore);
}
Loading
Loading