From 26fc9b3906c390ba9978d9bd00ecd00a07d98a60 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 7 Jan 2020 16:13:28 +1100 Subject: [PATCH] Speed up tga decoding and add new benchmark comparison --- Directory.Build.targets | 7 +- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 2 +- src/ImageSharp/Image.FromBytes.cs | 14 ++-- .../ImageSharp.Benchmarks/Codecs/DecodeTga.cs | 67 ++++++++++++++++--- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 5 +- .../Codecs/MultiImageBenchmarkBase.cs | 3 +- tests/ImageSharp.Benchmarks/Config.cs | 9 +-- .../ImageSharp.Benchmarks.csproj | 3 +- 8 files changed, 82 insertions(+), 28 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 01c1f1039..f6523fee0 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -22,18 +22,19 @@ - - + + + - + diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index bfc69d1c8..1ff3bb599 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Formats.Tga throw new UnknownImageFormatException("Width or height cannot be 0"); } - var image = new Image(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); + var image = Image.CreateUninitialized(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.fileHeader.ColorMapType is 1) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 178098b7f..389fbba6d 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp public static Image Load(Configuration config, byte[] data) where TPixel : struct, IPixel { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(config, stream); } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp public static Image Load(Configuration config, byte[] data, out IImageFormat format) where TPixel : struct, IPixel { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(config, stream, out format); } @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp public static Image Load(byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(stream, decoder); } @@ -125,9 +125,9 @@ namespace SixLabors.ImageSharp public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { - using (var memoryStream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return Load(config, memoryStream, decoder); + return Load(config, stream, decoder); } } @@ -299,7 +299,7 @@ namespace SixLabors.ImageSharp /// The . public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(config, stream, decoder); } @@ -314,7 +314,7 @@ namespace SixLabors.ImageSharp /// The . public static Image Load(Configuration config, byte[] data, out IImageFormat format) { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(config, stream, out format); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs index e3c721610..527b6bb8b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs @@ -1,15 +1,16 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Buffers; using System.IO; - +using System.Threading; using BenchmarkDotNet.Attributes; using ImageMagick; - +using Pfim; +using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests; -using SixLabors.Primitives; namespace SixLabors.ImageSharp.Benchmarks.Codecs { @@ -17,26 +18,74 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public class DecodeTga : BenchmarkBase { private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + private readonly PfimConfig pfimConfig = new PfimConfig(allocator: new PfimAllocator()); + private byte[] data; [Params(TestImages.Tga.Bit24)] public string TestImage { get; set; } + [GlobalSetup] + public void SetupData() + { + this.data = File.ReadAllBytes(this.TestImageFullPath); + } + [Benchmark(Baseline = true, Description = "ImageMagick Tga")] - public Size TgaImageMagick() + public int TgaImageMagick() { - using (var magickImage = new MagickImage(this.TestImageFullPath)) + var settings = new MagickReadSettings { Format = MagickFormat.Tga }; + using (var image = new MagickImage(new MemoryStream(this.data), settings)) { - return new Size(magickImage.Width, magickImage.Height); + return image.Width; } } [Benchmark(Description = "ImageSharp Tga")] - public Size TgaCore() + public int TgaCore() { - using (var image = Image.Load(this.TestImageFullPath)) + using (var image = Image.Load(this.data, new TgaDecoder())) { - return new Size(image.Width, image.Height); + return image.Width; } } + + [Benchmark(Description = "Pfim Tga")] + public int TgaPfim() + { + using (var image = Targa.Create(this.data, this.pfimConfig)) + { + return image.Width; + } + } + + private class PfimAllocator : IImageAllocator + { + private int rented; + private readonly ArrayPool shared = ArrayPool.Shared; + + public byte[] Rent(int size) + { + return this.shared.Rent(size); + } + + public void Return(byte[] data) + { + Interlocked.Decrement(ref this.rented); + this.shared.Return(data); + } + + public int Rented => this.rented; + } + + // RESULTS (07/01/2020) + //| Method | Runtime | TestImage | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated | + //|------------------ |-------------- |-------------------- |-------------:|-------------:|-----------:|------:|-------:|------:|------:|----------:| + //| 'ImageMagick Tga' | .NET 4.7.2 | Tga/targa_24bit.tga | 1,778.965 us | 1,711.088 us | 93.7905 us | 1.000 | 1.9531 | - | - | 13668 B | + //| 'ImageSharp Tga' | .NET 4.7.2 | Tga/targa_24bit.tga | 38.659 us | 6.886 us | 0.3774 us | 0.022 | 0.3052 | - | - | 1316 B | + //| 'Pfim Tga' | .NET 4.7.2 | Tga/targa_24bit.tga | 6.752 us | 10.268 us | 0.5628 us | 0.004 | 0.0687 | - | - | 313 B | + //| | | | | | | | | | | | + //| 'ImageMagick Tga' | .NET Core 2.1 | Tga/targa_24bit.tga | 1,407.585 us | 124.215 us | 6.8087 us | 1.000 | 1.9531 | - | - | 13307 B | + //| 'ImageSharp Tga' | .NET Core 2.1 | Tga/targa_24bit.tga | 17.958 us | 9.352 us | 0.5126 us | 0.013 | 0.2747 | - | - | 1256 B | + //| 'Pfim Tga' | .NET Core 2.1 | Tga/targa_24bit.tga | 5.645 us | 2.279 us | 0.1249 us | 0.004 | 0.0610 | - | - | 280 B | } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 99b071e59..17ad79e58 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -6,6 +6,7 @@ using System.IO; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Environments; using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Formats.Jpeg; @@ -35,8 +36,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg public ShortClr() { this.Add( - // Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3), - Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3) + // Job.Default.With(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3), + Job.Default.With(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3) ); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index bf694211d..6d4caa843 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -17,6 +17,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Diagnosers; + using BenchmarkDotNet.Environments; using SixLabors.ImageSharp.Tests; using CoreImage = ImageSharp.Image; @@ -36,7 +37,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public ShortClr() { this.Add( - Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithIterationCount(2) + Job.Default.With(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(1).WithIterationCount(2) ); } } diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index 0543cbc50..018a2e02b 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -1,8 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Environments; using BenchmarkDotNet.Jobs; namespace SixLabors.ImageSharp.Benchmarks @@ -19,10 +20,10 @@ namespace SixLabors.ImageSharp.Benchmarks public ShortClr() { this.Add( - Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), - Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3) + Job.Default.With(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), + Job.Default.With(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3) ); } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index a57d388a9..cd8497ee4 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,4 +1,4 @@ - + @@ -19,6 +19,7 @@ +