From 37d59a980ba9a5f1afe5155cee880af292b91add Mon Sep 17 00:00:00 2001 From: JerrettDavis Date: Sat, 23 May 2026 15:59:23 -0500 Subject: [PATCH] perf: add application scenario benchmark results --- README.md | 6 +++ .../Application/RepositoryBenchmarks.cs | 29 ++++++++++++++ .../Application/SpecificationBenchmarks.cs | 38 +++++++++++++++++++ .../Application/TableDataGatewayBenchmarks.cs | 29 ++++++++++++++ docs/guides/benchmark-results.md | 6 +++ docs/guides/benchmarks.md | 6 +++ 6 files changed, 114 insertions(+) create mode 100644 benchmarks/PatternKit.Benchmarks/Application/RepositoryBenchmarks.cs create mode 100644 benchmarks/PatternKit.Benchmarks/Application/SpecificationBenchmarks.cs create mode 100644 benchmarks/PatternKit.Benchmarks/Application/TableDataGatewayBenchmarks.cs diff --git a/README.md b/README.md index 6ebd4bf..34111b5 100644 --- a/README.md +++ b/README.md @@ -476,12 +476,18 @@ BenchmarkDotNet guidance is documented in [docs/guides/benchmarks.md](docs/guide | Message Translator | Execution | 365.30 ns | 2,528 B | 381.79 ns | 2,528 B | Same allocation; fluent was slightly faster in this path. | | Reliability Pipeline | Construction | 34.90 ns | 392 B | 33.16 ns | 328 B | Generated reduced construction time and allocation in this microbenchmark. | | Reliability Pipeline | Execution | 2.303 us | 3,992 B | 381.36 ns | 1,872 B | Generated was materially faster and allocated less for duplicate inbox processing plus outbox dispatch. | +| Repository | Construction | 9.793 ns | 112 B | 9.239 ns | 112 B | Same allocation; generated was slightly faster in this microbenchmark. | +| Repository | Execution | 146.37 ns | 888 B | 143.27 ns | 888 B | Same allocation; generated was slightly faster for the seed-and-query workflow. | | Retry | Construction | 25.36 ns | 208 B | 27.18 ns | 208 B | Same allocation; fluent was slightly faster in this microbenchmark. | | Retry | Execution | 110.53 ns | 600 B | 109.52 ns | 600 B | Same allocation; generated was slightly faster for the transient retry workflow. | | Scheduler Agent Supervisor | Construction | 47.29 ns | 400 B | 45.40 ns | 400 B | Same allocation; generated was slightly faster in this microbenchmark. | | Scheduler Agent Supervisor | Execution | 177.46 ns | 1,304 B | 180.14 ns | 1,304 B | Effectively equivalent for this scenario. | | Service Activator | Construction | 4.825 ns | 32 B | 4.641 ns | 32 B | Same allocation; generated was slightly faster in this microbenchmark. | | Service Activator | Execution | 25.48 ns | 256 B | 26.49 ns | 256 B | Same allocation; fluent was slightly faster in this path. | +| Specification | Construction | 196.03 ns | 1,704 B | 136.87 ns | 1,008 B | Generated reduced construction time and allocation in this microbenchmark. | +| Specification | Execution | 111.25 ns | 344 B | 93.30 ns | 344 B | Same allocation; generated was faster for loan-application evaluation. | +| Table Data Gateway | Construction | 9.740 ns | 120 B | 9.698 ns | 120 B | Effectively equivalent for this microbenchmark. | +| Table Data Gateway | Execution | 90.51 ns | 600 B | 96.35 ns | 600 B | Same allocation; fluent was slightly faster for the insert-update-query workflow. | Run the benchmarks on target hardware before making final route decisions: diff --git a/benchmarks/PatternKit.Benchmarks/Application/RepositoryBenchmarks.cs b/benchmarks/PatternKit.Benchmarks/Application/RepositoryBenchmarks.cs new file mode 100644 index 0000000..da3ea63 --- /dev/null +++ b/benchmarks/PatternKit.Benchmarks/Application/RepositoryBenchmarks.cs @@ -0,0 +1,29 @@ +using BenchmarkDotNet.Attributes; +using PatternKit.Application.Repository; +using PatternKit.Examples.RepositoryDemo; + +namespace PatternKit.Benchmarks.Application; + +[BenchmarkCategory("ApplicationArchitecture", "Repository")] +public class RepositoryBenchmarks +{ + [Benchmark(Baseline = true, Description = "Fluent: create repository")] + [BenchmarkCategory("Fluent", "Construction")] + public InMemoryRepository Fluent_CreateRepository() + => OrderRepositoryPolicies.CreateFluentRepository(); + + [Benchmark(Description = "Generated: create repository")] + [BenchmarkCategory("Generated", "Construction")] + public InMemoryRepository Generated_CreateRepository() + => GeneratedOrderRepository.CreateRepository(); + + [Benchmark(Description = "Fluent: seed and query repository")] + [BenchmarkCategory("Fluent", "Execution")] + public ValueTask Fluent_SeedAndQuery() + => OrderRepositoryDemo.RunFluentAsync(); + + [Benchmark(Description = "Generated: seed and query repository")] + [BenchmarkCategory("Generated", "Execution")] + public ValueTask Generated_SeedAndQuery() + => OrderRepositoryDemo.RunGeneratedAsync(); +} diff --git a/benchmarks/PatternKit.Benchmarks/Application/SpecificationBenchmarks.cs b/benchmarks/PatternKit.Benchmarks/Application/SpecificationBenchmarks.cs new file mode 100644 index 0000000..313b53e --- /dev/null +++ b/benchmarks/PatternKit.Benchmarks/Application/SpecificationBenchmarks.cs @@ -0,0 +1,38 @@ +using BenchmarkDotNet.Attributes; +using PatternKit.Application.Specification; +using PatternKit.Examples.SpecificationDemo; + +namespace PatternKit.Benchmarks.Application; + +[BenchmarkCategory("ApplicationArchitecture", "Specification")] +public class SpecificationBenchmarks +{ + private static readonly LoanApprovalSpecificationDemo.LoanApplication PrimeApplication = + LoanApprovalSpecificationDemo.CreatePrimeApplication(); + + private readonly SpecificationRegistry _fluent = + LoanApprovalSpecificationDemo.CreateFluentRegistry(); + + private readonly SpecificationRegistry _generated = + LoanApprovalSpecificationDemo.CreateGeneratedRegistry(); + + [Benchmark(Baseline = true, Description = "Fluent: create specification registry")] + [BenchmarkCategory("Fluent", "Construction")] + public SpecificationRegistry Fluent_CreateRegistry() + => LoanApprovalSpecificationDemo.CreateFluentRegistry(); + + [Benchmark(Description = "Generated: create specification registry")] + [BenchmarkCategory("Generated", "Construction")] + public SpecificationRegistry Generated_CreateRegistry() + => LoanApprovalSpecificationDemo.CreateGeneratedRegistry(); + + [Benchmark(Description = "Fluent: evaluate loan application")] + [BenchmarkCategory("Fluent", "Execution")] + public LoanApprovalSpecificationDemo.LoanDecision Fluent_EvaluateLoanApplication() + => LoanApprovalSpecificationDemo.Evaluate(PrimeApplication, _fluent); + + [Benchmark(Description = "Generated: evaluate loan application")] + [BenchmarkCategory("Generated", "Execution")] + public LoanApprovalSpecificationDemo.LoanDecision Generated_EvaluateLoanApplication() + => LoanApprovalSpecificationDemo.Evaluate(PrimeApplication, _generated); +} diff --git a/benchmarks/PatternKit.Benchmarks/Application/TableDataGatewayBenchmarks.cs b/benchmarks/PatternKit.Benchmarks/Application/TableDataGatewayBenchmarks.cs new file mode 100644 index 0000000..4744f59 --- /dev/null +++ b/benchmarks/PatternKit.Benchmarks/Application/TableDataGatewayBenchmarks.cs @@ -0,0 +1,29 @@ +using BenchmarkDotNet.Attributes; +using PatternKit.Application.TableDataGateway; +using PatternKit.Examples.TableDataGatewayDemo; + +namespace PatternKit.Benchmarks.Application; + +[BenchmarkCategory("ApplicationArchitecture", "TableDataGateway")] +public class TableDataGatewayBenchmarks +{ + [Benchmark(Baseline = true, Description = "Fluent: create table data gateway")] + [BenchmarkCategory("Fluent", "Construction")] + public InMemoryTableDataGateway Fluent_CreateGateway() + => OrderTableGatewayPolicies.CreateFluentGateway(); + + [Benchmark(Description = "Generated: create table data gateway")] + [BenchmarkCategory("Generated", "Construction")] + public InMemoryTableDataGateway Generated_CreateGateway() + => GeneratedOrderTableGateway.CreateGateway(); + + [Benchmark(Description = "Fluent: insert update query")] + [BenchmarkCategory("Fluent", "Execution")] + public ValueTask Fluent_InsertUpdateQuery() + => OrderTableDataGatewayDemo.RunFluentAsync(); + + [Benchmark(Description = "Generated: insert update query")] + [BenchmarkCategory("Generated", "Execution")] + public ValueTask Generated_InsertUpdateQuery() + => OrderTableDataGatewayDemo.RunGeneratedAsync(); +} diff --git a/docs/guides/benchmark-results.md b/docs/guides/benchmark-results.md index 3d6e83c..c7a1ad7 100644 --- a/docs/guides/benchmark-results.md +++ b/docs/guides/benchmark-results.md @@ -23,12 +23,18 @@ The latest measured timings below were captured on Windows 11, Intel Core i9-149 | Message Translator | Execution | 365.30 ns | 2,528 B | 381.79 ns | 2,528 B | Same allocation; fluent was slightly faster in this path. | | Reliability Pipeline | Construction | 34.90 ns | 392 B | 33.16 ns | 328 B | Generated reduced construction time and allocation in this microbenchmark. | | Reliability Pipeline | Execution | 2.303 us | 3,992 B | 381.36 ns | 1,872 B | Generated was materially faster and allocated less for duplicate inbox processing plus outbox dispatch. | +| Repository | Construction | 9.793 ns | 112 B | 9.239 ns | 112 B | Same allocation; generated was slightly faster in this microbenchmark. | +| Repository | Execution | 146.37 ns | 888 B | 143.27 ns | 888 B | Same allocation; generated was slightly faster for the seed-and-query workflow. | | Retry | Construction | 25.36 ns | 208 B | 27.18 ns | 208 B | Same allocation; fluent was slightly faster in this microbenchmark. | | Retry | Execution | 110.53 ns | 600 B | 109.52 ns | 600 B | Same allocation; generated was slightly faster for the transient retry workflow. | | Scheduler Agent Supervisor | Construction | 47.29 ns | 400 B | 45.40 ns | 400 B | Same allocation; generated was slightly faster in this microbenchmark. | | Scheduler Agent Supervisor | Execution | 177.46 ns | 1,304 B | 180.14 ns | 1,304 B | Effectively equivalent for this scenario. | | Service Activator | Construction | 4.825 ns | 32 B | 4.641 ns | 32 B | Same allocation; generated was slightly faster in this microbenchmark. | | Service Activator | Execution | 25.48 ns | 256 B | 26.49 ns | 256 B | Same allocation; fluent was slightly faster in this path. | +| Specification | Construction | 196.03 ns | 1,704 B | 136.87 ns | 1,008 B | Generated reduced construction time and allocation in this microbenchmark. | +| Specification | Execution | 111.25 ns | 344 B | 93.30 ns | 344 B | Same allocation; generated was faster for loan-application evaluation. | +| Table Data Gateway | Construction | 9.740 ns | 120 B | 9.698 ns | 120 B | Effectively equivalent for this microbenchmark. | +| Table Data Gateway | Execution | 90.51 ns | 600 B | 96.35 ns | 600 B | Same allocation; fluent was slightly faster for the insert-update-query workflow. | ## Coverage Matrix Summary diff --git a/docs/guides/benchmarks.md b/docs/guides/benchmarks.md index 446179c..20575e8 100644 --- a/docs/guides/benchmarks.md +++ b/docs/guides/benchmarks.md @@ -40,12 +40,18 @@ The following numbers were captured on Windows 11, Intel Core i9-14900K, .NET SD | Message Translator | Execution | 365.30 ns | 2,528 B | 381.79 ns | 2,528 B | Same allocation; fluent was slightly faster in this path. | | Reliability Pipeline | Construction | 34.90 ns | 392 B | 33.16 ns | 328 B | Generated reduced construction time and allocation in this microbenchmark. | | Reliability Pipeline | Execution | 2.303 us | 3,992 B | 381.36 ns | 1,872 B | Generated was materially faster and allocated less for duplicate inbox processing plus outbox dispatch. | +| Repository | Construction | 9.793 ns | 112 B | 9.239 ns | 112 B | Same allocation; generated was slightly faster in this microbenchmark. | +| Repository | Execution | 146.37 ns | 888 B | 143.27 ns | 888 B | Same allocation; generated was slightly faster for the seed-and-query workflow. | | Retry | Construction | 25.36 ns | 208 B | 27.18 ns | 208 B | Same allocation; fluent was slightly faster in this microbenchmark. | | Retry | Execution | 110.53 ns | 600 B | 109.52 ns | 600 B | Same allocation; generated was slightly faster for the transient retry workflow. | | Scheduler Agent Supervisor | Construction | 47.29 ns | 400 B | 45.40 ns | 400 B | Same allocation; generated was slightly faster in this microbenchmark. | | Scheduler Agent Supervisor | Execution | 177.46 ns | 1,304 B | 180.14 ns | 1,304 B | Effectively equivalent for this scenario. | | Service Activator | Construction | 4.825 ns | 32 B | 4.641 ns | 32 B | Same allocation; generated was slightly faster in this microbenchmark. | | Service Activator | Execution | 25.48 ns | 256 B | 26.49 ns | 256 B | Same allocation; fluent was slightly faster in this path. | +| Specification | Construction | 196.03 ns | 1,704 B | 136.87 ns | 1,008 B | Generated reduced construction time and allocation in this microbenchmark. | +| Specification | Execution | 111.25 ns | 344 B | 93.30 ns | 344 B | Same allocation; generated was faster for loan-application evaluation. | +| Table Data Gateway | Construction | 9.740 ns | 120 B | 9.698 ns | 120 B | Effectively equivalent for this microbenchmark. | +| Table Data Gateway | Execution | 90.51 ns | 600 B | 96.35 ns | 600 B | Same allocation; fluent was slightly faster for the insert-update-query workflow. | The coverage matrix is separate from the scenario timings. Matrix benchmarks prove every catalog pattern and every generator source file has a reportable BenchmarkDotNet route; pattern-specific scenario benchmarks provide the fluent-vs-generated construction and execution numbers shown above. See [Benchmark Results](benchmark-results.md) for the full pattern and generator matrix.