Skip to content

build: add BenchmarkDotNet baseline project for test doubles (#80, #102)#167

Merged
Chris-Wolfgang merged 2 commits into
mainfrom
feature/benchmarks-80-102
Jun 23, 2026
Merged

build: add BenchmarkDotNet baseline project for test doubles (#80, #102)#167
Chris-Wolfgang merged 2 commits into
mainfrom
feature/benchmarks-80-102

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Summary

Stands up a BenchmarkDotNet baseline project for the ETL Test Kit's runtime test doubles, satisfying #80 (stand up a BDN baseline project) and #102 (hold benchmarks to TreatWarningsAsErrors via a curated benchmarks/.editorconfig, with no benchmarks/Directory.Build.props exemption).

The project

benchmarks/Wolfgang.Etl.TestKit.Benchmarks/ — an Exe targeting net10.0, LangVersion=latest, ImplicitUsings=disable, with a ProjectReference to Wolfgang.Etl.TestKit and a single BenchmarkDotNet 0.15.8 package reference. Program.cs uses the standard BenchmarkSwitcher.FromAssembly(...).Run(args) entry point. Analyzer package references are inherited from the root Directory.Build.props (comment noted in the csproj). Added to ETL-Test-Kit.slnx under the /benchmarks/ folder.

Three benchmark classes

Each is [MemoryDiagnoser], with [Params(1_000, 10_000, 100_000)] public int ItemCount and a [GlobalSetup] that builds an in-memory int[]. T = int keeps allocations dominated by the framework path rather than record construction. One representative benchmark per class is [Benchmark(Baseline = true)].

  • ExtractorBenchmarks.Extractnew TestExtractor<int>(int[]) then await foreach over ExtractAsync().
  • LoaderBenchmarks.Loadnew TestLoader<int>(collectItems: false) then await loader.LoadAsync(source).
  • TransformerBenchmarks.Transformnew TestTransformer<int>() then await foreach over TransformAsync(source).

#102 — held to TreatWarningsAsErrors

There is no benchmarks/Directory.Build.props. The benchmark project inherits the root Directory.Build.props, so it IS held to TreatWarningsAsErrors in Release. The only relaxation is a curated benchmarks/.editorconfig silencing genuinely benchmark-inappropriate analyzer rules, each with a one-line justification:

  • AsyncFixer01 — remove async/await; benchmark methods follow BDN conventions.
  • MA0004ConfigureAwait(false) not needed in the benchmark harness.
  • S1215GC.GetTotalMemory is required by memory benchmarks.
  • VSTHRD200 — Async suffix; benchmark method names follow BDN naming conventions.

This matches the curated FixedWidth set exactly — no additional rule IDs were needed; the Release build is clean (0 warnings, 0 errors) against the full analyzer set.

IAsyncEnumerable source

Rather than depend on System.Linq.Async's .ToAsyncEnumerable() (a transitive dep), the loader and transformer benchmarks use a tiny local async IAsyncEnumerable<int> generator helper, keeping the source self-contained and the measured pipeline obvious.

Verification

  • dotnet build benchmarks/Wolfgang.Etl.TestKit.Benchmarks/... -c ReleaseBuild succeeded, 0 Warning(s), 0 Error(s).
  • dotnet run -c Release --project benchmarks/... -- --list flat lists all three benchmarks.
  • dotnet run -c Release --project benchmarks/... -- --filter '*Extract*' --job dry executes and emits a summary table with the MemoryDiagnoser Allocated column (e.g. ~520 B/op across all three ItemCount params), confirming the harness runs.

Closes #80
Closes #102

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Chris-Wolfgang Chris-Wolfgang merged commit cb26a05 into main Jun 23, 2026
8 checks passed
@Chris-Wolfgang Chris-Wolfgang deleted the feature/benchmarks-80-102 branch June 23, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant