Skip to content

Commit 1640852

Browse files
fix: benchmark refactoring
1 parent 53b0df7 commit 1640852

18 files changed

+259
-330
lines changed

CodeGenerator/Generators/QueriesGen.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,7 @@ public class {{className}}{{baseTypesStr}}
102102

103103
return classDeclaration.AddMembers(
104104
[.. dbDriver.GetAdditionalClassMembers()
105-
.AddRangeExcludeNulls(classMembers)
106-
.AddRangeIf(
107-
[dbDriver.GetDisposeMethodImpl()],
108-
dbDriver.GetClassBaseTypes().Any(x => x == "IDisposable")
109-
)]
105+
.AddRangeExcludeNulls(classMembers)]
110106
);
111107
}
112108

Drivers/DbDriver.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,11 +238,6 @@ public virtual MemberDeclarationSyntax[] GetAdditionalClassMembers()
238238
return [];
239239
}
240240

241-
public virtual MemberDeclarationSyntax? GetDisposeMethodImpl()
242-
{
243-
return null;
244-
}
245-
246241
protected virtual ISet<string> GetConfigureSqlMappings()
247242
{
248243
return ColumnMappings

Drivers/MySqlConnectorDriver.cs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ public override string[] GetConstructorStatements()
499499
{{dataSourceVar}} = new Lazy<MySqlDataSource>(() =>
500500
{
501501
var builder = new MySqlConnectionStringBuilder({{connectionStringVar}}{{optionalNotNullVerify}});
502-
builder.ConnectionReset = {{Options.MySqlConnectionReset.ToString().ToLower()}};
502+
builder.ConnectionReset = true;
503503
// Pre-warm connection pool with minimum connections
504504
if (builder.MinimumPoolSize == 0)
505505
builder.MinimumPoolSize = 1;
@@ -513,32 +513,28 @@ public override MemberDeclarationSyntax[] GetAdditionalClassMembers()
513513
{
514514
var dataSourceField = Variable.DataSource.AsFieldName();
515515
var optionalNotNullVerify = Options.DotnetFramework.IsDotnetCore() ? "?" : string.Empty;
516-
var fieldDeclaration = ParseMemberDeclaration($$"""
517-
private readonly Lazy<MySqlDataSource>{{optionalNotNullVerify}} {{dataSourceField}};
518-
""")!;
519516

520-
var getDataSourceMethod = ParseMemberDeclaration($$"""
517+
return [
518+
ParseMemberDeclaration($$"""
519+
private readonly Lazy<MySqlDataSource>{{optionalNotNullVerify}} {{dataSourceField}};
520+
""")!,
521+
ParseMemberDeclaration($$"""
521522
private MySqlDataSource GetDataSource()
522523
{
523524
if ({{dataSourceField}} == null)
524525
throw new InvalidOperationException("ConnectionString is required when not using a transaction");
525526
return {{dataSourceField}}.Value;
526527
}
527-
""")!;
528-
529-
return [fieldDeclaration, getDataSourceMethod];
530-
}
531-
532-
public override MemberDeclarationSyntax? GetDisposeMethodImpl()
533-
{
534-
return ParseMemberDeclaration($$"""
528+
""")!,
529+
ParseMemberDeclaration($$"""
535530
public void Dispose()
536531
{
537532
GC.SuppressFinalize(this);
538-
if ({{Variable.DataSource.AsFieldName()}}?.IsValueCreated == true)
539-
{{Variable.DataSource.AsFieldName()}}.Value.Dispose();
533+
if ({{dataSourceField}}?.IsValueCreated == true)
534+
{{dataSourceField}}.Value.Dispose();
540535
}
541-
""")!;
536+
""")!
537+
];
542538
}
543539

544540
public override CommandGenCommands CreateSqlCommand(string sqlTextConstant)

Drivers/NpgsqlDriver.cs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -570,32 +570,28 @@ public override MemberDeclarationSyntax[] GetAdditionalClassMembers()
570570
{
571571
var dataSourceField = Variable.DataSource.AsFieldName();
572572
var optionalNotNullVerify = Options.DotnetFramework.IsDotnetCore() ? "?" : string.Empty;
573-
var fieldDeclaration = ParseMemberDeclaration($$"""
574-
private readonly Lazy<NpgsqlDataSource>{{optionalNotNullVerify}} {{dataSourceField}};
575-
""")!;
576573

577-
var getDataSourceMethod = ParseMemberDeclaration($$"""
574+
return [
575+
ParseMemberDeclaration($$"""
576+
private readonly Lazy<NpgsqlDataSource>{{optionalNotNullVerify}} {{dataSourceField}};
577+
""")!,
578+
ParseMemberDeclaration($$"""
578579
private NpgsqlDataSource GetDataSource()
579580
{
580581
if ({{dataSourceField}} == null)
581582
throw new InvalidOperationException("ConnectionString is required when not using a transaction");
582583
return {{dataSourceField}}.Value;
583584
}
584-
""")!;
585-
586-
return [fieldDeclaration, getDataSourceMethod];
587-
}
588-
589-
public override MemberDeclarationSyntax? GetDisposeMethodImpl()
590-
{
591-
return ParseMemberDeclaration($$"""
585+
""")!,
586+
ParseMemberDeclaration($$"""
592587
public void Dispose()
593588
{
594589
GC.SuppressFinalize(this);
595-
if ({{Variable.DataSource.AsFieldName()}}?.IsValueCreated == true)
596-
{{Variable.DataSource.AsFieldName()}}.Value.Dispose();
590+
if ({{dataSourceField}}?.IsValueCreated == true)
591+
{{dataSourceField}}.Value.Dispose();
597592
}
598-
""")!;
593+
""")!
594+
];
599595
}
600596

601597
public override CommandGenCommands CreateSqlCommand(string sqlTextConstant)

PluginOptions/Options.cs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,8 @@ public class Options
1111
public Options(GenerateRequest generateRequest)
1212
{
1313
var text = Encoding.UTF8.GetString(generateRequest.PluginOptions.ToByteArray());
14-
// handle empty options case
15-
if (text.Trim() == string.Empty)
14+
if (NoOptionsProvided(text))
1615
text = "{}";
17-
1816
var rawOptions = JsonSerializer.Deserialize<RawOptions>(text) ?? throw new InvalidOperationException();
1917

2018
DriverName = EngineToDriverMapping[generateRequest.Settings.Engine];
@@ -26,13 +24,11 @@ public Options(GenerateRequest generateRequest)
2624
DotnetFramework = DotnetFrameworkExtensions.ParseName(rawOptions.TargetFramework);
2725
Overrides = rawOptions.Overrides ?? [];
2826
WithAsyncSuffix = rawOptions.WithAsyncSuffix;
27+
UseCentralPackageManagement = rawOptions.UseCentralPackageManagement;
2928

3029
if (rawOptions.DebugRequest && generateRequest.Settings.Codegen.Wasm is not null)
3130
throw new ArgumentException("Debug request mode cannot be used with WASM plugin");
3231
DebugRequest = rawOptions.DebugRequest;
33-
34-
UseCentralPackageManagement = rawOptions.UseCentralPackageManagement;
35-
MySqlConnectionReset = rawOptions.MySqlConnectionReset ?? false;
3632
}
3733

3834
public DriverName DriverName { get; }
@@ -61,17 +57,15 @@ public Options(GenerateRequest generateRequest)
6157

6258
public bool WithAsyncSuffix { get; }
6359

64-
/// <summary>
65-
/// When true, connections retrieved from the pool will be reset to a clean state.
66-
/// When false (default), connections maintain their previous state (session variables, temporary tables, etc.).
67-
/// Setting to true adds an extra round trip to the server but ensures clean connection state.
68-
/// </summary>
69-
public bool MySqlConnectionReset { get; }
70-
7160
private static readonly Dictionary<string, DriverName> EngineToDriverMapping = new()
7261
{
7362
{ "mysql", DriverName.MySqlConnector },
7463
{ "postgresql", DriverName.Npgsql },
7564
{ "sqlite", DriverName.Sqlite }
7665
};
66+
67+
private static bool NoOptionsProvided(string optionsText)
68+
{
69+
return optionsText.Trim() == string.Empty;
70+
}
7771
}

PluginOptions/RawOptions.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ public record RawOptions
3434

3535
[JsonPropertyName("withAsyncSuffix")]
3636
public bool WithAsyncSuffix { get; init; } = true;
37-
38-
[JsonPropertyName("mySqlConnectionReset")]
39-
public bool? MySqlConnectionReset { get; init; }
4037
}
4138

4239
public class OverrideOption
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
public static class ReadBenchmarkConsts
2+
{
3+
public const int CustomerCount = 500;
4+
public const int QueriesToRun = 1000;
5+
}
6+
7+
public static class WriteBenchmarkConsts
8+
{
9+
public const int TotalRecords = 2000000;
10+
}

benchmark/BenchmarkRunner/Benchmarks/MysqlReadBenchmark.cs

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ namespace BenchmarkRunner.Benchmarks;
1414
[CategoriesColumn]
1515
public class MysqlReadBenchmark
1616
{
17-
private readonly string _connectionString = Config.GetMysqlConnectionString();
18-
private QuerySql _sqlcImpl = null!;
17+
private static readonly string _connectionString = Config.GetMysqlConnectionString();
18+
private readonly QuerySql _sqlcImpl = new(_connectionString);
19+
private static bool _isInitialized = false;
20+
private static readonly SemaphoreSlim _initLock = new(1, 1);
1921

20-
[Params(500)]
22+
[Params(ReadBenchmarkConsts.CustomerCount)]
2123
public int CustomerCount { get; set; }
2224

23-
[Params(1000)]
25+
[Params(ReadBenchmarkConsts.QueriesToRun)]
2426
public int QueriesToRun { get; set; }
2527

2628
[Params(100, 1000)]
@@ -32,16 +34,27 @@ public class MysqlReadBenchmark
3234
[GlobalSetup]
3335
public async Task GlobalSetup()
3436
{
35-
_sqlcImpl = new(_connectionString);
36-
await MysqlDatabaseHelper.CleanupDatabaseAsync(_connectionString);
37-
var seeder = new MysqlDatabaseSeeder(_connectionString);
38-
await seeder.SeedAsync(
39-
customerCount: CustomerCount, // selectivity: 1/500 of the table returned
40-
productsPerCategory: 150,
41-
ordersPerCustomer: 1000,
42-
itemsPerOrder: 20
43-
// 20 * 1000 = 20,000 possible rows returned
44-
);
37+
if (_isInitialized) return;
38+
await _initLock.WaitAsync();
39+
try
40+
{
41+
if (_isInitialized) return;
42+
43+
await MysqlDatabaseHelper.CleanupDatabaseAsync(_connectionString);
44+
var seeder = new MysqlDatabaseSeeder(_connectionString);
45+
await seeder.SeedAsync(
46+
customerCount: CustomerCount, // selectivity: 1/500 of the table returned
47+
productsPerCategory: 150,
48+
ordersPerCustomer: 1000,
49+
itemsPerOrder: 20
50+
// 20 * 1000 = 20,000 possible rows returned
51+
);
52+
_isInitialized = true;
53+
}
54+
finally
55+
{
56+
_initLock.Release();
57+
}
4558
}
4659

4760
[IterationSetup]
@@ -92,10 +105,4 @@ await seeder.SeedAsync(
92105
));
93106
});
94107
}
95-
96-
[GlobalCleanup]
97-
public async Task GlobalCleanup()
98-
{
99-
await MysqlDatabaseHelper.CleanupDatabaseAsync(_connectionString);
100-
}
101108
}

benchmark/BenchmarkRunner/Benchmarks/MysqlWriteBenchmark.cs

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,53 @@ namespace BenchmarkRunner.Benchmarks;
1515
[CategoriesColumn]
1616
public class MysqlWriteBenchmark
1717
{
18-
private readonly string _connectionString = Config.GetMysqlConnectionString();
19-
private QuerySql _sqlcImpl = null!;
20-
private Queries _efCoreImpl = null!;
18+
private static readonly string _connectionString = Config.GetMysqlConnectionString();
19+
private readonly QuerySql _sqlcImpl = new(_connectionString);
20+
private readonly Queries _efCoreImpl = new(new SalesDbContext(_connectionString), useTracking: false);
2121
private List<QuerySql.AddOrderItemsArgs> _testOrderItems = null!;
22+
private static bool _isInitialized = false;
23+
private static readonly SemaphoreSlim _initLock = new(1, 1);
2224

23-
[Params(2000000)]
25+
[Params(WriteBenchmarkConsts.TotalRecords)]
2426
public int TotalRecords { get; set; }
2527

2628
[Params(100, 500, 1000)]
2729
public int BatchSize { get; set; }
2830

2931
[GlobalSetup]
30-
public void GlobalSetup()
32+
public async Task GlobalSetup()
3133
{
32-
_sqlcImpl = new QuerySql(_connectionString);
33-
_efCoreImpl = new Queries(new SalesDbContext(_connectionString), useTracking: false);
34-
PrepareTestDataAsync().GetAwaiter().GetResult();
34+
if (_isInitialized) return;
35+
await _initLock.WaitAsync();
36+
try
37+
{
38+
if (_isInitialized) return;
39+
40+
await MysqlDatabaseHelper.CleanupDatabaseAsync(_connectionString);
41+
var seeder = new MysqlDatabaseSeeder(_connectionString);
42+
await seeder.SeedAsync(
43+
customerCount: 10,
44+
productsPerCategory: 15,
45+
ordersPerCustomer: 300,
46+
itemsPerOrder: 0
47+
);
48+
49+
var orderIds = await _sqlcImpl.GetOrderIdsAsync(new QuerySql.GetOrderIdsArgs(Limit: 1000));
50+
var productIds = await _sqlcImpl.GetProductIdsAsync(new QuerySql.GetProductIdsArgs(Limit: 1000));
51+
52+
_testOrderItems = [.. Enumerable.Range(0, TotalRecords).Select(i => new QuerySql.AddOrderItemsArgs(
53+
OrderId: orderIds[i % orderIds.Count].OrderId,
54+
ProductId: productIds[i % productIds.Count].ProductId,
55+
Quantity: Random.Shared.Next(1, 10),
56+
UnitPrice: (decimal)(Random.Shared.NextDouble() * 100 + 5)
57+
))];
58+
59+
_isInitialized = true;
60+
}
61+
finally
62+
{
63+
_initLock.Release();
64+
}
3565
}
3666

3767
[IterationSetup]
@@ -41,28 +71,6 @@ public void IterationSetup()
4171
Helpers.InvokeGarbageCollection();
4272
}
4373

44-
private async Task PrepareTestDataAsync()
45-
{
46-
await MysqlDatabaseHelper.CleanupDatabaseAsync(_connectionString);
47-
var seeder = new MysqlDatabaseSeeder(_connectionString);
48-
await seeder.SeedAsync(
49-
customerCount: 10,
50-
productsPerCategory: 15,
51-
ordersPerCustomer: 300,
52-
itemsPerOrder: 0
53-
);
54-
55-
var orderIds = await _sqlcImpl.GetOrderIdsAsync(new QuerySql.GetOrderIdsArgs(Limit: 1000));
56-
var productIds = await _sqlcImpl.GetProductIdsAsync(new QuerySql.GetProductIdsArgs(Limit: 1000));
57-
58-
_testOrderItems = [.. Enumerable.Range(0, TotalRecords).Select(i => new QuerySql.AddOrderItemsArgs(
59-
OrderId: orderIds[i % orderIds.Count].OrderId,
60-
ProductId: productIds[i % productIds.Count].ProductId,
61-
Quantity: Random.Shared.Next(1, 10),
62-
UnitPrice: (decimal)(Random.Shared.NextDouble() * 100 + 5)
63-
))];
64-
}
65-
6674
[BenchmarkCategory("Write")]
6775
[Benchmark(Baseline = true, Description = "SQLC - AddOrderItems")]
6876
public async Task Sqlc_AddOrderItems()
@@ -79,11 +87,4 @@ public async Task EFCore_AddOrderItems()
7987
)).ToList();
8088
await Helpers.InsertInBatchesAsync(args, BatchSize, _efCoreImpl.AddOrderItems);
8189
}
82-
83-
[GlobalCleanup]
84-
public async Task GlobalCleanup()
85-
{
86-
await _efCoreImpl.DbContext.DisposeAsync();
87-
await MysqlDatabaseHelper.CleanupDatabaseAsync(_connectionString);
88-
}
8990
}

0 commit comments

Comments
 (0)