Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5634d4a
extract out an ICrdtRepository.cs interface
hahn-kev Jul 23, 2025
e6ff74c
create benchmarks project to enable dedicated running on benchmarks
hahn-kev Jul 23, 2025
c2d3c5f
setup git job comparison
hahn-kev Jul 23, 2025
04c6e4d
replace CrdtRepositoryFactory with ICrdtRepositoryFactory
hahn-kev Jul 23, 2025
8e08b90
introduce some more benchmarks and initial version of Linq2Db repo
hahn-kev Jul 24, 2025
a395f7a
make commit hash updates explicit
hahn-kev Jul 24, 2025
7cefd25
add debug logging
hahn-kev Jul 24, 2025
3367d9f
make debugging easier
hahn-kev Jul 24, 2025
7b35041
add more repo tests to find bugs with the new repo
hahn-kev Jul 24, 2025
b5e9eb6
fix an issue with one test expecting the returned commit to have the …
hahn-kev Jul 24, 2025
426bf8c
add 2 benchmarks, one for all at once
hahn-kev Jul 24, 2025
2f3cfc6
don't use logging during a perf test, add a DataModelTestBase.cs conf…
hahn-kev Jul 24, 2025
4a304a1
always run repo tests for both versions
hahn-kev Jul 24, 2025
9a9901a
add dotTrace for easy profiling
hahn-kev Jul 24, 2025
53a46ed
use new package version
hahn-kev Jul 24, 2025
7c3b8d2
remove extra check projecting entities
hahn-kev Jul 24, 2025
e29dd8e
add a second benchmark for all changes
hahn-kev Jul 24, 2025
9ad734c
disable linq2db logging when running as part of a perf test
hahn-kev Aug 28, 2025
d7414c3
increase change count in add change benchmarks
hahn-kev Aug 28, 2025
c593cc0
add test for `GetCurrentSnapshotByObjectId` and change it to use a co…
hahn-kev Aug 28, 2025
cd78ec9
lower dotnet version used for benchmarks
hahn-kev Aug 29, 2025
54e7357
Merge branch 'main' into create-linq2db-repository
hahn-kev Aug 29, 2025
733b622
resolve merge conflicts
hahn-kev Aug 29, 2025
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
18 changes: 11 additions & 7 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.4" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.4" />
<PackageVersion Include="BenchmarkDotNet.Diagnostics.dotMemory" Version="0.15.2" />
<PackageVersion Include="BenchmarkDotNet.Diagnostics.dotTrace" Version="0.15.2" />
<PackageVersion Include="Enterprize1.BenchmarkDotNet.GitCompare" Version="0.0.1" />
<PackageVersion Include="linq2db.Extensions" Version="6.0.0-rc.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="9.0.7" />
<PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="9.0.7" />
<PackageVersion Include="Nito.AsyncEx.Coordination" Version="5.1.2" />
<PackageVersion Include="System.IO.Hashing" Version="9.0.0" />
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
<PackageVersion Include="BenchmarkDotNet" Version="0.15.2" />
<PackageVersion Include="FluentAssertions" Version="7.0.0-alpha.6" />
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1" />
<PackageVersion Include="JetBrains.Profiler.SelfApi" Version="2.5.12" />
Expand All @@ -22,7 +27,6 @@
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.12.19" />
<PackageVersion Include="linq2db.AspNet" Version="5.4.1" />
<PackageVersion Include="linq2db.EntityFrameworkCore" Version="9.0.0" />
<PackageVersion Include="linq2db.EntityFrameworkCore" Version="9.1.0-rc.1" />
</ItemGroup>
</Project>
</Project>
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,10 @@ NuGet package versions are calculated from a combination of tags and commit mess
* `+semver: minor` or `+semver: feature` - update minor version number, reset patch to 0 (so 2.3.1 would become 2.4.0)
* Anything else, including no `+semver` lines at all - update patch version number (so 2.3.1 would become 2.3.2)
* If you want to include `+semver` lines, then `+semver: patch` or `+semver: fix` are the standard ways to increment a patch version bump, but the patch version will be bumped regardless as long as there is at least one commit since the most recent tag.

### Run benchmarks

docs: https://benchmarkdotnet.org/articles/guides/console-args.html
```bash
dotnet run --project ./src/SIL.Harmony.Benchmarks/SIL.Harmony.Benchmarks.csproj -c Release -- --filter *
```
Comment on lines +190 to +195
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Fix markdownlint MD034 and align run command with CI SDK.

  • Replace bare URL with a markdown link.
  • CI fails on net9.0; document running benchmarks with net8.0 to match the pipeline until SDK is upgraded.
-### Run benchmarks
-
-docs: https://benchmarkdotnet.org/articles/guides/console-args.html
-```bash
-dotnet run --project ./src/SIL.Harmony.Benchmarks/SIL.Harmony.Benchmarks.csproj -c Release -- --filter *
-```
+### Run benchmarks
+
+[Docs: BenchmarkDotNet console args](https://benchmarkdotnet.org/articles/guides/console-args.html)
+```bash
+dotnet run --project ./src/SIL.Harmony.Benchmarks/SIL.Harmony.Benchmarks.csproj -c Release -f net8.0 -- --filter *
+```
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

192-192: Bare URL used

(MD034, no-bare-urls)

🤖 Prompt for AI Agents
In README.md around lines 190 to 195, replace the bare URL with a proper
markdown link and update the example run command to target net8.0 to match CI;
specifically, change the docs line to a linked text ("Docs: BenchmarkDotNet
console args" linking to the provided URL) and modify the dotnet run command to
include the framework option (e.g., -f net8.0) so the command matches the CI SDK
until the pipeline is upgraded.

6 changes: 6 additions & 0 deletions harmony.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
src\.editorconfig = src\.editorconfig
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SIL.Harmony.Benchmarks", "src\SIL.Harmony.Benchmarks\SIL.Harmony.Benchmarks.csproj", "{96FABEBB-5A18-46D5-8530-84B9FFF5442C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -54,5 +56,9 @@ Global
{8EB807F6-C548-4016-856E-2ACCA5603036}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EB807F6-C548-4016-856E-2ACCA5603036}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EB807F6-C548-4016-856E-2ACCA5603036}.Release|Any CPU.Build.0 = Release|Any CPU
{96FABEBB-5A18-46D5-8530-84B9FFF5442C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96FABEBB-5A18-46D5-8530-84B9FFF5442C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96FABEBB-5A18-46D5-8530-84B9FFF5442C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{96FABEBB-5A18-46D5-8530-84B9FFF5442C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
56 changes: 56 additions & 0 deletions src/SIL.Harmony.Benchmarks/AddChangeBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using BenchmarkDotNet_GitCompare;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnostics.dotMemory;
using BenchmarkDotNet.Diagnostics.dotTrace;
using BenchmarkDotNet.Engines;
using SIL.Harmony.Linq2db;
using SIL.Harmony.Tests;

namespace SIL.Harmony.Benchmarks;

[SimpleJob(RunStrategy.Throughput)]
[MemoryDiagnoser]
// [DotMemoryDiagnoser]
// [DotTraceDiagnoser]
// [GitJob(gitReference: "HEAD", id: "before", baseline: true)]
public class AddChangeBenchmarks
{
private DataModelTestBase _emptyDataModel = null!;
private Guid _clientId = Guid.NewGuid();
public const int ActualChangeCount = 2000;
[Params(true, false)]
public bool UseLinq2DbRepo { get; set; }

[IterationSetup]
public void IterationSetup()
{
_emptyDataModel = new(alwaysValidate: false, performanceTest: true, useLinq2DbRepo: UseLinq2DbRepo);
_emptyDataModel.WriteNextChange(_emptyDataModel.SetWord(Guid.NewGuid(), "entity1")).GetAwaiter().GetResult();
}

[Benchmark(OperationsPerInvoke = ActualChangeCount)]
public List<Commit> AddChanges()
{
var commits = new List<Commit>();
for (var i = 0; i < ActualChangeCount; i++)
{
commits.Add(_emptyDataModel.WriteNextChange(_emptyDataModel.SetWord(Guid.NewGuid(), "entity1")).Result);
}

return commits;
}

[Benchmark(OperationsPerInvoke = ActualChangeCount)]
public Commit AddChangesAllAtOnce()
{
return _emptyDataModel.WriteChange(_clientId, DateTimeOffset.Now, Enumerable.Range(0, ActualChangeCount)
.Select(i =>
_emptyDataModel.SetWord(Guid.NewGuid(), "entity1"))).Result;
}

[IterationCleanup]
public void IterationCleanup()
{
_emptyDataModel.DisposeAsync().GetAwaiter().GetResult();
}
}
79 changes: 79 additions & 0 deletions src/SIL.Harmony.Benchmarks/AddSnapshotsBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using BenchmarkDotNet_GitCompare;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Engines;
using Microsoft.Extensions.DependencyInjection;
using SIL.Harmony.Core;
using SIL.Harmony.Db;
using SIL.Harmony.Linq2db;
using SIL.Harmony.Sample.Models;
using SIL.Harmony.Tests;

namespace SIL.Harmony.Benchmarks;

[SimpleJob(RunStrategy.Throughput)]
[MemoryDiagnoser]
// [GitJob(gitReference: "HEAD", id: "before", baseline: true)]
public class AddSnapshotsBenchmarks
{
private DataModelTestBase _emptyDataModel = null!;
private ICrdtRepository _repository = null!;
private Commit _commit = null!;

[Params(1000)]
public int SnapshotCount { get; set; }

[Params(true, false)]
public bool UseLinq2DbRepo { get; set; }

[IterationSetup]
public void IterationSetup()
{
_emptyDataModel = new(alwaysValidate: false,
performanceTest: true, useLinq2DbRepo: UseLinq2DbRepo);
var crdtRepositoryFactory = _emptyDataModel.Services.GetRequiredService<ICrdtRepositoryFactory>();
_repository = crdtRepositoryFactory.CreateRepositorySync();
_repository.AddCommit(_commit = new Commit(Guid.NewGuid())
{
ClientId = Guid.NewGuid(),
HybridDateTime = new HybridDateTime(DateTimeOffset.Now, 0),
}).GetAwaiter().GetResult();
}

[Benchmark(OperationsPerInvoke = 1000)]
public void AddSnapshotsOneAtATime()
{
for (var i = 0; i < SnapshotCount; i++)
{
_repository.AddSnapshots([
new ObjectSnapshot(new Word()
{
Id = Guid.NewGuid(),
Text = "test",
}, _commit, true)
]).GetAwaiter().GetResult();
}
}

[Benchmark(OperationsPerInvoke = 1000)]
public void AddSnapshotsAllAtOnce()
{
var snapshots = Enumerable.Range(0, SnapshotCount)
.Select(i => new ObjectSnapshot(new Word()
{
Id = Guid.NewGuid(),
Text = "test",
},
_commit,
true))
.ToArray();

_repository.AddSnapshots(snapshots).GetAwaiter().GetResult();
}

[IterationCleanup]
public void IterationCleanup()
{
_repository.Dispose();
_emptyDataModel.DisposeAsync().GetAwaiter().GetResult();
}
}
4 changes: 4 additions & 0 deletions src/SIL.Harmony.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using BenchmarkDotNet.Running;
using SIL.Harmony.Tests.Benchmarks;

BenchmarkSwitcher.FromAssemblies([typeof(Program).Assembly, typeof(ChangeThroughput).Assembly]).Run(args);
21 changes: 21 additions & 0 deletions src/SIL.Harmony.Benchmarks/SIL.Harmony.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.dotMemory" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.dotTrace" />
<PackageReference Include="Enterprize1.BenchmarkDotNet.GitCompare" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\SIL.Harmony.Tests\SIL.Harmony.Tests.csproj" />
</ItemGroup>

</Project>
Loading
Loading