Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
warning-explosive committed Nov 26, 2023
1 parent 284833d commit 86eeb39
Show file tree
Hide file tree
Showing 278 changed files with 19,021 additions and 0 deletions.
21 changes: 21 additions & 0 deletions tests/Benchmarks/Benchmark.Api/Benchmark.Api.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<AssemblyName>SpaceEngineers.Core.Benchmark.Api</AssemblyName>
<RootNamespace>SpaceEngineers.Core.Benchmark.Api</RootNamespace>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.6"/>
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

</Project>
181 changes: 181 additions & 0 deletions tests/Benchmarks/Benchmark.Api/Benchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
namespace SpaceEngineers.Core.Benchmark.Api
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Validators;
using Perfolizer.Horology;

/// <summary>
/// Benchmark entry point
/// </summary>
[SuppressMessage("Analysis", "CA1724", Justification = "desired name")]
public static class Benchmark
{
/// <summary>
/// Benchmark entry point method
/// </summary>
/// <param name="output">Output</param>
/// <typeparam name="TSource">TSource type-argument</typeparam>
/// <returns>Benchmark summary</returns>
public static Summary Run<TSource>(Action<string> output)
{
var summary = BenchmarkRunner.Run<TSource>();

output(summary.Title);
output($"TotalTime: {summary.TotalTime.ToString()}");
output($"Details in: {summary.LogFilePath}");

if (summary.HasCriticalValidationErrors)
{
var errors = ((IEnumerable<ValidationError>)summary.ValidationErrors)
.Select(error => new InvalidOperationException(error.ToString()))
.ToList();

throw new AggregateException(errors);
}

return summary;
}

/// <summary>
/// Gets time measure in seconds from benchmark summary
/// </summary>
/// <param name="summary">Summary</param>
/// <param name="measureRecordName">Measure record name</param>
/// <param name="measure">Measure</param>
/// <param name="output">Output</param>
/// <returns>Seconds time measure</returns>
public static decimal SecondMeasure(
this Summary summary,
string measureRecordName,
Measure measure,
Action<string> output)
{
return summary.TimeMeasure(
TimeUnit.Second,
measureRecordName,
measure,
output);
}

/// <summary>
/// Gets time measure in milliseconds from benchmark summary
/// </summary>
/// <param name="summary">Summary</param>
/// <param name="measureRecordName">Measure record name</param>
/// <param name="measure">Measure</param>
/// <param name="output">Output</param>
/// <returns>Milliseconds time measure</returns>
public static decimal MillisecondMeasure(
this Summary summary,
string measureRecordName,
Measure measure,
Action<string> output)
{
return summary.TimeMeasure(
TimeUnit.Millisecond,
measureRecordName,
measure,
output);
}

/// <summary>
/// Gets time measure in nanoseconds from benchmark summary
/// </summary>
/// <param name="summary">Summary</param>
/// <param name="measureRecordName">Measure record name</param>
/// <param name="measure">Measure</param>
/// <param name="output">Output</param>
/// <returns>Nanoseconds time measure</returns>
public static decimal NanosecondMeasure(
this Summary summary,
string measureRecordName,
Measure measure,
Action<string> output)
{
return summary.TimeMeasure(
TimeUnit.Nanosecond,
measureRecordName,
measure,
output);
}

/// <summary>
/// Gets time measure from benchmark summary
/// </summary>
/// <param name="summary">Summary</param>
/// <param name="timeUnit">TimeUnit</param>
/// <param name="measureRecordName">Measure record name</param>
/// <param name="measure">Measure</param>
/// <param name="output">Output</param>
/// <returns>Time measure</returns>
public static decimal TimeMeasure(
this Summary summary,
TimeUnit timeUnit,
string measureRecordName,
Measure measure,
Action<string> output)
{
var timeMeasure = summary.TimeMeasures(measure, timeUnit)[measureRecordName];

output($"{measureRecordName} -> {measure} -> {timeMeasure} {timeUnit.Name}");

return timeMeasure;
}

private static IDictionary<string, decimal> TimeMeasures(
this Summary summary,
Measure measure,
TimeUnit timeUnit)
{
var measureColumnName = measure.ToString();

var methodColumn = summary.Column("Method");
var measureColumn = summary.Column(measureColumnName);

if (!measureColumn.IsNumeric)
{
throw new InvalidOperationException($"{measureColumnName} isn't numeric");
}

var style = new SummaryStyle(CultureInfo.InvariantCulture,
false,
SizeUnit.B,
timeUnit,
false,
true);

return summary
.BenchmarksCases
.ToDictionary(benchmarksCase => methodColumn.GetValue(summary, benchmarksCase),
ParseTime(summary, methodColumn, measureColumn, measureColumnName, timeUnit, style));

static Func<BenchmarkCase, decimal> ParseTime(
Summary summary,
IColumn methodColumn,
IColumn measureColumn,
string measureColumnName,
TimeUnit timeUnit,
SummaryStyle style)
{
return benchmarkCase =>
{
var measure = measureColumn.GetValue(summary, benchmarkCase, style);
return decimal.Parse(measure, CultureInfo.InvariantCulture);
};
}
}

private static IColumn Column(this Summary summary, string columnName)
{
return summary.GetColumns().Single(col => col.ColumnName == columnName);
}
}
}
13 changes: 13 additions & 0 deletions tests/Benchmarks/Benchmark.Api/Measure.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace SpaceEngineers.Core.Benchmark.Api
{
/// <summary>
/// Measure
/// </summary>
public enum Measure
{
/// <summary>
/// Mean
/// </summary>
Mean
}
}
5 changes: 5 additions & 0 deletions tests/Benchmarks/Benchmark.Api/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using System.Reflection;

[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0.0")]
154 changes: 154 additions & 0 deletions tests/Benchmarks/GenericHost.Benchmark/Benchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
namespace SpaceEngineers.Core.GenericHost.Benchmark
{
using System.Threading.Tasks;
using Core.Benchmark.Api;
using Sources;
using Test.Api;
using Test.Api.ClassFixtures;
using Xunit;
using Xunit.Abstractions;

/// <summary>
/// Benchmarks
/// </summary>
// TODO: #136 - remove magic numbers and use adaptive approach -> store test artifacts in DB and search performance change points
public class Benchmarks : TestBase
{
/// <summary> .cctor </summary>
/// <param name="output">ITestOutputHelper</param>
/// <param name="fixture">TestFixture</param>
public Benchmarks(ITestOutputHelper output, TestFixture fixture)
: base(output, fixture)
{
}

[Fact(Timeout = 300_000)]
internal void DatabaseConnectionProviderBenchmark()
{
var summary = Benchmark.Run<DatabaseConnectionProviderBenchmarkSource>(Output.WriteLine);

var read = summary.MillisecondMeasure(
nameof(DatabaseConnectionProviderBenchmarkSource.Read),
Measure.Mean,
Output.WriteLine);

var insert = summary.MillisecondMeasure(
nameof(DatabaseConnectionProviderBenchmarkSource.Insert),
Measure.Mean,
Output.WriteLine);

var delete = summary.MillisecondMeasure(
nameof(DatabaseConnectionProviderBenchmarkSource.Delete),
Measure.Mean,
Output.WriteLine);

Assert.True(read < 25m);
Assert.True(insert < 25m);
Assert.True(delete < 25m);
}

[Fact(Timeout = 300_000)]
internal static async Task DatabaseConnectionProviderBenchmarkTest()
{
var source = new DatabaseConnectionProviderBenchmarkSource();

try
{
source.GlobalSetup();

for (var i = 0; i < 1000; i++)
{
source.IterationSetup();

await source.Read().ConfigureAwait(false);
await source.Insert().ConfigureAwait(false);
await source.Delete().ConfigureAwait(false);

source.IterationCleanup();
}
}
finally
{
source.GlobalCleanup();
}
}

[Fact(Timeout = 300_000)]
internal void MessageHandlerMiddlewareBenchmark()
{
var summary = Benchmark.Run<MessageHandlerMiddlewareBenchmarkSource>(Output.WriteLine);

var compositeMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunCompositeMiddleware),
Measure.Mean,
Output.WriteLine);

var tracingMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunTracingMiddleware),
Measure.Mean,
Output.WriteLine);

var errorHandlingMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunErrorHandlingMiddleware),
Measure.Mean,
Output.WriteLine);

var authorizationMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunAuthorizationMiddleware),
Measure.Mean,
Output.WriteLine);

var unitOfWorkMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunUnitOfWorkMiddleware),
Measure.Mean,
Output.WriteLine);

var handledByEndpointMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunHandledByEndpointMiddleware),
Measure.Mean,
Output.WriteLine);

var requestReplyMiddleware = summary.MillisecondMeasure(
nameof(MessageHandlerMiddlewareBenchmarkSource.RunRequestReplyMiddleware),
Measure.Mean,
Output.WriteLine);

Assert.True(compositeMiddleware < 50m);
Assert.True(tracingMiddleware < 1m);
Assert.True(errorHandlingMiddleware < 1m);
Assert.True(authorizationMiddleware < 1m);
Assert.True(unitOfWorkMiddleware < 25m);
Assert.True(handledByEndpointMiddleware < 1m);
Assert.True(requestReplyMiddleware < 1m);
}

[Fact(Timeout = 300_000)]
internal static async Task MessageHandlerMiddlewareBenchmarkTest()
{
var source = new MessageHandlerMiddlewareBenchmarkSource();

try
{
source.GlobalSetup();

for (var i = 0; i < 1000; i++)
{
source.IterationSetup();

await source.RunTracingMiddleware().ConfigureAwait(false);
await source.RunErrorHandlingMiddleware().ConfigureAwait(false);
await source.RunAuthorizationMiddleware().ConfigureAwait(false);
await source.RunUnitOfWorkMiddleware().ConfigureAwait(false);
await source.RunHandledByEndpointMiddleware().ConfigureAwait(false);
await source.RunRequestReplyMiddleware().ConfigureAwait(false);

source.IterationCleanup();
}
}
finally
{
source.GlobalCleanup();
}
}
}
}
Loading

0 comments on commit 86eeb39

Please sign in to comment.