Introduce new performance benchmark runners#4447
Conversation
There was a problem hiding this comment.
Pull request overview
Adds new BenchmarkDotNet runners to the Microsoft.Data.SqlClient.PerformanceTests harness to measure previously reported performance hot spots (large async reads, MARS overhead, parallel OpenAsync, cancellation token overhead, sequential XML reads, JSON vs VARCHAR reads, transaction latency, and connection pool stress), along with configuration and wiring updates to run them via runnerconfig.json.
Changes:
- Registers 8 new benchmark runners and gates each by a per-runner
RunnerJob.Enabledconfig. - Extends the perf test config model (
Config) and defaultrunnerconfig.jsonwith new runner entries plus new top-level flags. - Updates BenchmarkDotNet
ManualConfigoptions/environment for more consistent perf runs (e.g., dont overwrite results, joined summary, server GC).
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/runnerconfig.json | Adds new top-level flags and runner job entries; enables new runners by default and disables older ones. |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/Program.cs | Loads config, applies AppContext switches / optional profiler wait, and invokes each runner when enabled. |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/Config/Config.cs | Adds new config fields and per-runner RunnerJob entries. |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/Config/BenchmarkConfig.cs | Updates BDN config options and sets server GC env var; joins summaries. |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/BenchmarkRunners/AsyncLargeDataReadRunner.cs | New runner to compare sync vs async large VARBINARY streaming reads. |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/BenchmarkRunners/MarsOverheadRunner.cs | New runner comparing query execution with MARS enabled/disabled (sync + async). |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/BenchmarkRunners/ParallelAsyncConnectionRunner.cs | New runner opening many connections concurrently with pooling on/off. |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/BenchmarkRunners/CancellationTokenReadAsyncRunner.cs | New runner measuring ReadAsync iteration overhead with/without CancellationToken. |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/BenchmarkRunners/SequentialXmlReadRunner.cs | New runner targeting sequential XML read scaling across payload sizes. |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/BenchmarkRunners/JsonVsVarcharReadRunner.cs | New runner comparing JSON vs VARCHAR read performance (disabled by default). |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/BenchmarkRunners/BeginTransactionRunner.cs | New runner comparing transaction vs no-transaction latency (sync + async). |
| src/Microsoft.Data.SqlClient/tests/PerformanceTests/BenchmarkRunners/ConnectionPoolStressRunner.cs | New stress runner for pooled open/close churn, mixed sync/async contention, and exhaustion/recovery. |
apoorvdeshmukh
left a comment
There was a problem hiding this comment.
These benchmarks will be very helpful!
Wondering if it would be possible to establish a baseline for native memory consumption when running these benchmarks and monitor memory growth if it drifts too much from the established baseline? This may be beyond the current scope of the PR but worth looking into.
Added optionally, could you try and confirm as well? |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4447 +/- ##
==========================================
- Coverage 65.83% 63.95% -1.89%
==========================================
Files 287 284 -3
Lines 43763 66786 +23023
==========================================
+ Hits 28812 42712 +13900
- Misses 14951 24074 +9123
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- AsyncLargeDataReadRunner: seed VARBINARY(MAX) row via CRYPT_GEN_RANDOM T-SQL instead of allocating a client-side byte[] and shipping it over the wire, and add [Params] for ReadBufferBytes so we can observe how the client read buffer size interacts with payload size. - CancellationTokenReadAsyncRunner: move CancellationTokenSource allocation to [IterationSetup] and disposal to [IterationCleanup] so only the per-row ReadAsync(CancellationToken) overhead is measured. - ConnectionPoolStressRunner: scale the RapidFireOpenClose per-task iteration count with MaxPoolSize/Parallelism so total checkouts stay proportional to pool capacity, and drop the unused System.Collections.Generic import. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 62d8a5ff-8bd4-4780-9715-748ea0d950aa
- JsonVsVarcharReadRunner: use SqlDataReader.GetSqlJson(0).Value for the JSON case (sync and async) so the benchmark exercises the SqlJson accessor path implicated in #3499 instead of the shared GetString / GetFieldValueAsync<string> path used for VARCHAR. - ConnectionPoolStressRunner.BurstyTrafficPattern: spin up Parallelism concurrent tasks per burst instead of Parallelism/burstCount, so the configured Parallelism parameter actually drives observed concurrency. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 62d8a5ff-8bd4-4780-9715-748ea0d950aa
|
/azp run |
|
Azure Pipelines: Successfully started running 3 pipeline(s). |
Summary
Adds 8
BenchmarkDotNetrunners toMicrosoft.Data.SqlClient.PerformanceTestscovering previously-reported hot spots, plus config/wiring updates to support them.New runners
VARBINARY(MAX)(1–20 MB)OpenAsync(10/50/100), pooling on/offCancellationTokenoverhead inReadAsyncSequentialAccessXML reads at increasing sizes (O(N²) check)JSONvsVARCHAR(MAX)reads (disabled by default, needs SQL 2025+)BeginTransaction/Asynclatency vs baselineSupporting changes
RunnerJob.EnabledRunnerJobper runnerDontOverwriteResults,JoinSummary,COMPlus_gcServer=1Validation
Ran all new runners locally (.NET 9.0 Release, Apple M3 Pro, Docker
azure-sql-edge) — all completed successfully.Checklist