Skip to main content

Vali-Flow Benchmarks

The Vali-Flow.Benchmarks project measures the performance of the InMemory evaluator and the SQL builder using BenchmarkDotNet.


Running benchmarks​

Always run in Release mode. Debug builds disable BenchmarkDotNet's warmup and measurement phases.

cd Vali-Flow.Benchmarks
dotnet run --configuration Release

Results land in BenchmarkDotNet.Artifacts/results/. Do not commit these files — they are gitignored.

To run a specific benchmark class:

dotnet run --configuration Release -- --filter "*InMemoryFilter*"
dotnet run --configuration Release -- --filter "*SqlBuilder*"

Benchmark suites​

InMemory evaluator​

All InMemory benchmarks parameterize over N ∈ { 1 000, 10 000, 100 000 } to show how each operation scales.

ClassWhat it measures
InMemoryFilterBenchmarksEvaluateQuery (enumerate all) and EvaluateAny — baseline is raw LINQ .Where()
InMemoryCountBenchmarksEvaluateCount with a simple filter vs a compound filter
InMemoryAggregateBenchmarksEvaluateSum, EvaluateAverage, EvaluateMin, EvaluateMax, EvaluateCountByGroup
InMemoryWriteBenchmarksAdd, Update, Delete, Upsert — per-operation cost
InMemoryPaginationBenchmarksEvaluatePaged at different page sizes
InMemoryLookupBenchmarksDirect entity lookup by ID vs filtered search

SQL builder​

ClassWhat it measures
SqlBuilderBenchmarksSqlQueryBuilder SELECT with JOINs, INSERT, UPDATE — construction cost only (no DB round-trip)

Interpreting results​

BenchmarkDotNet reports:

ColumnMeaning
MeanAverage time per operation across all iterations
RatioRelative to the marked [Benchmark(Baseline = true)] method
AllocatedManaged heap allocated per operation (requires [MemoryDiagnoser])

What to look for:

  • Ratio ≈ 1.0 — on par with the baseline (typically raw LINQ)
  • Ratio < 2.0 — acceptable overhead for the evaluator abstraction layer
  • Allocated bytes growing with N — expected; flat allocation across N sizes indicates a potential issue

Adding a new benchmark​

  1. Create a class in Vali-Flow.Benchmarks/Benchmarks/ annotated with [MemoryDiagnoser].
  2. Parameterize with [Params(1_000, 10_000, 100_000)] for collection-size-sensitive operations.
  3. Mark one method as [Benchmark(Baseline = true)] — use the equivalent raw LINQ/direct operation as the baseline.
  4. Use BenchmarkDataFactory.Generate(N) to produce consistent, reproducible test data.
  5. Avoid side effects in benchmarks — write results to a Consumer (BenchmarkDotNet's sink), not to Console.

Known limitations​

  • No NoSQL benchmarks — Vali-Flow.NoSql.* translators are not benchmarked. Translation is CPU-only (no I/O) and the trees are small, so overhead is expected to be sub-microsecond.
  • No EF Core benchmarks — EF Core performance is dominated by the database round-trip, not the Vali-Flow layer. Profiling should be done with actual query plans, not microbenchmarks.

See also​