add benchmark project

This commit is contained in:
Renjaya Raga Zenta 2025-07-31 00:35:43 +07:00
parent 1456503a3f
commit 72c644a37e
8 changed files with 198 additions and 2 deletions

View file

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.2" />
<PackageReference Include="NSubstitute" Version="5.3.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Oh.My.Stitcher\Oh.My.Stitcher.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,45 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using NetVips;
using Oh.My.Stitcher.NetVips;
namespace Oh.My.Stitcher.Benchmark;
[SimpleJob(RuntimeMoniker.Net80)]
[MemoryDiagnoser]
public class OperationBenchmark
{
// CHANGE ME
private const string TILES_DIRECTORY = "/home/formulatrix/Downloads/tiles1705";
[Benchmark(Baseline = true)] // Mark this as the baseline for comparison
public void Standard_Operation()
{
const string rect = "A1:AE55";
if( !Tile.TryParseRect(rect, out int minRow, out int maxRow, out int minCol, out int maxCol) )
throw new ArgumentException($"Invalid canvas_rect: '{rect}'");
for( int row = minRow; row <= maxRow; row++ )
for( int col = minCol; col <= maxCol; col++ )
{
string path = Tile.FullPath(TILES_DIRECTORY, row, col);
using var i = ( Operation.Call("pngload", path) as Image )!;
}
}
[Benchmark]
public void Fast_Operation()
{
const string rect = "A1:AE55";
if( !Tile.TryParseRect(rect, out int minRow, out int maxRow, out int minCol, out int maxCol) )
throw new ArgumentException($"Invalid canvas_rect: '{rect}'");
Span<byte> pathBuffer = stackalloc byte[512];
for( int row = minRow; row <= maxRow; row++ )
for( int col = minCol; col <= maxCol; col++ )
{
int length = Tile.FullPathFast(TILES_DIRECTORY, row, col, pathBuffer);
using var i = ( OperationHacks.Call("pngload", pathBuffer.Slice(0, length + 1)) as Image )!;
}
}
}

View file

@ -0,0 +1,41 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
namespace Oh.My.Stitcher.Benchmark;
[SimpleJob(RuntimeMoniker.Net80)]
[MemoryDiagnoser]
public class PathCreationBenchmark
{
// CHANGE ME
private const string TILES_DIRECTORY = "/home/formulatrix/Downloads/tiles1705";
[Benchmark(Baseline = true)] // Mark this as the baseline for comparison
public void Standard_PathCombine()
{
const string rect = "A1:AE55";
if( !Tile.TryParseRect(rect, out int minRow, out int maxRow, out int minCol, out int maxCol) )
throw new ArgumentException($"Invalid canvas_rect: '{rect}'");
for( int row = minRow; row <= maxRow; row++ )
for( int col = minCol; col <= maxCol; col++ )
{
Tile.FullPath(TILES_DIRECTORY, row, col);
}
}
[Benchmark]
public void Fast_PathCombine()
{
const string rect = "A1:AE55";
if( !Tile.TryParseRect(rect, out int minRow, out int maxRow, out int minCol, out int maxCol) )
throw new ArgumentException($"Invalid canvas_rect: '{rect}'");
Span<byte> pathBuffer = stackalloc byte[512];
for( int row = minRow; row <= maxRow; row++ )
for( int col = minCol; col <= maxCol; col++ )
{
Tile.FullPathFast(TILES_DIRECTORY, row, col, pathBuffer);
}
}
}

View file

@ -0,0 +1,13 @@
using BenchmarkDotNet.Running;
namespace Oh.My.Stitcher.Benchmark;
static class Program
{
static void Main(string[] _)
{
BenchmarkRunner.Run<PathCreationBenchmark>();
BenchmarkRunner.Run<OperationBenchmark>();
BenchmarkRunner.Run<UsageBenchmark>();
}
}

View file

@ -0,0 +1,62 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using NetVips;
using NSubstitute;
namespace Oh.My.Stitcher.Benchmark;
[SimpleJob(RuntimeMoniker.Net80)]
[MemoryDiagnoser]
public class UsageBenchmark
{
// CHANGE ME
private const string TILES_DIRECTORY = "/home/formulatrix/Downloads/tiles1705";
[Benchmark(Baseline = true)] // Mark this as the baseline for comparison
public void Standard_Usage()
{
Stitch request = new()
{
CanvasRect = "A1:AE55", CropOffset = new CropOffset(0, 0), CropSize = new CropSize(1, 1), OutputScale = 1
};
Image? image = null;
List<Image> images = [];
IMemoryCache cache = Substitute.For<IMemoryCache>();
ILogger logger = Substitute.For<ILogger>();
try
{
Tile.TryCreate(in request, TILES_DIRECTORY, images, logger, cache, out image, out string? _, out string? _);
}
finally
{
image?.Dispose();
foreach( Image img in images )
img.Dispose();
}
}
[Benchmark]
public void Fast_Usage()
{
Stitch request = new()
{
CanvasRect = "A1:AE55", CropOffset = new CropOffset(0, 0), CropSize = new CropSize(1, 1), OutputScale = 1
};
Image? image = null;
List<Image> images = [];
IMemoryCache cache = Substitute.For<IMemoryCache>();
ILogger logger = Substitute.For<ILogger>();
try
{
Tile.TryCreateFast(in request, TILES_DIRECTORY, images, logger, cache, out image, out string? _, out string? _);
}
finally
{
image?.Dispose();
foreach( Image img in images )
img.Dispose();
}
}
}