Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ public class ConnectionPoolStressRunner : BaseRunner
/// <summary>
/// Max pool size — controls how many physical connections the pool can hold.
/// When Parallelism exceeds this, tasks must wait for a free connection.
/// The larger values exercise pool bookkeeping under high capacity; SQL Server
/// itself must be able to accept that many concurrent connections for the
/// higher values to be meaningful.
Comment on lines 33 to +37
/// </summary>
[Params(50, 100)]
[Params(50, 100, 500, 1000)]
public int MaxPoolSize { get; set; }

[GlobalSetup]
Expand Down Expand Up @@ -145,18 +148,21 @@ public async Task RandomizedHoldAndQuery()
/// <summary>
/// Mixed sync and async — half the tasks use sync Open/ExecuteReader,
/// the other half use async. Stresses the pool lock paths that differ
/// between sync and async checkout.
/// between sync and async checkout. Per-task iteration count scales with
/// MaxPoolSize/Parallelism so total checkouts stay proportional to pool
/// capacity regardless of how the [Params] values change.
/// </summary>
[Benchmark]
public async Task MixedSyncAsyncContention()
{
int iterationsPerTask = Math.Max(10, MaxPoolSize / Math.Max(1, Parallelism) * 2);
var tasks = new Task[Parallelism];
for (int i = 0; i < Parallelism; i++)
{
bool useAsync = i % 2 == 0;
tasks[i] = Task.Run(async () =>
{
for (int j = 0; j < 10; j++)
for (int j = 0; j < iterationsPerTask; j++)
{
using var conn = new SqlConnection(_connectionString);
if (useAsync)
Expand All @@ -181,10 +187,14 @@ public async Task MixedSyncAsyncContention()
/// Connection reuse with multiple commands — each task opens one connection and
/// executes many sequential queries before returning it. Measures pool efficiency
/// when connections are held for multi-step operations (like EF SaveChanges).
/// Command burst size scales with MaxPoolSize so the workload per checkout grows
/// with pool capacity.
/// </summary>
[Benchmark]
public async Task MultiCommandReuse()
{
int minCommands = Math.Max(5, MaxPoolSize / 20);
int maxCommandsExclusive = Math.Max(minCommands + 1, MaxPoolSize / 5);
var tasks = new Task[Parallelism];
for (int i = 0; i < Parallelism; i++)
{
Expand All @@ -195,8 +205,7 @@ public async Task MultiCommandReuse()
using var conn = new SqlConnection(_connectionString);
await conn.OpenAsync();

// Execute a burst of 5-15 commands on the same connection
int commandCount = rng.Next(5, 16);
int commandCount = rng.Next(minCommands, maxCommandsExclusive);
for (int c = 0; c < commandCount; c++)
{
using var cmd = new SqlCommand($"SELECT Val FROM {_tableName} WHERE Id = @id", conn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ public static ManualConfig s_instance(RunnerJob runnerJob)
.WithWarmupCount(runnerJob.WarmupCount)
.WithUnrollFactor(1)
.WithStrategy(BenchmarkDotNet.Engines.RunStrategy.Throughput)
.WithEnvironmentVariable("COMPlus_gcServer", "1")
// Server GC is configured at the host-process level via the
// <ServerGarbageCollection> csproj property (COMPlus_gcServer is
// startup-only and would be ignored here under InProcessEmitToolchain).
)
.WithOptions(ConfigOptions.JoinSummary);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<Configurations>Debug;Release;</Configurations>
<StartupObject>Microsoft.Data.SqlClient.PerformanceTests.Program</StartupObject>
<!-- The perf test host process runs benchmarks in-process via InProcessEmitToolchain,
so GC mode must be configured up-front on the host. COMPlus_gcServer is a
startup-only runtime knob and won't apply if set after the host has started. -->
<ServerGarbageCollection>true</ServerGarbageCollection>
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
</PropertyGroup>

<!-- Items to remove -->
Expand Down
Loading