Browse Source

Get the benchmarks working again.

pull/2886/head
James Jackson-South 1 year ago
parent
commit
9be7d84400
  1. 4
      tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs
  2. 2
      tests/ImageSharp.Benchmarks/Bulk/Vector4Factory.cs
  3. 17
      tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs
  4. 8
      tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs
  5. 2
      tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs
  6. 12
      tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs
  7. 10
      tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs
  8. 4
      tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs
  9. 13
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs
  10. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs
  11. 60
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs
  12. 19
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
  13. 10
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs
  14. 17
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
  15. 9
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs
  16. 10
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs
  17. 28
      tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs
  18. 2
      tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs
  19. 26
      tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs
  20. 10
      tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs
  21. 2
      tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs
  22. 4
      tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs
  23. 2
      tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs
  24. 46
      tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs
  25. 2
      tests/ImageSharp.Benchmarks/Color/ColorEquality.cs
  26. 2
      tests/ImageSharp.Benchmarks/General/GetSetPixel.cs
  27. 8
      tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs
  28. 18
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
  29. 5
      tests/ImageSharp.Benchmarks/General/StructCasting.cs
  30. 24
      tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs
  31. 18
      tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs
  32. 44
      tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs
  33. 20
      tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
  34. 4
      tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
  35. 10
      tests/ImageSharp.Benchmarks/Processing/Crop.cs
  36. 36
      tests/ImageSharp.Benchmarks/Processing/Resize.cs

4
tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs

@ -62,9 +62,7 @@ public abstract class FromRgba32Bytes<TPixel>
=> PixelOperations<TPixel>.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes<Rgba32>
{
}
public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes<Rgba32>;
public class FromRgba32Bytes_ToBgra32 : FromRgba32Bytes<Bgra32>
{

2
tests/ImageSharp.Benchmarks/Bulk/Vector4Factory.cs

@ -30,5 +30,5 @@ internal static class Vector4Factory
}
private static float GetRandomFloat(Random rnd, float minVal, float maxVal)
=> (float)rnd.NextDouble() * (maxVal - minVal) + minVal;
=> ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal;
}

17
tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
@ -19,12 +20,7 @@ public class DecodeBmp
[GlobalSetup]
public void ReadImages()
{
if (this.bmpBytes == null)
{
this.bmpBytes = File.ReadAllBytes(this.TestImageFullPath);
}
}
=> this.bmpBytes ??= File.ReadAllBytes(this.TestImageFullPath);
[Params(TestImages.Bmp.Car)]
public string TestImage { get; set; }
@ -32,16 +28,17 @@ public class DecodeBmp
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public SDSize BmpSystemDrawing()
{
using var memoryStream = new MemoryStream(this.bmpBytes);
using var image = SDImage.FromStream(memoryStream);
using MemoryStream memoryStream = new(this.bmpBytes);
using SDImage image = SDImage.FromStream(memoryStream);
return image.Size;
}
[Benchmark(Description = "ImageSharp Bmp")]
public Size BmpImageSharp()
{
using var memoryStream = new MemoryStream(this.bmpBytes);
using var image = Image.Load<Rgba32>(memoryStream);
using MemoryStream memoryStream = new(this.bmpBytes);
using Image<Rgba32> image = Image.Load<Rgba32>(memoryStream);
return new Size(image.Width, image.Height);
}
}
#endif

8
tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
@ -12,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.Short))]
public class EncodeBmp
{
private Stream bmpStream;
private FileStream bmpStream;
private SDImage bmpDrawing;
private Image<Rgba32> bmpCore;
@ -40,14 +41,15 @@ public class EncodeBmp
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public void BmpSystemDrawing()
{
using var memoryStream = new MemoryStream();
using MemoryStream memoryStream = new();
this.bmpDrawing.Save(memoryStream, ImageFormat.Bmp);
}
[Benchmark(Description = "ImageSharp Bmp")]
public void BmpImageSharp()
{
using var memoryStream = new MemoryStream();
using MemoryStream memoryStream = new();
this.bmpCore.SaveAsBmp(memoryStream);
}
}
#endif

2
tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Bmp;
@ -28,3 +29,4 @@ public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
return null;
});
}
#endif

12
tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
@ -26,22 +27,23 @@ public class DecodeGif
}
}
[Params(TestImages.Gif.Cheers)]
[Params(TestImages.Gif.Rings)]
public string TestImage { get; set; }
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public SDSize GifSystemDrawing()
{
using var memoryStream = new MemoryStream(this.gifBytes);
using var image = SDImage.FromStream(memoryStream);
using MemoryStream memoryStream = new(this.gifBytes);
using SDImage image = SDImage.FromStream(memoryStream);
return image.Size;
}
[Benchmark(Description = "ImageSharp Gif")]
public Size GifImageSharp()
{
using var memoryStream = new MemoryStream(this.gifBytes);
using var image = Image.Load<Rgba32>(memoryStream);
using MemoryStream memoryStream = new(this.gifBytes);
using Image<Rgba32> image = Image.Load<Rgba32>(memoryStream);
return new Size(image.Width, image.Height);
}
}
#endif

10
tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Gif;
@ -16,12 +17,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
public class EncodeGif
{
// System.Drawing needs this.
private Stream bmpStream;
private FileStream bmpStream;
private SDImage bmpDrawing;
private Image<Rgba32> bmpCore;
// Try to get as close to System.Drawing's output as possible
private readonly GifEncoder encoder = new GifEncoder
private readonly GifEncoder encoder = new()
{
Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 })
};
@ -53,14 +54,15 @@ public class EncodeGif
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public void GifSystemDrawing()
{
using var memoryStream = new MemoryStream();
using MemoryStream memoryStream = new();
this.bmpDrawing.Save(memoryStream, ImageFormat.Gif);
}
[Benchmark(Description = "ImageSharp Gif")]
public void GifImageSharp()
{
using var memoryStream = new MemoryStream();
using MemoryStream memoryStream = new();
this.bmpCore.SaveAsGif(memoryStream, this.encoder);
}
}
#endif

4
tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Gif;
@ -22,7 +23,7 @@ public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
=> this.ForEachImageSharpImage((img, ms) =>
{
// Try to get as close to System.Drawing's output as possible
var options = new GifEncoder
GifEncoder options = new()
{
Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 })
};
@ -39,3 +40,4 @@ public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
return null;
});
}
#endif

13
tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs

@ -12,8 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations;
public class Block8x8F_LoadFromInt16
{
private Block8x8 source;
private Block8x8F dest = default;
private Block8x8F destination;
[GlobalSetup]
public void Setup()
@ -30,16 +29,10 @@ public class Block8x8F_LoadFromInt16
}
[Benchmark(Baseline = true)]
public void Scalar()
{
this.dest.LoadFromInt16Scalar(ref this.source);
}
public void Scalar() => this.destination.LoadFromInt16Scalar(ref this.source);
[Benchmark]
public void ExtendedAvx2()
{
this.dest.LoadFromInt16ExtendedAvx2(ref this.source);
}
public void ExtendedAvx2() => this.destination.LoadFromInt16ExtendedAvx2(ref this.source);
// RESULT:
// Method | Mean | Error | StdDev | Scaled |

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs

@ -11,7 +11,7 @@ public class Block8x8F_Quantize
{
private Block8x8F block = CreateFromScalar(1);
private Block8x8F quant = CreateFromScalar(1);
private Block8x8 result = default;
private Block8x8 result;
[Benchmark]
public short Quantize()

60
tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs

@ -36,7 +36,7 @@ public unsafe class Block8x8F_Round
if (ptr % 16 != 0)
{
throw new Exception("ptr is unaligned");
throw new InvalidOperationException("ptr is unaligned");
}
this.alignedPtr = (float*)ptr;
@ -67,21 +67,21 @@ public unsafe class Block8x8F_Round
ref Block8x8F b = ref this.block;
ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V0L);
row0 = SimdUtils.FastRound(row0);
row0 = row0.FastRound();
ref Vector<float> row1 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V1L);
row1 = SimdUtils.FastRound(row1);
row1 = row1.FastRound();
ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V2L);
row2 = SimdUtils.FastRound(row2);
row2 = row2.FastRound();
ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V3L);
row3 = SimdUtils.FastRound(row3);
row3 = row3.FastRound();
ref Vector<float> row4 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V4L);
row4 = SimdUtils.FastRound(row4);
row4 = row4.FastRound();
ref Vector<float> row5 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V5L);
row5 = SimdUtils.FastRound(row5);
row5 = row5.FastRound();
ref Vector<float> row6 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V6L);
row6 = SimdUtils.FastRound(row6);
row6 = row6.FastRound();
ref Vector<float> row7 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V7L);
row7 = SimdUtils.FastRound(row7);
row7 = row7.FastRound();
}
[Benchmark]
@ -90,21 +90,21 @@ public unsafe class Block8x8F_Round
ref Block8x8F b = ref Unsafe.AsRef<Block8x8F>(this.alignedPtr);
ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V0L);
row0 = SimdUtils.FastRound(row0);
row0 = row0.FastRound();
ref Vector<float> row1 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V1L);
row1 = SimdUtils.FastRound(row1);
row1 = row1.FastRound();
ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V2L);
row2 = SimdUtils.FastRound(row2);
row2 = row2.FastRound();
ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V3L);
row3 = SimdUtils.FastRound(row3);
row3 = row3.FastRound();
ref Vector<float> row4 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V4L);
row4 = SimdUtils.FastRound(row4);
row4 = row4.FastRound();
ref Vector<float> row5 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V5L);
row5 = SimdUtils.FastRound(row5);
row5 = row5.FastRound();
ref Vector<float> row6 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V6L);
row6 = SimdUtils.FastRound(row6);
row6 = row6.FastRound();
ref Vector<float> row7 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V7L);
row7 = SimdUtils.FastRound(row7);
row7 = row7.FastRound();
}
[Benchmark]
@ -117,20 +117,20 @@ public unsafe class Block8x8F_Round
ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V2L);
ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V3L);
row0 = SimdUtils.FastRound(row0);
row1 = SimdUtils.FastRound(row1);
row2 = SimdUtils.FastRound(row2);
row3 = SimdUtils.FastRound(row3);
row0 = row0.FastRound();
row1 = row1.FastRound();
row2 = row2.FastRound();
row3 = row3.FastRound();
row0 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V4L);
row1 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V5L);
row2 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V6L);
row3 = ref Unsafe.As<Vector4, Vector<float>>(ref b.V7L);
row0 = SimdUtils.FastRound(row0);
row1 = SimdUtils.FastRound(row1);
row2 = SimdUtils.FastRound(row2);
row3 = SimdUtils.FastRound(row3);
row0 = row0.FastRound();
row1 = row1.FastRound();
row2 = row2.FastRound();
row3 = row3.FastRound();
}
[Benchmark]
@ -174,7 +174,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
public unsafe void Sse41_V2()
public void Sse41_V2()
{
ref Vector128<float> p = ref Unsafe.As<Block8x8F, Vector128<float>>(ref this.block);
p = Sse41.RoundToNearestInteger(p);
@ -214,7 +214,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
public unsafe void Sse41_V3()
public void Sse41_V3()
{
ref Vector128<float> p = ref Unsafe.As<Block8x8F, Vector128<float>>(ref this.block);
p = Sse41.RoundToNearestInteger(p);
@ -228,7 +228,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
public unsafe void Sse41_V4()
public void Sse41_V4()
{
ref Vector128<float> p = ref Unsafe.As<Block8x8F, Vector128<float>>(ref this.block);
nuint offset = (uint)sizeof(Vector128<float>);
@ -271,7 +271,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
public unsafe void Sse41_V5_Unaligned()
public void Sse41_V5_Unaligned()
{
float* p = this.alignedPtr + 1;
@ -356,7 +356,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
public unsafe void Sse41_V5_Aligned()
public void Sse41_V5_Aligned()
{
float* p = this.alignedPtr;

19
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
@ -27,20 +28,20 @@ public class DecodeJpegParseStreamOnly
[Benchmark(Baseline = true, Description = "System.Drawing FULL")]
public SDSize JpegSystemDrawing()
{
using var memoryStream = new MemoryStream(this.jpegBytes);
using var image = System.Drawing.Image.FromStream(memoryStream);
using MemoryStream memoryStream = new(this.jpegBytes);
using System.Drawing.Image image = System.Drawing.Image.FromStream(memoryStream);
return image.Size;
}
[Benchmark(Description = "JpegDecoderCore.ParseStream")]
public void ParseStream()
{
using var memoryStream = new MemoryStream(this.jpegBytes);
using var bufferedStream = new BufferedReadStream(Configuration.Default, memoryStream);
var options = new JpegDecoderOptions() { GeneralOptions = new() { SkipMetadata = true } };
using MemoryStream memoryStream = new(this.jpegBytes);
using BufferedReadStream bufferedStream = new(Configuration.Default, memoryStream);
JpegDecoderOptions options = new() { GeneralOptions = new() { SkipMetadata = true } };
using var decoder = new JpegDecoderCore(options);
var spectralConverter = new NoopSpectralConverter();
using JpegDecoderCore decoder = new(options);
NoopSpectralConverter spectralConverter = new();
decoder.ParseStream(bufferedStream, spectralConverter, cancellationToken: default);
}
@ -48,7 +49,7 @@ public class DecodeJpegParseStreamOnly
// Nor we need to allocate final pixel buffer
// Note: this still introduces virtual method call overhead for baseline interleaved images
// There's no way to eliminate it as spectral conversion is built into the scan decoding loop for memory footprint reduction
private class NoopSpectralConverter : SpectralConverter
private sealed class NoopSpectralConverter : SpectralConverter
{
public override void ConvertStrideBaseline()
{
@ -65,7 +66,7 @@ public class DecodeJpegParseStreamOnly
}
}
}
#endif
/*
BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19042.1083 (20H2/October2020Update)
Intel Core i7-6700K CPU 4.00GHz (Skylake), 1 CPU, 8 logical and 4 physical cores

10
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
@ -17,23 +18,24 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase
{
protected override IEnumerable<string> InputImageSubfoldersOrFiles
=> new[]
{
=>
[
TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome,
TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr,
TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr,
TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr,
TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr,
};
];
[Params(InputImageCategory.AllImages)]
public override InputImageCategory InputCategory { get; set; }
[Benchmark]
public void ImageSharp()
=> this.ForEachStream(ms => Image.Load<Rgba32>(ms));
=> this.ForEachStream(Image.Load<Rgba32>);
[Benchmark(Baseline = true)]
public void SystemDrawing()
=> this.ForEachStream(SDImage.FromStream);
}
#endif

17
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Tests;
@ -35,26 +36,21 @@ public class DecodeJpeg_ImageSpecific
[GlobalSetup]
public void ReadImages()
{
if (this.jpegBytes == null)
{
this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath);
}
}
=> this.jpegBytes ??= File.ReadAllBytes(this.TestImageFullPath);
[Benchmark(Baseline = true)]
public SDSize SystemDrawing()
{
using var memoryStream = new MemoryStream(this.jpegBytes);
using var image = SDImage.FromStream(memoryStream);
using MemoryStream memoryStream = new(this.jpegBytes);
using SDImage image = SDImage.FromStream(memoryStream);
return image.Size;
}
[Benchmark]
public Size ImageSharp()
{
using var memoryStream = new MemoryStream(this.jpegBytes);
using var image = Image.Load(new DecoderOptions() { SkipMetadata = true }, memoryStream);
using MemoryStream memoryStream = new(this.jpegBytes);
using Image image = Image.Load(new DecoderOptions() { SkipMetadata = true }, memoryStream);
return new Size(image.Width, image.Height);
}
@ -71,3 +67,4 @@ public class DecodeJpeg_ImageSpecific
| 'Decode Jpeg - ImageSharp' | Jpg/i(...)e.jpg [43] | 276.490 ms | 195.5104 ms | 10.7166 ms | 0.71 | 0.01 | - | - | - | 36022368 B |
*/
}
#endif

9
tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs

@ -19,11 +19,6 @@ public class EncodeJpegComparison
{
// Big enough, 4:4:4 chroma sampling
private const string TestImage = TestImages.Jpeg.Baseline.Calliphora;
// Change/add parameters for extra benchmarks
[Params(75, 90, 100)]
public int Quality;
private MemoryStream destinationStream;
// ImageSharp
@ -33,6 +28,10 @@ public class EncodeJpegComparison
// SkiaSharp
private SKBitmap imageSkiaSharp;
// Change/add parameters for extra benchmarks
[Params(75, 90, 100)]
public int Quality { get; set; }
[GlobalSetup(Target = nameof(BenchmarkImageSharp))]
public void SetupImageSharp()
{

10
tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs

@ -20,19 +20,19 @@ public class EncodeJpegFeatures
// No metadata
private const string TestImage = TestImages.Jpeg.Baseline.Calliphora;
public static IEnumerable<JpegColorType> ColorSpaceValues => new[]
{
public static IEnumerable<JpegColorType> ColorSpaceValues =>
[
JpegColorType.Luminance,
JpegColorType.Rgb,
JpegColorType.YCbCrRatio420,
JpegColorType.YCbCrRatio444,
};
];
[Params(75, 90, 100)]
public int Quality;
public int Quality { get; set; }
[ParamsSource(nameof(ColorSpaceValues), Priority = -100)]
public JpegColorType TargetColorSpace;
public JpegColorType TargetColorSpace { get; set; }
private Image<Rgb24> bmpCore;
private JpegEncoder encoder;

28
tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing;
using System.Numerics;
using BenchmarkDotNet.Attributes;
@ -11,11 +12,11 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
public abstract class MultiImageBenchmarkBase
{
protected Dictionary<string, byte[]> FileNamesToBytes { get; set; } = new Dictionary<string, byte[]>();
protected Dictionary<string, byte[]> FileNamesToBytes { get; set; } = [];
protected Dictionary<string, Image<Rgba32>> FileNamesToImageSharpImages { get; set; } = new Dictionary<string, Image<Rgba32>>();
protected Dictionary<string, Image<Rgba32>> FileNamesToImageSharpImages { get; set; } = [];
protected Dictionary<string, Bitmap> FileNamesToSystemDrawingImages { get; set; } = new Dictionary<string, Bitmap>();
protected Dictionary<string, Bitmap> FileNamesToSystemDrawingImages { get; set; } = [];
/// <summary>
/// The values of this enum separate input files into categories.
@ -43,12 +44,12 @@ public abstract class MultiImageBenchmarkBase
protected virtual string BaseFolder => TestEnvironment.InputImagesDirectoryFullPath;
protected virtual IEnumerable<string> SearchPatterns => new[] { "*.*" };
protected virtual IEnumerable<string> SearchPatterns => ["*.*"];
/// <summary>
/// Gets the file names containing these strings are substrings are not processed by the benchmark.
/// </summary>
protected virtual IEnumerable<string> ExcludeSubstringsInFileNames => new[] { "badeof", "BadEof", "CriticalEOF" };
protected virtual IEnumerable<string> ExcludeSubstringsInFileNames => ["badeof", "BadEof", "CriticalEOF"];
/// <summary>
/// Gets folders containing files OR files to be processed by the benchmark.
@ -70,7 +71,7 @@ public abstract class MultiImageBenchmarkBase
InputImageCategory.AllImages => input,
InputImageCategory.SmallImagesOnly => input.Where(kv => checkIfSmall(kv.Value)),
InputImageCategory.LargeImagesOnly => input.Where(kv => !checkIfSmall(kv.Value)),
_ => throw new ArgumentOutOfRangeException(),
_ => throw new ArgumentOutOfRangeException(nameof(input), "Invalid input category")
};
protected IEnumerable<KeyValuePair<string, byte[]>> FileNames2Bytes
@ -86,7 +87,7 @@ public abstract class MultiImageBenchmarkBase
{
if (!Vector.IsHardwareAccelerated)
{
throw new Exception("Vector.IsHardwareAccelerated == false! Check your build settings!");
throw new InvalidOperationException("Vector.IsHardwareAccelerated == false! Check your build settings!");
}
// Console.WriteLine("Vector.IsHardwareAccelerated: " + Vector.IsHardwareAccelerated);
@ -103,13 +104,13 @@ public abstract class MultiImageBenchmarkBase
continue;
}
string[] excludeStrings = this.ExcludeSubstringsInFileNames.Select(s => s.ToLower()).ToArray();
string[] excludeStrings = this.ExcludeSubstringsInFileNames.ToArray();
string[] allFiles =
this.SearchPatterns.SelectMany(
f =>
Directory.EnumerateFiles(path, f, SearchOption.AllDirectories)
.Where(fn => !excludeStrings.Any(excludeStr => fn.ToLower().Contains(excludeStr)))).ToArray();
.Where(fn => !excludeStrings.Any(excludeStr => fn.Contains(excludeStr, StringComparison.OrdinalIgnoreCase)))).ToArray();
foreach (string fn in allFiles)
{
@ -126,7 +127,7 @@ public abstract class MultiImageBenchmarkBase
{
foreach (KeyValuePair<string, byte[]> kv in this.FileNames2Bytes)
{
using var memoryStream = new MemoryStream(kv.Value);
using MemoryStream memoryStream = new(kv.Value);
try
{
object obj = operation(memoryStream);
@ -150,7 +151,7 @@ public abstract class MultiImageBenchmarkBase
byte[] bytes = kv.Value;
string fn = kv.Key;
using (var ms1 = new MemoryStream(bytes))
using (MemoryStream ms1 = new(bytes))
{
this.FileNamesToImageSharpImages[fn] = Image.Load<Rgba32>(ms1);
}
@ -191,7 +192,7 @@ public abstract class MultiImageBenchmarkBase
protected void ForEachImageSharpImage(Func<Image<Rgba32>, MemoryStream, object> operation)
{
using var workStream = new MemoryStream();
using MemoryStream workStream = new();
this.ForEachImageSharpImage(
img =>
{
@ -222,7 +223,7 @@ public abstract class MultiImageBenchmarkBase
protected void ForEachSystemDrawingImage(Func<Bitmap, MemoryStream, object> operation)
{
using var workStream = new MemoryStream();
using MemoryStream workStream = new();
this.ForEachSystemDrawingImage(
img =>
{
@ -236,3 +237,4 @@ public abstract class MultiImageBenchmarkBase
}
}
}
#endif

2
tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
@ -40,3 +41,4 @@ public class DecodePng
return image.Size;
}
}
#endif

26
tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs

@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
public class EncodeIndexedPng
{
// System.Drawing needs this.
private Stream bmpStream;
private FileStream bmpStream;
private Image<Rgba32> bmpCore;
[GlobalSetup]
@ -43,48 +43,48 @@ public class EncodeIndexedPng
[Benchmark(Baseline = true, Description = "ImageSharp Octree Png")]
public void PngCoreOctree()
{
using var memoryStream = new MemoryStream();
var options = new PngEncoder { Quantizer = KnownQuantizers.Octree };
using MemoryStream memoryStream = new();
PngEncoder options = new() { Quantizer = KnownQuantizers.Octree };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Octree NoDither Png")]
public void PngCoreOctreeNoDither()
{
using var memoryStream = new MemoryStream();
var options = new PngEncoder { Quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = null }) };
using MemoryStream memoryStream = new();
PngEncoder options = new() { Quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = null }) };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Palette Png")]
public void PngCorePalette()
{
using var memoryStream = new MemoryStream();
var options = new PngEncoder { Quantizer = KnownQuantizers.WebSafe };
using MemoryStream memoryStream = new();
PngEncoder options = new() { Quantizer = KnownQuantizers.WebSafe };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Palette NoDither Png")]
public void PngCorePaletteNoDither()
{
using var memoryStream = new MemoryStream();
var options = new PngEncoder { Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = null }) };
using MemoryStream memoryStream = new();
PngEncoder options = new() { Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = null }) };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Wu Png")]
public void PngCoreWu()
{
using var memoryStream = new MemoryStream();
var options = new PngEncoder { Quantizer = KnownQuantizers.Wu };
using MemoryStream memoryStream = new();
PngEncoder options = new() { Quantizer = KnownQuantizers.Wu };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Wu NoDither Png")]
public void PngCoreWuNoDither()
{
using var memoryStream = new MemoryStream();
var options = new PngEncoder { Quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }), ColorType = PngColorType.Palette };
using MemoryStream memoryStream = new();
PngEncoder options = new() { Quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }), ColorType = PngColorType.Palette };
this.bmpCore.SaveAsPng(memoryStream, options);
}
}

10
tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Png;
@ -14,7 +15,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
public class EncodePng
{
// System.Drawing needs this.
private Stream bmpStream;
private FileStream bmpStream;
private SDImage bmpDrawing;
private Image<Rgba32> bmpCore;
@ -46,15 +47,16 @@ public class EncodePng
[Benchmark(Baseline = true, Description = "System.Drawing Png")]
public void PngSystemDrawing()
{
using var memoryStream = new MemoryStream();
using MemoryStream memoryStream = new();
this.bmpDrawing.Save(memoryStream, ImageFormat.Png);
}
[Benchmark(Description = "ImageSharp Png")]
public void PngCore()
{
using var memoryStream = new MemoryStream();
var encoder = new PngEncoder { FilterMethod = PngFilterMethod.None };
using MemoryStream memoryStream = new();
PngEncoder encoder = new() { FilterMethod = PngFilterMethod.None };
this.bmpCore.SaveAsPng(memoryStream, encoder);
}
}
#endif

2
tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs

@ -48,7 +48,7 @@ public class DecodeTga
return image.Width;
}
private class PfimAllocator : IImageAllocator
private sealed class PfimAllocator : IImageAllocator
{
private int rented;
private readonly ArrayPool<byte> shared = ArrayPool<byte>.Shared;

4
tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs

@ -41,14 +41,14 @@ public class EncodeTga
[Benchmark(Baseline = true, Description = "Magick Tga")]
public void MagickTga()
{
using var memoryStream = new MemoryStream();
using MemoryStream memoryStream = new();
this.tgaMagick.Write(memoryStream, MagickFormat.Tga);
}
[Benchmark(Description = "ImageSharp Tga")]
public void ImageSharpTga()
{
using var memoryStream = new MemoryStream();
using MemoryStream memoryStream = new();
this.tga.SaveAsTga(memoryStream);
}
}

2
tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
// Enable this for using larger Tiff files. Those files are very large (> 700MB) and therefor not part of the git repo.
// Use the scripts gen_big.ps1 and gen_medium.ps1 in tests\Images\Input\Tiff\Benchmarks to generate those images.
//// #define BIG_TESTS
@ -82,3 +83,4 @@ public class DecodeTiff
return image.Size;
}
}
#endif

46
tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
@ -17,7 +18,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.Short))]
public class EncodeTiff
{
private Stream stream;
private FileStream stream;
private SDImage drawing;
private Image<Rgba32> core;
@ -60,12 +61,12 @@ public class EncodeTiff
public void SystemDrawing()
{
ImageCodecInfo codec = FindCodecForType("image/tiff");
using var parameters = new EncoderParameters(1)
using EncoderParameters parameters = new(1)
{
Param = { [0] = new EncoderParameter(Encoder.Compression, (long)Cast(this.Compression)) }
};
using var memoryStream = new MemoryStream();
using MemoryStream memoryStream = new();
this.drawing.Save(memoryStream, codec, parameters);
}
@ -77,8 +78,8 @@ public class EncodeTiff
TiffPhotometricInterpretation.WhiteIsZero :
TiffPhotometricInterpretation.Rgb;
var encoder = new TiffEncoder() { Compression = this.Compression, PhotometricInterpretation = photometricInterpretation };
using var memoryStream = new MemoryStream();
TiffEncoder encoder = new() { Compression = this.Compression, PhotometricInterpretation = photometricInterpretation };
using MemoryStream memoryStream = new();
this.core.SaveAsTiff(memoryStream, encoder);
}
@ -98,33 +99,16 @@ public class EncodeTiff
}
private static EncoderValue Cast(TiffCompression compression)
{
switch (compression)
=> compression switch
{
case TiffCompression.None:
return EncoderValue.CompressionNone;
case TiffCompression.CcittGroup3Fax:
return EncoderValue.CompressionCCITT3;
case TiffCompression.Ccitt1D:
return EncoderValue.CompressionRle;
case TiffCompression.Lzw:
return EncoderValue.CompressionLZW;
default:
throw new NotSupportedException(compression.ToString());
}
}
TiffCompression.None => EncoderValue.CompressionNone,
TiffCompression.CcittGroup3Fax => EncoderValue.CompressionCCITT3,
TiffCompression.Ccitt1D => EncoderValue.CompressionRle,
TiffCompression.Lzw => EncoderValue.CompressionLZW,
_ => throw new NotSupportedException(compression.ToString()),
};
public static bool IsOneBitCompression(TiffCompression compression)
{
if (compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or TiffCompression.CcittGroup4Fax)
{
return true;
}
return false;
}
=> compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or TiffCompression.CcittGroup4Fax;
}
#endif

2
tests/ImageSharp.Benchmarks/Color/ColorEquality.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SystemColor = System.Drawing.Color;
@ -17,3 +18,4 @@ public class ColorEquality
public bool ColorEqual()
=> new Rgba32(128, 128, 128, 128).Equals(new Rgba32(128, 128, 128, 128));
}
#endif

2
tests/ImageSharp.Benchmarks/General/GetSetPixel.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
@ -25,3 +26,4 @@ public class GetSetPixel
return image[200, 200];
}
}
#endif

8
tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs

@ -78,7 +78,7 @@ public class BufferedStreams
public int StandardStreamRead()
{
int r = 0;
Stream stream = this.stream1;
MemoryStream stream = this.stream1;
byte[] b = this.chunk1;
for (int i = 0; i < stream.Length / 2; i++)
@ -138,7 +138,7 @@ public class BufferedStreams
public int StandardStreamReadByte()
{
int r = 0;
Stream stream = this.stream2;
MemoryStream stream = this.stream2;
for (int i = 0; i < stream.Length; i++)
{
@ -205,8 +205,8 @@ public class BufferedStreams
private static byte[] CreateTestBytes()
{
var buffer = new byte[Configuration.Default.StreamProcessingBufferSize * 3];
var random = new Random();
byte[] buffer = new byte[Configuration.Default.StreamProcessingBufferSize * 3];
Random random = new();
random.NextBytes(buffer);
return buffer;

18
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs

@ -184,14 +184,16 @@ public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConver
}
}
[Benchmark]
public void PixelConverter_Rgba32_ToArgb32()
{
Span<byte> source = MemoryMarshal.Cast<Rgba32, byte>(this.PermutedRunnerRgbaToArgb.Source);
Span<byte> dest = MemoryMarshal.Cast<TestArgb, byte>(this.PermutedRunnerRgbaToArgb.Destination);
PixelConverter.FromRgba32.ToArgb32(source, dest);
}
// Commenting this out because for some reason MSBuild is showing error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'System.Span<byte>'
// when trying to build via BenchmarkDotnet. (╯‵□′)╯︵┻━┻
// [Benchmark]
// public void PixelConverter_Rgba32_ToArgb32()
// {
// ReadOnlySpan<byte> source = MemoryMarshal.Cast<Rgba32, byte>(this.PermutedRunnerRgbaToArgb.Source);
// Span<byte> destination = MemoryMarshal.Cast<TestArgb, byte>(this.PermutedRunnerRgbaToArgb.Destination);
//
// PixelConverter.FromRgba32.ToArgb32(source, destination);
// }
/*
BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3)

5
tests/ImageSharp.Benchmarks/General/StructCasting.cs

@ -11,7 +11,7 @@ public class StructCasting
[Benchmark(Baseline = true)]
public short ExplicitCast()
{
int x = 5 * 2;
const int x = 5 * 2;
return (short)x;
}
@ -25,6 +25,7 @@ public class StructCasting
[Benchmark]
public short UnsafeCastRef()
{
return Unsafe.As<int, short>(ref Unsafe.AsRef(5 * 2));
int x = 5 * 2;
return Unsafe.As<int, short>(ref Unsafe.AsRef(ref x));
}
}

24
tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs

@ -15,10 +15,10 @@ public class DivFloat : SIMDBenchmarkBase<float>.Divide
[Benchmark(Baseline = true)]
public void Standard()
{
float v = this.testValue;
for (int i = 0; i < this.input.Length; i++)
float v = this.TestValue;
for (int i = 0; i < this.Input.Length; i++)
{
this.result[i] = this.input[i] / v;
this.Result[i] = this.Input[i] / v;
}
}
}
@ -30,10 +30,10 @@ public class Divide : SIMDBenchmarkBase<uint>.Divide
[Benchmark(Baseline = true)]
public void Standard()
{
uint v = this.testValue;
for (int i = 0; i < this.input.Length; i++)
uint v = this.TestValue;
for (int i = 0; i < this.Input.Length; i++)
{
this.result[i] = this.input[i] / v;
this.Result[i] = this.Input[i] / v;
}
}
}
@ -45,10 +45,10 @@ public class DivInt32 : SIMDBenchmarkBase<int>.Divide
[Benchmark(Baseline = true)]
public void Standard()
{
int v = this.testValue;
for (int i = 0; i < this.input.Length; i++)
int v = this.TestValue;
for (int i = 0; i < this.Input.Length; i++)
{
this.result[i] = this.input[i] / v;
this.Result[i] = this.Input[i] / v;
}
}
}
@ -62,10 +62,10 @@ public class DivInt16 : SIMDBenchmarkBase<short>.Divide
[Benchmark(Baseline = true)]
public void Standard()
{
short v = this.testValue;
for (int i = 0; i < this.input.Length; i++)
short v = this.TestValue;
for (int i = 0; i < this.Input.Length; i++)
{
this.result[i] = (short)(this.input[i] / v);
this.Result[i] = (short)(this.Input[i] / v);
}
}
}

18
tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs

@ -15,10 +15,10 @@ public class MulUInt32 : SIMDBenchmarkBase<uint>.Multiply
[Benchmark(Baseline = true)]
public void Standard()
{
uint v = this.testValue;
for (int i = 0; i < this.input.Length; i++)
uint v = this.TestValue;
for (int i = 0; i < this.Input.Length; i++)
{
this.result[i] = this.input[i] * v;
this.Result[i] = this.Input[i] * v;
}
}
}
@ -28,10 +28,10 @@ public class MulInt32 : SIMDBenchmarkBase<int>.Multiply
[Benchmark(Baseline = true)]
public void Standard()
{
int v = this.testValue;
for (int i = 0; i < this.input.Length; i++)
int v = this.TestValue;
for (int i = 0; i < this.Input.Length; i++)
{
this.result[i] = this.input[i] * v;
this.Result[i] = this.Input[i] * v;
}
}
}
@ -45,10 +45,10 @@ public class MulInt16 : SIMDBenchmarkBase<short>.Multiply
[Benchmark(Baseline = true)]
public void Standard()
{
short v = this.testValue;
for (int i = 0; i < this.input.Length; i++)
short v = this.TestValue;
for (int i = 0; i < this.Input.Length; i++)
{
this.result[i] = (short)(this.input[i] * v);
this.Result[i] = (short)(this.Input[i] * v);
}
}
}

44
tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs

@ -10,28 +10,28 @@ namespace ImageSharp.Benchmarks.General.Vectorization;
public abstract class SIMDBenchmarkBase<T>
where T : struct
{
protected T[] input;
protected virtual T GetTestValue() => default;
protected T[] result;
protected virtual Vector<T> GetTestVector() => new(this.GetTestValue());
protected T testValue;
[Params(32)]
public int InputSize { get; set; }
protected Vector<T> testVector;
protected T[] Input { get; set; }
protected virtual T GetTestValue() => default;
protected T[] Result { get; set; }
protected virtual Vector<T> GetTestVector() => new Vector<T>(this.GetTestValue());
protected T TestValue { get; set; }
[Params(32)]
public int InputSize { get; set; }
protected Vector<T> TestVector { get; set; }
[GlobalSetup]
public virtual void Setup()
{
this.input = new T[this.InputSize];
this.result = new T[this.InputSize];
this.testValue = this.GetTestValue();
this.testVector = this.GetTestVector();
this.Input = new T[this.InputSize];
this.Result = new T[this.InputSize];
this.TestValue = this.GetTestValue();
this.TestVector = this.GetTestVector();
}
public abstract class Multiply : SIMDBenchmarkBase<T>
@ -39,13 +39,13 @@ public abstract class SIMDBenchmarkBase<T>
[Benchmark]
public void Simd()
{
Vector<T> v = this.testVector;
Vector<T> v = this.TestVector;
for (int i = 0; i < this.input.Length; i += Vector<uint>.Count)
for (int i = 0; i < this.Input.Length; i += Vector<uint>.Count)
{
Vector<T> a = Unsafe.As<T, Vector<T>>(ref this.input[i]);
a = a * v;
Unsafe.As<T, Vector<T>>(ref this.result[i]) = a;
Vector<T> a = Unsafe.As<T, Vector<T>>(ref this.Input[i]);
a *= v;
Unsafe.As<T, Vector<T>>(ref this.Result[i]) = a;
}
}
}
@ -55,13 +55,13 @@ public abstract class SIMDBenchmarkBase<T>
[Benchmark]
public void Simd()
{
Vector<T> v = this.testVector;
Vector<T> v = this.TestVector;
for (int i = 0; i < this.input.Length; i += Vector<uint>.Count)
for (int i = 0; i < this.Input.Length; i += Vector<uint>.Count)
{
Vector<T> a = Unsafe.As<T, Vector<T>>(ref this.input[i]);
a = a / v;
Unsafe.As<T, Vector<T>>(ref this.result[i]) = a;
Vector<T> a = Unsafe.As<T, Vector<T>>(ref this.Input[i]);
a /= v;
Unsafe.As<T, Vector<T>>(ref this.Result[i]) = a;
}
}
}

20
tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

@ -15,9 +15,25 @@
</PropertyGroup>
<PropertyGroup>
<!--BenchmarkDotNet cannot run static benchmarks-->
<!--
BenchmarkDotNet requires a certain structure to the code,
as such, some of these rules cannot be implemented.
-->
<!--Mark members as static-->
<NoWarn>CA1822</NoWarn>
<!--Validate platform compatibility-->
<!--Types that own disposable fields should be disposable-->
<!--Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'System.Span<byte>'-->
<NoWarn>CA1822;CA1416;CA1001;CS0029;CA1861;CA2201</NoWarn>
<!--<NoWarn>CA1001</NoWarn>-->
<!--Validate platform compatibility-->
<!--<NoWarn>CA1416</NoWarn>-->
<!--Types that own disposable fields should be disposable-->
<!--<NoWarn>CA1001</NoWarn>-->
</PropertyGroup>
<Choose>

4
tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
@ -40,7 +41,7 @@ public class LoadResizeSaveStressRunner
public double TotalProcessedMegapixels { get; private set; }
public Size LastProcessedImageSize { get; private set; }
public ImageSharpSize LastProcessedImageSize { get; private set; }
private string outputDirectory;
@ -345,3 +346,4 @@ public class LoadResizeSaveStressRunner
thumb.Jpegsave(this.OutputPath(input), q: Quality, keep: NetVips.Enums.ForeignKeep.None);
}
}
#endif

10
tests/ImageSharp.Benchmarks/Processing/Crop.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing;
using System.Drawing.Drawing2D;
using BenchmarkDotNet.Attributes;
@ -17,9 +18,9 @@ public class Crop
[Benchmark(Baseline = true, Description = "System.Drawing Crop")]
public SDSize CropSystemDrawing()
{
using var source = new Bitmap(800, 800);
using var destination = new Bitmap(100, 100);
using var graphics = Graphics.FromImage(destination);
using Bitmap source = new(800, 800);
using Bitmap destination = new(100, 100);
using Graphics graphics = Graphics.FromImage(destination);
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
@ -32,8 +33,9 @@ public class Crop
[Benchmark(Description = "ImageSharp Crop")]
public Size CropImageSharp()
{
using var image = new Image<Rgba32>(800, 800);
using Image<Rgba32> image = new(800, 800);
image.Mutate(x => x.Crop(100, 100));
return new Size(image.Width, image.Height);
}
}
#endif

36
tests/ImageSharp.Benchmarks/Processing/Resize.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if OS_WINDOWS
using System.Drawing;
using System.Drawing.Drawing2D;
using BenchmarkDotNet.Attributes;
@ -16,7 +17,7 @@ namespace SixLabors.ImageSharp.Benchmarks;
public abstract class Resize<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private byte[] bytes = null;
private byte[] bytes;
private Image<TPixel> sourceImage;
@ -35,7 +36,7 @@ public abstract class Resize<TPixel>
this.sourceImage = Image.Load<TPixel>(this.bytes);
var ms1 = new MemoryStream(this.bytes);
MemoryStream ms1 = new(this.bytes);
this.sourceBitmap = SDImage.FromStream(ms1);
this.DestSize = this.sourceBitmap.Width / 2;
}
@ -52,21 +53,19 @@ public abstract class Resize<TPixel>
[Benchmark(Baseline = true)]
public int SystemDrawing()
{
using (var destination = new Bitmap(this.DestSize, this.DestSize))
using Bitmap destination = new(this.DestSize, this.DestSize);
using (Graphics g = Graphics.FromImage(destination))
{
using (var g = Graphics.FromImage(destination))
{
g.CompositingMode = CompositingMode.SourceCopy;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawImage(this.sourceBitmap, 0, 0, this.DestSize, this.DestSize);
}
return destination.Width;
g.CompositingMode = CompositingMode.SourceCopy;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawImage(this.sourceBitmap, 0, 0, this.DestSize, this.DestSize);
}
return destination.Width;
}
[Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 1")]
@ -87,10 +86,8 @@ public abstract class Resize<TPixel>
{
this.Configuration.MaxDegreeOfParallelism = maxDegreeOfParallelism;
using (Image<TPixel> clone = this.sourceImage.Clone(this.ExecuteResizeOperation))
{
return clone.Width;
}
using Image<TPixel> clone = this.sourceImage.Clone(this.ExecuteResizeOperation);
return clone.Width;
}
protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx);
@ -244,3 +241,4 @@ public class Resize_Bicubic_Compare_Rgba32_Rgb24
[Benchmark]
public void Rgb24() => this.rgb24.ImageSharp_P1();
}
#endif

Loading…
Cancel
Save