Skip to content

Commit 170ea15

Browse files
authored
feat: Add Benchmarks (#95)
1 parent e4aed8b commit 170ea15

5 files changed

Lines changed: 184 additions & 2 deletions

File tree

Docker.DotNet.slnx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
<File Path="README.md" />
77
</Folder>
88
<Folder Name="/src/">
9+
<File Path="src/Directory.Build.props" />
10+
<File Path="src/Directory.Build.targets" />
911
<Project Path="src/Docker.DotNet.BasicAuth/Docker.DotNet.BasicAuth.csproj" />
1012
<Project Path="src/Docker.DotNet.Handler.Abstractions/Docker.DotNet.Handler.Abstractions.csproj" />
1113
<Project Path="src/Docker.DotNet.LegacyHttp/Docker.DotNet.LegacyHttp.csproj" />
@@ -15,10 +17,9 @@
1517
<Project Path="src/Docker.DotNet.X509/Docker.DotNet.X509.csproj" />
1618
<Project Path="src/Docker.DotNet/Docker.DotNet.csproj" />
1719
<Project Path="src/Microsoft.Net.Http.Client/Microsoft.Net.Http.Client.csproj" />
18-
<File Path="src/Directory.Build.props" />
19-
<File Path="src/Directory.Build.targets" />
2020
</Folder>
2121
<Folder Name="/test/">
22+
<Project Path="test/Docker.DotNet.Benchmarks/Docker.DotNet.Benchmarks.csproj" />
2223
<Project Path="test/Docker.DotNet.Tests/Docker.DotNet.Tests.csproj" />
2324
<Project Path="test/Docker.DotNet.TestsV2/Docker.DotNet.TestsV2.csproj" />
2425
</Folder>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
4+
<OutputType>Exe</OutputType>
5+
<IsPackable>false</IsPackable>
6+
<IsPublishable>false</IsPublishable>
7+
</PropertyGroup>
8+
<PropertyGroup>
9+
<DockerDotNetReleaseVersion Condition="'$(DockerDotNetReleaseVersion)' == ''">3.132.0</DockerDotNetReleaseVersion>
10+
<UseReleasedPackage Condition="'$(UseReleasedPackage)' == ''">false</UseReleasedPackage>
11+
</PropertyGroup>
12+
<ItemGroup>
13+
<PackageReference Include="BenchmarkDotNet" VersionOverride="0.15.8" />
14+
</ItemGroup>
15+
<Choose>
16+
<When Condition="'$(UseReleasedPackage)' == 'true'">
17+
<PropertyGroup>
18+
<DefineConstants>$(DefineConstants);DOCKER_DOTNET_RELEASE</DefineConstants>
19+
</PropertyGroup>
20+
<ItemGroup>
21+
<PackageReference Include="Docker.DotNet.Enhanced" VersionOverride="$(DockerDotNetReleaseVersion)" />
22+
</ItemGroup>
23+
</When>
24+
<Otherwise>
25+
<PropertyGroup>
26+
<DefineConstants>$(DefineConstants);DOCKER_DOTNET_MAIN</DefineConstants>
27+
</PropertyGroup>
28+
<ItemGroup>
29+
<ProjectReference Include="../../src/Docker.DotNet/Docker.DotNet.csproj" />
30+
</ItemGroup>
31+
</Otherwise>
32+
</Choose>
33+
<ItemGroup>
34+
<Using Include="System" />
35+
<Using Include="System.Collections.Generic" />
36+
<Using Include="System.Threading" />
37+
<Using Include="System.Threading.Tasks" />
38+
<Using Include="BenchmarkDotNet.Attributes" />
39+
<Using Include="BenchmarkDotNet.Running" />
40+
<Using Include="Docker.DotNet" />
41+
<Using Include="Docker.DotNet.Benchmarks" />
42+
<Using Include="Docker.DotNet.Models" />
43+
</ItemGroup>
44+
</Project>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
namespace Docker.DotNet.Benchmarks;
2+
3+
[MemoryDiagnoser]
4+
public class DockerDaemonRoundtripBenchmarks
5+
{
6+
private readonly string _imageReference = "busybox:1.37";
7+
8+
private DockerClient _client = null!;
9+
10+
[GlobalSetup]
11+
public async Task GlobalSetup()
12+
{
13+
#if DOCKER_DOTNET_RELEASE
14+
const string implementation = "release";
15+
#else
16+
const string implementation = "main";
17+
#endif
18+
19+
var builder = new DockerClientBuilder();
20+
21+
_client = builder.Build();
22+
23+
Console.WriteLine($"Running daemon round-trip benchmarks against: {implementation}");
24+
25+
await _client.System.PingAsync(CancellationToken.None)
26+
.ConfigureAwait(false);
27+
28+
await EnsureImageExistsAsync()
29+
.ConfigureAwait(false);
30+
}
31+
32+
[GlobalCleanup]
33+
public void GlobalCleanup()
34+
{
35+
_client.Dispose();
36+
}
37+
38+
[Benchmark]
39+
public async Task<int> CreateContainerRequestResponse()
40+
{
41+
var parameters = new CreateContainerParameters();
42+
parameters.Name = $"dockerdotnet-benchmark-{Guid.NewGuid():N}";
43+
parameters.Image = _imageReference;
44+
parameters.Cmd = ["sh", "-c", "sleep 1"];
45+
parameters.Labels = new Dictionary<string, string>();
46+
parameters.Labels.Add("suite", "benchmark");
47+
parameters.Labels.Add("scenario", "create-roundtrip");
48+
49+
var response = await _client.Containers.CreateContainerAsync(parameters, CancellationToken.None)
50+
.ConfigureAwait(false);
51+
52+
try
53+
{
54+
return response.ID.Length;
55+
}
56+
finally
57+
{
58+
await SafeRemoveContainerAsync(response.ID)
59+
.ConfigureAwait(false);
60+
}
61+
}
62+
63+
[Benchmark]
64+
public async Task<bool> StartContainerRequestResponse()
65+
{
66+
var parameters = new CreateContainerParameters();
67+
parameters.Name = $"dockerdotnet-benchmark-{Guid.NewGuid():N}";
68+
parameters.Image = _imageReference;
69+
parameters.Cmd = ["sh", "-c", "exit 0"];
70+
parameters.Labels = new Dictionary<string, string>();
71+
parameters.Labels.Add("suite", "benchmark");
72+
parameters.Labels.Add("scenario", "start-roundtrip");
73+
74+
var response = await _client.Containers.CreateContainerAsync(parameters, CancellationToken.None)
75+
.ConfigureAwait(false);
76+
77+
try
78+
{
79+
return await _client.Containers.StartContainerAsync(response.ID, new ContainerStartParameters(), CancellationToken.None)
80+
.ConfigureAwait(false);
81+
}
82+
finally
83+
{
84+
await SafeRemoveContainerAsync(response.ID)
85+
.ConfigureAwait(false);
86+
}
87+
}
88+
89+
private async Task EnsureImageExistsAsync()
90+
{
91+
var parameters = new ImagesCreateParameters();
92+
parameters.FromImage = _imageReference;
93+
94+
await _client.Images.CreateImageAsync(parameters, new AuthConfig(), new Progress<JSONMessage>(_ => { }), CancellationToken.None)
95+
.ConfigureAwait(false);
96+
}
97+
98+
private async Task SafeRemoveContainerAsync(string containerId)
99+
{
100+
var parameters = new ContainerRemoveParameters();
101+
parameters.Force = true;
102+
103+
try
104+
{
105+
await _client.Containers.RemoveContainerAsync(containerId, parameters, CancellationToken.None)
106+
.ConfigureAwait(false);
107+
}
108+
catch (DockerContainerNotFoundException)
109+
{
110+
}
111+
}
112+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Type[] benchmarks = [typeof(DockerDaemonRoundtripBenchmarks)];
2+
BenchmarkSwitcher.FromTypes(benchmarks).Run(args);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Docker.DotNet Benchmarks
2+
3+
This benchmark project compares the current `main` source code against a released NuGet package by running the same benchmark class twice.
4+
5+
## Run
6+
7+
From the repository root, run `main` first:
8+
9+
```bash
10+
dotnet run -c Release --project test/Docker.DotNet.Benchmarks/Docker.DotNet.Benchmarks.csproj -- --filter '*DockerDaemonRoundtripBenchmarks*'
11+
```
12+
13+
Then run the released NuGet package implementation:
14+
15+
```bash
16+
dotnet run -c Release --project test/Docker.DotNet.Benchmarks/Docker.DotNet.Benchmarks.csproj -p:UseReleasedPackage=true -- --filter '*DockerDaemonRoundtripBenchmarks*'
17+
```
18+
19+
To compare against a different release tag/package version:
20+
21+
```bash
22+
dotnet run -c Release --project test/Docker.DotNet.Benchmarks/Docker.DotNet.Benchmarks.csproj -p:UseReleasedPackage=true -p:DockerDotNetReleaseVersion=3.132.0 -- --filter '*DockerDaemonRoundtripBenchmarks*'
23+
```

0 commit comments

Comments
 (0)