diff --git a/.gitignore b/.gitignore index add57be..8b3bbe2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin/ obj/ /packages/ riderModule.iml -/_ReSharper.Caches/ \ No newline at end of file +/_ReSharper.Caches/ +*Artifacts/ diff --git a/src/Oh.My.Stitcher.Benchmark/Oh.My.Stitcher.Benchmark.csproj b/src/Oh.My.Stitcher.Benchmark/Oh.My.Stitcher.Benchmark.csproj new file mode 100644 index 0000000..be0402a --- /dev/null +++ b/src/Oh.My.Stitcher.Benchmark/Oh.My.Stitcher.Benchmark.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/src/Oh.My.Stitcher.Benchmark/OperationBenchmark.cs b/src/Oh.My.Stitcher.Benchmark/OperationBenchmark.cs new file mode 100644 index 0000000..80cfff6 --- /dev/null +++ b/src/Oh.My.Stitcher.Benchmark/OperationBenchmark.cs @@ -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 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 )!; + } + } +} diff --git a/src/Oh.My.Stitcher.Benchmark/PathCreationBenchmark.cs b/src/Oh.My.Stitcher.Benchmark/PathCreationBenchmark.cs new file mode 100644 index 0000000..08be29f --- /dev/null +++ b/src/Oh.My.Stitcher.Benchmark/PathCreationBenchmark.cs @@ -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 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); + } + } +} diff --git a/src/Oh.My.Stitcher.Benchmark/Program.cs b/src/Oh.My.Stitcher.Benchmark/Program.cs new file mode 100644 index 0000000..a8af081 --- /dev/null +++ b/src/Oh.My.Stitcher.Benchmark/Program.cs @@ -0,0 +1,13 @@ +using BenchmarkDotNet.Running; + +namespace Oh.My.Stitcher.Benchmark; + +static class Program +{ + static void Main(string[] _) + { + BenchmarkRunner.Run(); + BenchmarkRunner.Run(); + BenchmarkRunner.Run(); + } +} diff --git a/src/Oh.My.Stitcher.Benchmark/UsageBenchmark.cs b/src/Oh.My.Stitcher.Benchmark/UsageBenchmark.cs new file mode 100644 index 0000000..9ae34f8 --- /dev/null +++ b/src/Oh.My.Stitcher.Benchmark/UsageBenchmark.cs @@ -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 images = []; + IMemoryCache cache = Substitute.For(); + ILogger logger = Substitute.For(); + 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 images = []; + IMemoryCache cache = Substitute.For(); + ILogger logger = Substitute.For(); + 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(); + } + } +} diff --git a/stitchaton.sln b/stitchaton.sln index 6f825ef..a2f972a 100644 --- a/stitchaton.sln +++ b/stitchaton.sln @@ -4,6 +4,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AEE9B1D3-6AD EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Oh.My.Stitcher", "src\Oh.My.Stitcher\Oh.My.Stitcher.csproj", "{9AB5F809-0D6A-4906-AB89-DC797FB7CF42}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Oh.My.Stitcher.Benchmark", "src\Oh.My.Stitcher.Benchmark\Oh.My.Stitcher.Benchmark.csproj", "{68A9786C-87C0-488C-9DA4-29909671F4F0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "vendor", "vendor", "{2F99FC95-31EA-42FD-BA0B-948B7DB33D86}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetVips", "vendor\NetVips\NetVips.csproj", "{A27A7D25-4601-45A5-ACA0-7DE44AE7FD33}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -12,12 +17,21 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {9AB5F809-0D6A-4906-AB89-DC797FB7CF42} = {AEE9B1D3-6AD8-4EEE-800B-2873B0BB78DD} - {A9CC8F78-CB38-4986-9480-5FB4556F1356} = {AEE9B1D3-6AD8-4EEE-800B-2873B0BB78DD} + {68A9786C-87C0-488C-9DA4-29909671F4F0} = {AEE9B1D3-6AD8-4EEE-800B-2873B0BB78DD} + {A27A7D25-4601-45A5-ACA0-7DE44AE7FD33} = {2F99FC95-31EA-42FD-BA0B-948B7DB33D86} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {9AB5F809-0D6A-4906-AB89-DC797FB7CF42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9AB5F809-0D6A-4906-AB89-DC797FB7CF42}.Debug|Any CPU.Build.0 = Debug|Any CPU {9AB5F809-0D6A-4906-AB89-DC797FB7CF42}.Release|Any CPU.ActiveCfg = Release|Any CPU {9AB5F809-0D6A-4906-AB89-DC797FB7CF42}.Release|Any CPU.Build.0 = Release|Any CPU + {68A9786C-87C0-488C-9DA4-29909671F4F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68A9786C-87C0-488C-9DA4-29909671F4F0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68A9786C-87C0-488C-9DA4-29909671F4F0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68A9786C-87C0-488C-9DA4-29909671F4F0}.Release|Any CPU.Build.0 = Release|Any CPU + {A27A7D25-4601-45A5-ACA0-7DE44AE7FD33}.Debug|Any CPU.ActiveCfg = Debug|x64 + {A27A7D25-4601-45A5-ACA0-7DE44AE7FD33}.Debug|Any CPU.Build.0 = Debug|x64 + {A27A7D25-4601-45A5-ACA0-7DE44AE7FD33}.Release|Any CPU.ActiveCfg = Release|x64 + {A27A7D25-4601-45A5-ACA0-7DE44AE7FD33}.Release|Any CPU.Build.0 = Release|x64 EndGlobalSection EndGlobal diff --git a/stitchaton.sln.DotSettings b/stitchaton.sln.DotSettings index d094dec..8f3153e 100644 --- a/stitchaton.sln.DotSettings +++ b/stitchaton.sln.DotSettings @@ -1,2 +1,3 @@  + True True \ No newline at end of file