Serena MCP is mandatory for C# code. First call
mcp__serena__initial_instructionsto load the Serena tool manual, then use the Serena tools for ALL.csreading / searching / navigation / creation / editing — prefer symbol navigation (get_symbols_overview/find_symbol/find_referencing_symbols) over whole-file reads. NativeEdit/Writeon.csis hook-blocked (the TS/React frontend uses the native tools).
Microbenchmarking with BenchmarkDotNet ({{ProductName}})
Use this to turn a perf claim (often from dotnet-performance-review) into measured evidence. C# (.cs)
benchmark files are written via Serena.
⚠ Library approval required. BenchmarkDotNet is a third-party NuGet package. It is the de-facto .NET standard, but per our governance it needs Dan's explicit approval before being added (likely to a dedicated
*.Benchmarksproject, not the product projects). Do not add it silently.
Concepts
- Benchmark case = one method × one param combo × one job (the atomic measured unit).
- Benchmarks are comparative: a single run can compare approaches, runtime configuration, or package versions (e.g. LLM-provider-client versions, GC settings). Hardware/OS and historical comparisons need separate runs.
Cost-aware job presets
--job Dry (<1s, correctness only) → --job Short (5–8s, dev iteration) → Default (15–25s, final) →
--job Medium/--job Long (max confidence). Start cheap, escalate.
CLI
dotnet add package BenchmarkDotNet # only after approval
dotnet run -c Release -- --filter "*MethodName" --noOverwrite > benchmark.log 2>&1
Always Release. Use --filter (with BenchmarkSwitcher, or BenchmarkRunner to run directly) so it
doesn't hang waiting for input.
Writing workflow
- Plan — pick the use case (coverage suite / investigation / change-validation / throwaway) and the comparison axis; justify the cost (preset).
- Implement —
[Benchmark]methods that return their result (so the JIT can't elide them); init in[GlobalSetup](never in the benchmark body); no manual loops; mark the reference[Benchmark(Baseline = true)]; store inputs in fields or[Params]/[ParamsSource], not literals;[MemoryDiagnoser]for allocations. - Validate —
--job Dryto confirm it compiles/runs → one representative case at defaults → full suite.
Key attributes: [Benchmark], [Benchmark(Baseline=true)], [MemoryDiagnoser], [Params], [ParamsSource],
[Arguments], [GlobalSetup], [IterationSetup].
Ours
- Benchmark classes/methods are
.cs→ write via Serena. - LLMs routinely write bad BenchmarkDotNet code from stale assumptions — measure correctly (return values, setup outside the body, no loops) and treat a single noisy run with skepticism.
- A benchmark is the evidence behind a perf change; cite the numbers (mean, allocations, ratio-to-baseline) when proposing the optimization back to Dan.