Skip to content

Commit

Permalink
Work done on benchmarking
Browse files Browse the repository at this point in the history
  • Loading branch information
frankhaugen committed Mar 4, 2024
1 parent d28976d commit 947f74c
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 2 deletions.
4 changes: 4 additions & 0 deletions Frank.Testing.Logging/SimpleTestLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ public class SimpleTestLoggerProvider(ITestOutputHelper outputHelper, IOptions<L
{
private readonly ConcurrentDictionary<string, SimpleTestLogger> _loggers = new();

public SimpleTestLoggerProvider(ITestOutputHelper outputHelper): this(outputHelper, Options.Create<LoggerFilterOptions>(new LoggerFilterOptions() { MinLevel = LogLevel.Information }))
{
}

/// <inheritdoc />
public void Dispose() => _loggers.Clear();

Expand Down
3 changes: 3 additions & 0 deletions Frank.Testing.TestBases/Frank.Testing.TestBases.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.dotTrace" Version="0.13.12" />
<PackageReference Include="BenchmarkDotNetVisualizer" Version="1.0.5" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="xunit.extensibility.core" Version="2.7.0" />
</ItemGroup>
Expand Down
36 changes: 36 additions & 0 deletions Frank.Testing.TestBases/HostApplicationBenchmarkBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Globalization;

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Exporters.Csv;
using BenchmarkDotNet.Exporters.Json;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

using Perfolizer.Horology;

namespace Frank.Testing.TestBases;

public abstract class HostApplicationBenchmarkBase : HostApplicationTestBase
{
/// <inheritdoc />
protected HostApplicationBenchmarkBase(ILoggerProvider loggerProvider) : base(loggerProvider, LogLevel.Information)
{
}

/// <summary>
/// Run a benchmark of the specified type and return the summary.
/// </summary>
/// <returns></returns>
protected Summary RunBenchmarks<T>(IConfig config) where T : class
{
return BenchmarkRunner.Run<T>(config);
}
}
36 changes: 36 additions & 0 deletions Frank.Testing.TestBases/StringDelegateBenchmarkLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Text;

using BenchmarkDotNet.Loggers;

namespace Frank.Testing.TestBases;

public class StringDelegateBenchmarkLogger(Action<string> output) : ILogger
{
private readonly StringBuilder _stringBuilder = new();

/// <inheritdoc />
public void Write(LogKind logKind, string text) => _stringBuilder.Append(text);

/// <inheritdoc />
public void WriteLine()
{
output(_stringBuilder.ToString());
_stringBuilder.Clear();
}

/// <inheritdoc />
public void WriteLine(LogKind logKind, string text) => _stringBuilder.AppendLine(text);

/// <inheritdoc />
public void Flush()
{
output(_stringBuilder.ToString());
_stringBuilder.Clear();
}

/// <inheritdoc />
public string Id { get; set; } = string.Empty;

/// <inheritdoc />
public int Priority { get; set; } = 0;
}
88 changes: 88 additions & 0 deletions Frank.Testing.Tests/TestBases/HostApplicationBenchmarkBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System.Diagnostics;
using System.Text;

using BenchmarkDotNet.Analysers;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Characteristics;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Exporters.Csv;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Loggers;

using BenchmarkDotNetVisualizer;

using Frank.Testing.Logging;
using Frank.Testing.TestBases;

using Xunit.Abstractions;

namespace Frank.Testing.Tests.TestBases;

public class HostApplicationBenchmarkBaseTests : HostApplicationBenchmarkBase
{
private readonly ITestOutputHelper _testOutputHelper;

/// <inheritdoc />
public HostApplicationBenchmarkBaseTests(ITestOutputHelper testOutputHelper) : base(new SimpleTestLoggerProvider(testOutputHelper))
{
_testOutputHelper = testOutputHelper;
}


[Fact]
public async Task Test1()
{
// Arrange

// Act
var summary = RunBenchmarks<TestBenchmark>(new DebugInProcessConfig()
.AddDiagnoser(MemoryDiagnoser.Default, new DisassemblyDiagnoser(new DisassemblyDiagnoserConfig()), ThreadingDiagnoser.Default)
.AddExporter(HtmlExporter.Default, CsvExporter.Default, MarkdownExporter.GitHub)
.AddAnalyser(OutliersAnalyser.Default, EnvironmentAnalyser.Default, MultimodalDistributionAnalyzer.Default, ZeroMeasurementAnalyser.Default)
.AddHardwareCounters(HardwareCounter.BranchMispredictions, HardwareCounter.BranchInstructions, HardwareCounter.CacheMisses, HardwareCounter.TotalCycles, HardwareCounter.Timer)
.AddLogger(new StringDelegateBenchmarkLogger(_testOutputHelper.WriteLine))
);

// Assert
// var html = summary.GetMarkdown(new ReportMarkdownOptions()
// {
// Title = "TestBenchmark"
// });
//
// _testOutputHelper.WriteLine(html);
}

[HardwareCounters(
HardwareCounter.BranchMispredictions,
HardwareCounter.BranchInstructions)]
public class TestBenchmark
{
[Benchmark]
public void Run()
{
var result = 1f + 1f + 1f;
}
}
}

public class XUnitBenchmarkConfiguration : ManualConfig
{
public XUnitBenchmarkConfiguration(ILogger? benchmarkLogger = null)
{
if (benchmarkLogger != null)
AddLogger(benchmarkLogger);

AddJob(Job.ShortRun);
AddExporter(HtmlExporter.Default, new RichMarkdownExporter(new ReportMarkdownOptions()
{
Title = "Benchmark"
}));
AddDiagnoser(MemoryDiagnoser.Default, new DisassemblyDiagnoser(new DisassemblyDiagnoserConfig()), ThreadingDiagnoser.Default);
WithOptions(ConfigOptions.DisableOptimizationsValidator);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -29,9 +30,19 @@ protected override Task SetupApplicationAsync(WebApplication application)
{
application.UseRouting();
application.MapControllers();
application.MapGet("/test1", async httpContext =>
application.MapGet("/test1/{id}/test2/{id2}",
async httpContext =>
{
await httpContext.Response.WriteAsync("Test1 endpoint");
});
application.MapDelete("/test1/{id}/test2/{id2}",
async (HttpContext httpContext, string id, string id2) =>
{
await httpContext.Response.WriteAsync("Test1 endpoint");
});
application.MapGet("/test2", async httpContext =>
{
await httpContext.Response.WriteAsync("Test1 endpoint");
await httpContext.Response.WriteAsync("Test2 endpoint");
});
return Task.CompletedTask;
}
Expand All @@ -46,6 +57,8 @@ public async Task Test()
var myServiceLogger = GetServices.GetRequiredService<ILogger<MyService>>();
var inMemoryLogger = myServiceLogger as InMemoryLogger<MyService>;
inMemoryLogger?.GetLogEntries().Should().Contain(log => log.Message == "DoSomething");

outputHelper.WriteTable(GetEndpoints.Cast<RouteEndpoint>().Select(route => new {Name = route.DisplayName, Method = route.Metadata.GetMetadata<HttpMethodMetadata>()!.HttpMethods.FirstOrDefault(), route.RoutePattern.RawText}));
}
}

Expand Down

0 comments on commit 947f74c

Please sign in to comment.