mirror of https://github.com/SixLabors/ImageSharp
125 changed files with 8147 additions and 8364 deletions
@ -1,49 +1,47 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Tests; |
|||
using SDImage = System.Drawing.Image; |
|||
using SDSize = System.Drawing.Size; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs; |
|||
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodeBmp |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodeBmp |
|||
{ |
|||
private byte[] bmpBytes; |
|||
private byte[] bmpBytes; |
|||
|
|||
private string TestImageFullPath |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
private string TestImageFullPath |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
|
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
{ |
|||
if (this.bmpBytes == null) |
|||
{ |
|||
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; } |
|||
[Params(TestImages.Bmp.Car)] |
|||
public string TestImage { get; set; } |
|||
|
|||
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")] |
|||
public SDSize BmpSystemDrawing() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.bmpBytes); |
|||
using var image = SDImage.FromStream(memoryStream); |
|||
return image.Size; |
|||
} |
|||
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")] |
|||
public SDSize BmpSystemDrawing() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.bmpBytes); |
|||
using var 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); |
|||
return new Size(image.Width, image.Height); |
|||
} |
|||
[Benchmark(Description = "ImageSharp Bmp")] |
|||
public Size BmpImageSharp() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.bmpBytes); |
|||
using var image = Image.Load<Rgba32>(memoryStream); |
|||
return new Size(image.Width, image.Height); |
|||
} |
|||
} |
|||
|
|||
@ -1,32 +1,30 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Drawing.Imaging; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Formats.Bmp; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs; |
|||
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded |
|||
{ |
|||
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; |
|||
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; |
|||
|
|||
[Benchmark(Description = "EncodeBmpMultiple - ImageSharp")] |
|||
public void EncodeBmpImageSharp() |
|||
=> this.ForEachImageSharpImage((img, ms) => |
|||
{ |
|||
img.Save(ms, new BmpEncoder()); |
|||
return null; |
|||
}); |
|||
[Benchmark(Description = "EncodeBmpMultiple - ImageSharp")] |
|||
public void EncodeBmpImageSharp() |
|||
=> this.ForEachImageSharpImage((img, ms) => |
|||
{ |
|||
img.Save(ms, new BmpEncoder()); |
|||
return null; |
|||
}); |
|||
|
|||
[Benchmark(Baseline = true, Description = "EncodeBmpMultiple - System.Drawing")] |
|||
public void EncodeBmpSystemDrawing() |
|||
=> this.ForEachSystemDrawingImage((img, ms) => |
|||
{ |
|||
img.Save(ms, ImageFormat.Bmp); |
|||
return null; |
|||
}); |
|||
} |
|||
[Benchmark(Baseline = true, Description = "EncodeBmpMultiple - System.Drawing")] |
|||
public void EncodeBmpSystemDrawing() |
|||
=> this.ForEachSystemDrawingImage((img, ms) => |
|||
{ |
|||
img.Save(ms, ImageFormat.Bmp); |
|||
return null; |
|||
}); |
|||
} |
|||
|
|||
@ -1,49 +1,47 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Tests; |
|||
using SDImage = System.Drawing.Image; |
|||
using SDSize = System.Drawing.Size; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs; |
|||
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodeGif |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodeGif |
|||
{ |
|||
private byte[] gifBytes; |
|||
private byte[] gifBytes; |
|||
|
|||
private string TestImageFullPath |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
private string TestImageFullPath |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
|
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
{ |
|||
if (this.gifBytes == null) |
|||
{ |
|||
if (this.gifBytes == null) |
|||
{ |
|||
this.gifBytes = File.ReadAllBytes(this.TestImageFullPath); |
|||
} |
|||
this.gifBytes = File.ReadAllBytes(this.TestImageFullPath); |
|||
} |
|||
} |
|||
|
|||
[Params(TestImages.Gif.Rings)] |
|||
public string TestImage { get; set; } |
|||
[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); |
|||
return image.Size; |
|||
} |
|||
[Benchmark(Baseline = true, Description = "System.Drawing Gif")] |
|||
public SDSize GifSystemDrawing() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.gifBytes); |
|||
using var 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); |
|||
return new Size(image.Width, image.Height); |
|||
} |
|||
[Benchmark(Description = "ImageSharp Gif")] |
|||
public Size GifImageSharp() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.gifBytes); |
|||
using var image = Image.Load<Rgba32>(memoryStream); |
|||
return new Size(image.Width, image.Height); |
|||
} |
|||
} |
|||
|
|||
@ -1,43 +1,41 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Drawing.Imaging; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Formats.Gif; |
|||
using SixLabors.ImageSharp.Processing; |
|||
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs; |
|||
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded |
|||
{ |
|||
[Params(InputImageCategory.AllImages)] |
|||
public override InputImageCategory InputCategory { get; set; } |
|||
[Params(InputImageCategory.AllImages)] |
|||
public override InputImageCategory InputCategory { get; set; } |
|||
|
|||
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Gif/" }; |
|||
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Gif/" }; |
|||
|
|||
[Benchmark(Description = "EncodeGifMultiple - ImageSharp")] |
|||
public void EncodeGifImageSharp() |
|||
=> this.ForEachImageSharpImage((img, ms) => |
|||
[Benchmark(Description = "EncodeGifMultiple - ImageSharp")] |
|||
public void EncodeGifImageSharp() |
|||
=> this.ForEachImageSharpImage((img, ms) => |
|||
{ |
|||
// Try to get as close to System.Drawing's output as possible
|
|||
var options = new GifEncoder |
|||
{ |
|||
// Try to get as close to System.Drawing's output as possible
|
|||
var options = new GifEncoder |
|||
{ |
|||
Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 }) |
|||
}; |
|||
Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 }) |
|||
}; |
|||
|
|||
img.Save(ms, options); |
|||
return null; |
|||
}); |
|||
img.Save(ms, options); |
|||
return null; |
|||
}); |
|||
|
|||
[Benchmark(Baseline = true, Description = "EncodeGifMultiple - System.Drawing")] |
|||
public void EncodeGifSystemDrawing() |
|||
=> this.ForEachSystemDrawingImage((img, ms) => |
|||
{ |
|||
img.Save(ms, ImageFormat.Gif); |
|||
return null; |
|||
}); |
|||
} |
|||
[Benchmark(Baseline = true, Description = "EncodeGifMultiple - System.Drawing")] |
|||
public void EncodeGifSystemDrawing() |
|||
=> this.ForEachSystemDrawingImage((img, ms) => |
|||
{ |
|||
img.Save(ms, ImageFormat.Gif); |
|||
return null; |
|||
}); |
|||
} |
|||
|
|||
@ -1,51 +1,49 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using SixLabors.ImageSharp.Formats.Jpeg.Components; |
|||
|
|||
// ReSharper disable InconsistentNaming
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations; |
|||
|
|||
public class Block8x8F_LoadFromInt16 |
|||
{ |
|||
public class Block8x8F_LoadFromInt16 |
|||
{ |
|||
private Block8x8 source; |
|||
private Block8x8 source; |
|||
|
|||
private Block8x8F dest = default; |
|||
private Block8x8F dest = default; |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
if (Vector<float>.Count != 8) |
|||
{ |
|||
if (Vector<float>.Count != 8) |
|||
{ |
|||
throw new NotSupportedException("Vector<float>.Count != 8"); |
|||
} |
|||
|
|||
for (short i = 0; i < Block8x8F.Size; i++) |
|||
{ |
|||
this.source[i] = i; |
|||
} |
|||
throw new NotSupportedException("Vector<float>.Count != 8"); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void Scalar() |
|||
for (short i = 0; i < Block8x8F.Size; i++) |
|||
{ |
|||
this.dest.LoadFromInt16Scalar(ref this.source); |
|||
this.source[i] = i; |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void ExtendedAvx2() |
|||
{ |
|||
this.dest.LoadFromInt16ExtendedAvx2(ref this.source); |
|||
} |
|||
[Benchmark(Baseline = true)] |
|||
public void Scalar() |
|||
{ |
|||
this.dest.LoadFromInt16Scalar(ref this.source); |
|||
} |
|||
|
|||
// RESULT:
|
|||
// Method | Mean | Error | StdDev | Scaled |
|
|||
// ------------- |---------:|----------:|----------:|-------:|
|
|||
// Scalar | 34.88 ns | 0.3296 ns | 0.3083 ns | 1.00 |
|
|||
// ExtendedAvx2 | 21.58 ns | 0.2125 ns | 0.1884 ns | 0.62 |
|
|||
[Benchmark] |
|||
public void ExtendedAvx2() |
|||
{ |
|||
this.dest.LoadFromInt16ExtendedAvx2(ref this.source); |
|||
} |
|||
|
|||
// RESULT:
|
|||
// Method | Mean | Error | StdDev | Scaled |
|
|||
// ------------- |---------:|----------:|----------:|-------:|
|
|||
// Scalar | 34.88 ns | 0.3296 ns | 0.3083 ns | 1.00 |
|
|||
// ExtendedAvx2 | 21.58 ns | 0.2125 ns | 0.1884 ns | 0.62 |
|
|||
} |
|||
|
|||
@ -1,61 +1,58 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; |
|||
|
|||
public abstract class ColorConversionBenchmark |
|||
{ |
|||
public abstract class ColorConversionBenchmark |
|||
{ |
|||
private readonly int componentCount; |
|||
private readonly int componentCount; |
|||
|
|||
public const int Count = 128; |
|||
public const int Count = 128; |
|||
|
|||
protected ColorConversionBenchmark(int componentCount) |
|||
=> this.componentCount = componentCount; |
|||
protected ColorConversionBenchmark(int componentCount) |
|||
=> this.componentCount = componentCount; |
|||
|
|||
protected Buffer2D<float>[] Input { get; private set; } |
|||
protected Buffer2D<float>[] Input { get; private set; } |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.Input = CreateRandomValues(this.componentCount, Count); |
|||
} |
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.Input = CreateRandomValues(this.componentCount, Count); |
|||
} |
|||
|
|||
[GlobalCleanup] |
|||
public void Cleanup() |
|||
[GlobalCleanup] |
|||
public void Cleanup() |
|||
{ |
|||
foreach (Buffer2D<float> buffer in this.Input) |
|||
{ |
|||
foreach (Buffer2D<float> buffer in this.Input) |
|||
{ |
|||
buffer.Dispose(); |
|||
} |
|||
buffer.Dispose(); |
|||
} |
|||
} |
|||
|
|||
private static Buffer2D<float>[] CreateRandomValues( |
|||
int componentCount, |
|||
int inputBufferLength, |
|||
float minVal = 0f, |
|||
float maxVal = 255f) |
|||
private static Buffer2D<float>[] CreateRandomValues( |
|||
int componentCount, |
|||
int inputBufferLength, |
|||
float minVal = 0f, |
|||
float maxVal = 255f) |
|||
{ |
|||
var rnd = new Random(42); |
|||
var buffers = new Buffer2D<float>[componentCount]; |
|||
for (int i = 0; i < componentCount; i++) |
|||
{ |
|||
var rnd = new Random(42); |
|||
var buffers = new Buffer2D<float>[componentCount]; |
|||
for (int i = 0; i < componentCount; i++) |
|||
{ |
|||
var values = new float[inputBufferLength]; |
|||
var values = new float[inputBufferLength]; |
|||
|
|||
for (int j = 0; j < inputBufferLength; j++) |
|||
{ |
|||
values[j] = ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; |
|||
} |
|||
|
|||
// no need to dispose when buffer is not array owner
|
|||
buffers[i] = Configuration.Default.MemoryAllocator.Allocate2D<float>(values.Length, 1); |
|||
for (int j = 0; j < inputBufferLength; j++) |
|||
{ |
|||
values[j] = ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; |
|||
} |
|||
|
|||
return buffers; |
|||
// no need to dispose when buffer is not array owner
|
|||
buffers[i] = Configuration.Default.MemoryAllocator.Allocate2D<float>(values.Length, 1); |
|||
} |
|||
|
|||
return buffers; |
|||
} |
|||
} |
|||
|
|||
@ -1,41 +1,39 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Collections.Generic; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Tests; |
|||
using SDImage = System.Drawing.Image; |
|||
|
|||
// ReSharper disable InconsistentNaming
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; |
|||
|
|||
/// <summary>
|
|||
/// An expensive Jpeg benchmark, running on a wide range of input images,
|
|||
/// showing aggregate results.
|
|||
/// </summary>
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase |
|||
{ |
|||
/// <summary>
|
|||
/// An expensive Jpeg benchmark, running on a wide range of input images,
|
|||
/// showing aggregate results.
|
|||
/// </summary>
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
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, |
|||
}; |
|||
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; } |
|||
[Params(InputImageCategory.AllImages)] |
|||
public override InputImageCategory InputCategory { get; set; } |
|||
|
|||
[Benchmark] |
|||
public void ImageSharp() |
|||
=> this.ForEachStream(ms => Image.Load<Rgba32>(ms)); |
|||
[Benchmark] |
|||
public void ImageSharp() |
|||
=> this.ForEachStream(ms => Image.Load<Rgba32>(ms)); |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void SystemDrawing() |
|||
=> this.ForEachStream(SDImage.FromStream); |
|||
} |
|||
[Benchmark(Baseline = true)] |
|||
public void SystemDrawing() |
|||
=> this.ForEachStream(SDImage.FromStream); |
|||
} |
|||
|
|||
@ -1,39 +1,37 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Formats.Jpeg; |
|||
using SixLabors.ImageSharp.Tests; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; |
|||
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class IdentifyJpeg |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class IdentifyJpeg |
|||
{ |
|||
private byte[] jpegBytes; |
|||
private byte[] jpegBytes; |
|||
|
|||
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
|
|||
[Params(TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Calliphora)] |
|||
public string TestImage { get; set; } |
|||
[Params(TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Calliphora)] |
|||
public string TestImage { get; set; } |
|||
|
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
{ |
|||
if (this.jpegBytes == null) |
|||
{ |
|||
if (this.jpegBytes == null) |
|||
{ |
|||
this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath); |
|||
} |
|||
this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public IImageInfo Identify() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.jpegBytes); |
|||
IImageDecoder decoder = new JpegDecoder(); |
|||
return decoder.Identify(DecoderOptions.Default, memoryStream, default); |
|||
} |
|||
[Benchmark] |
|||
public IImageInfo Identify() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.jpegBytes); |
|||
IImageDecoder decoder = new JpegDecoder(); |
|||
return decoder.Identify(DecoderOptions.Default, memoryStream, default); |
|||
} |
|||
} |
|||
|
|||
@ -1,67 +1,65 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using System.Runtime.CompilerServices; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Tests; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodeFilteredPng |
|||
{ |
|||
private byte[] filter0; |
|||
private byte[] filter1; |
|||
private byte[] filter2; |
|||
private byte[] filter3; |
|||
private byte[] averageFilter3bpp; |
|||
private byte[] averageFilter4bpp; |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs; |
|||
|
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
{ |
|||
this.filter0 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.Filter0)); |
|||
this.filter1 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.SubFilter3BytesPerPixel)); |
|||
this.filter2 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.UpFilter)); |
|||
this.filter3 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.PaethFilter3BytesPerPixel)); |
|||
this.averageFilter3bpp = File.ReadAllBytes(TestImageFullPath(TestImages.Png.AverageFilter3BytesPerPixel)); |
|||
this.averageFilter4bpp = File.ReadAllBytes(TestImageFullPath(TestImages.Png.AverageFilter4BytesPerPixel)); |
|||
} |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodeFilteredPng |
|||
{ |
|||
private byte[] filter0; |
|||
private byte[] filter1; |
|||
private byte[] filter2; |
|||
private byte[] filter3; |
|||
private byte[] averageFilter3bpp; |
|||
private byte[] averageFilter4bpp; |
|||
|
|||
[Benchmark(Baseline = true, Description = "None-filtered PNG file")] |
|||
public Size PngFilter0() |
|||
=> LoadPng(this.filter0); |
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
{ |
|||
this.filter0 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.Filter0)); |
|||
this.filter1 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.SubFilter3BytesPerPixel)); |
|||
this.filter2 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.UpFilter)); |
|||
this.filter3 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.PaethFilter3BytesPerPixel)); |
|||
this.averageFilter3bpp = File.ReadAllBytes(TestImageFullPath(TestImages.Png.AverageFilter3BytesPerPixel)); |
|||
this.averageFilter4bpp = File.ReadAllBytes(TestImageFullPath(TestImages.Png.AverageFilter4BytesPerPixel)); |
|||
} |
|||
|
|||
[Benchmark(Description = "Sub-filtered PNG file")] |
|||
public Size PngFilter1() |
|||
=> LoadPng(this.filter1); |
|||
[Benchmark(Baseline = true, Description = "None-filtered PNG file")] |
|||
public Size PngFilter0() |
|||
=> LoadPng(this.filter0); |
|||
|
|||
[Benchmark(Description = "Up-filtered PNG file")] |
|||
public Size PngFilter2() |
|||
=> LoadPng(this.filter2); |
|||
[Benchmark(Description = "Sub-filtered PNG file")] |
|||
public Size PngFilter1() |
|||
=> LoadPng(this.filter1); |
|||
|
|||
[Benchmark(Description = "Average-filtered PNG file (3bpp)")] |
|||
public Size PngAvgFilter1() |
|||
=> LoadPng(this.averageFilter3bpp); |
|||
[Benchmark(Description = "Up-filtered PNG file")] |
|||
public Size PngFilter2() |
|||
=> LoadPng(this.filter2); |
|||
|
|||
[Benchmark(Description = "Average-filtered PNG file (4bpp)")] |
|||
public Size PngAvgFilter2() |
|||
=> LoadPng(this.averageFilter4bpp); |
|||
[Benchmark(Description = "Average-filtered PNG file (3bpp)")] |
|||
public Size PngAvgFilter1() |
|||
=> LoadPng(this.averageFilter3bpp); |
|||
|
|||
[Benchmark(Description = "Paeth-filtered PNG file")] |
|||
public Size PngFilter4() |
|||
=> LoadPng(this.filter3); |
|||
[Benchmark(Description = "Average-filtered PNG file (4bpp)")] |
|||
public Size PngAvgFilter2() |
|||
=> LoadPng(this.averageFilter4bpp); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Size LoadPng(byte[] bytes) |
|||
{ |
|||
using var image = Image.Load<Rgba32>(bytes); |
|||
return image.Size(); |
|||
} |
|||
[Benchmark(Description = "Paeth-filtered PNG file")] |
|||
public Size PngFilter4() |
|||
=> LoadPng(this.filter3); |
|||
|
|||
private static string TestImageFullPath(string path) |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path); |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Size LoadPng(byte[] bytes) |
|||
{ |
|||
using var image = Image.Load<Rgba32>(bytes); |
|||
return image.Size(); |
|||
} |
|||
|
|||
private static string TestImageFullPath(string path) |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path); |
|||
} |
|||
|
|||
@ -1,49 +1,47 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Tests; |
|||
using SDImage = System.Drawing.Image; |
|||
using SDSize = System.Drawing.Size; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs; |
|||
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodePng |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class DecodePng |
|||
{ |
|||
private byte[] pngBytes; |
|||
private byte[] pngBytes; |
|||
|
|||
private string TestImageFullPath |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
private string TestImageFullPath |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
|
|||
[Params(TestImages.Png.Splash)] |
|||
public string TestImage { get; set; } |
|||
[Params(TestImages.Png.Splash)] |
|||
public string TestImage { get; set; } |
|||
|
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
{ |
|||
if (this.pngBytes == null) |
|||
{ |
|||
if (this.pngBytes == null) |
|||
{ |
|||
this.pngBytes = File.ReadAllBytes(this.TestImageFullPath); |
|||
} |
|||
this.pngBytes = File.ReadAllBytes(this.TestImageFullPath); |
|||
} |
|||
} |
|||
|
|||
[Benchmark(Baseline = true, Description = "System.Drawing Png")] |
|||
public SDSize PngSystemDrawing() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.pngBytes); |
|||
using var image = SDImage.FromStream(memoryStream); |
|||
return image.Size; |
|||
} |
|||
[Benchmark(Baseline = true, Description = "System.Drawing Png")] |
|||
public SDSize PngSystemDrawing() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.pngBytes); |
|||
using var image = SDImage.FromStream(memoryStream); |
|||
return image.Size; |
|||
} |
|||
|
|||
[Benchmark(Description = "ImageSharp Png")] |
|||
public Size PngImageSharp() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.pngBytes); |
|||
using var image = Image.Load<Rgba32>(memoryStream); |
|||
return image.Size(); |
|||
} |
|||
[Benchmark(Description = "ImageSharp Png")] |
|||
public Size PngImageSharp() |
|||
{ |
|||
using var memoryStream = new MemoryStream(this.pngBytes); |
|||
using var image = Image.Load<Rgba32>(memoryStream); |
|||
return image.Size(); |
|||
} |
|||
} |
|||
|
|||
@ -1,56 +1,54 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.IO; |
|||
using BenchmarkDotNet.Attributes; |
|||
using ImageMagick; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Tests; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs |
|||
namespace SixLabors.ImageSharp.Benchmarks.Codecs; |
|||
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class EncodeTga |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class EncodeTga |
|||
{ |
|||
private MagickImage tgaMagick; |
|||
private Image<Rgba32> tga; |
|||
private MagickImage tgaMagick; |
|||
private Image<Rgba32> tga; |
|||
|
|||
private string TestImageFullPath |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
private string TestImageFullPath |
|||
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); |
|||
|
|||
[Params(TestImages.Tga.Bit24BottomLeft)] |
|||
public string TestImage { get; set; } |
|||
[Params(TestImages.Tga.Bit24BottomLeft)] |
|||
public string TestImage { get; set; } |
|||
|
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
[GlobalSetup] |
|||
public void ReadImages() |
|||
{ |
|||
if (this.tga == null) |
|||
{ |
|||
if (this.tga == null) |
|||
{ |
|||
this.tga = Image.Load<Rgba32>(this.TestImageFullPath); |
|||
this.tgaMagick = new MagickImage(this.TestImageFullPath); |
|||
} |
|||
this.tga = Image.Load<Rgba32>(this.TestImageFullPath); |
|||
this.tgaMagick = new MagickImage(this.TestImageFullPath); |
|||
} |
|||
} |
|||
|
|||
[GlobalCleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.tga.Dispose(); |
|||
this.tga = null; |
|||
this.tgaMagick.Dispose(); |
|||
} |
|||
[GlobalCleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.tga.Dispose(); |
|||
this.tga = null; |
|||
this.tgaMagick.Dispose(); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true, Description = "Magick Tga")] |
|||
public void MagickTga() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
this.tgaMagick.Write(memoryStream, MagickFormat.Tga); |
|||
} |
|||
[Benchmark(Baseline = true, Description = "Magick Tga")] |
|||
public void MagickTga() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
this.tgaMagick.Write(memoryStream, MagickFormat.Tga); |
|||
} |
|||
|
|||
[Benchmark(Description = "ImageSharp Tga")] |
|||
public void ImageSharpTga() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
this.tga.SaveAsTga(memoryStream); |
|||
} |
|||
[Benchmark(Description = "ImageSharp Tga")] |
|||
public void ImageSharpTga() |
|||
{ |
|||
using var memoryStream = new MemoryStream(); |
|||
this.tga.SaveAsTga(memoryStream); |
|||
} |
|||
} |
|||
|
|||
@ -1,87 +1,85 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk |
|||
{ |
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class Pad3Shuffle4Channel |
|||
{ |
|||
private static readonly DefaultPad3Shuffle4 Control = new DefaultPad3Shuffle4(1, 0, 3, 2); |
|||
private static readonly XYZWPad3Shuffle4 ControlFast = default; |
|||
private byte[] source; |
|||
private byte[] destination; |
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
new Random(this.Count).NextBytes(this.source); |
|||
this.destination = new byte[this.Count * 4 / 3]; |
|||
} |
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class Pad3Shuffle4Channel |
|||
{ |
|||
private static readonly DefaultPad3Shuffle4 Control = new DefaultPad3Shuffle4(1, 0, 3, 2); |
|||
private static readonly XYZWPad3Shuffle4 ControlFast = default; |
|||
private byte[] source; |
|||
private byte[] destination; |
|||
|
|||
[Params(96, 384, 768, 1536)] |
|||
public int Count { get; set; } |
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
new Random(this.Count).NextBytes(this.source); |
|||
this.destination = new byte[this.Count * 4 / 3]; |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void Pad3Shuffle4() |
|||
{ |
|||
SimdUtils.Pad3Shuffle4(this.source, this.destination, Control); |
|||
} |
|||
[Params(96, 384, 768, 1536)] |
|||
public int Count { get; set; } |
|||
|
|||
[Benchmark] |
|||
public void Pad3Shuffle4FastFallback() |
|||
{ |
|||
SimdUtils.Pad3Shuffle4(this.source, this.destination, ControlFast); |
|||
} |
|||
[Benchmark] |
|||
public void Pad3Shuffle4() |
|||
{ |
|||
SimdUtils.Pad3Shuffle4(this.source, this.destination, Control); |
|||
} |
|||
|
|||
// 2020-10-30
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |------------------------- |------------------- |-------------------------------------------------- |------ |------------:|----------:|----------:|------------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Pad3Shuffle4 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 96 | 120.64 ns | 7.190 ns | 21.200 ns | 114.26 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 2. AVX | Empty | 96 | 23.63 ns | 0.175 ns | 0.155 ns | 23.65 ns | 0.15 | 0.01 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 3. SSE | COMPlus_EnableAVX=0 | 96 | 25.25 ns | 0.356 ns | 0.298 ns | 25.27 ns | 0.17 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 96 | 14.80 ns | 0.358 ns | 1.032 ns | 14.64 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 2. AVX | Empty | 96 | 24.84 ns | 0.376 ns | 0.333 ns | 24.74 ns | 1.57 | 0.06 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 96 | 24.58 ns | 0.471 ns | 0.704 ns | 24.38 ns | 1.60 | 0.09 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 384 | 258.92 ns | 4.873 ns | 4.069 ns | 257.95 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 2. AVX | Empty | 384 | 41.41 ns | 0.859 ns | 1.204 ns | 41.33 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 3. SSE | COMPlus_EnableAVX=0 | 384 | 40.74 ns | 0.848 ns | 0.793 ns | 40.48 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 384 | 74.50 ns | 0.490 ns | 0.383 ns | 74.49 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 2. AVX | Empty | 384 | 40.74 ns | 0.624 ns | 0.584 ns | 40.72 ns | 0.55 | 0.01 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 384 | 38.28 ns | 0.534 ns | 0.417 ns | 38.22 ns | 0.51 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 768 | 503.91 ns | 6.466 ns | 6.048 ns | 501.58 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 2. AVX | Empty | 768 | 62.86 ns | 0.332 ns | 0.277 ns | 62.80 ns | 0.12 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 3. SSE | COMPlus_EnableAVX=0 | 768 | 64.59 ns | 0.469 ns | 0.415 ns | 64.62 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 768 | 110.51 ns | 0.592 ns | 0.554 ns | 110.33 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 2. AVX | Empty | 768 | 64.72 ns | 1.306 ns | 1.090 ns | 64.51 ns | 0.59 | 0.01 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 768 | 62.11 ns | 0.816 ns | 0.682 ns | 61.98 ns | 0.56 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1536 | 1,005.84 ns | 13.176 ns | 12.325 ns | 1,004.70 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 2. AVX | Empty | 1536 | 110.05 ns | 0.256 ns | 0.214 ns | 110.04 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 3. SSE | COMPlus_EnableAVX=0 | 1536 | 110.23 ns | 0.545 ns | 0.483 ns | 110.09 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1536 | 220.37 ns | 1.601 ns | 1.419 ns | 220.13 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 2. AVX | Empty | 1536 | 111.54 ns | 2.173 ns | 2.901 ns | 111.27 ns | 0.51 | 0.01 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 1536 | 110.23 ns | 0.456 ns | 0.427 ns | 110.25 ns | 0.50 | 0.00 | - | - | - | - |
|
|||
[Benchmark] |
|||
public void Pad3Shuffle4FastFallback() |
|||
{ |
|||
SimdUtils.Pad3Shuffle4(this.source, this.destination, ControlFast); |
|||
} |
|||
} |
|||
|
|||
// 2020-10-30
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |------------------------- |------------------- |-------------------------------------------------- |------ |------------:|----------:|----------:|------------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Pad3Shuffle4 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 96 | 120.64 ns | 7.190 ns | 21.200 ns | 114.26 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 2. AVX | Empty | 96 | 23.63 ns | 0.175 ns | 0.155 ns | 23.65 ns | 0.15 | 0.01 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 3. SSE | COMPlus_EnableAVX=0 | 96 | 25.25 ns | 0.356 ns | 0.298 ns | 25.27 ns | 0.17 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 96 | 14.80 ns | 0.358 ns | 1.032 ns | 14.64 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 2. AVX | Empty | 96 | 24.84 ns | 0.376 ns | 0.333 ns | 24.74 ns | 1.57 | 0.06 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 96 | 24.58 ns | 0.471 ns | 0.704 ns | 24.38 ns | 1.60 | 0.09 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 384 | 258.92 ns | 4.873 ns | 4.069 ns | 257.95 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 2. AVX | Empty | 384 | 41.41 ns | 0.859 ns | 1.204 ns | 41.33 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 3. SSE | COMPlus_EnableAVX=0 | 384 | 40.74 ns | 0.848 ns | 0.793 ns | 40.48 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 384 | 74.50 ns | 0.490 ns | 0.383 ns | 74.49 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 2. AVX | Empty | 384 | 40.74 ns | 0.624 ns | 0.584 ns | 40.72 ns | 0.55 | 0.01 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 384 | 38.28 ns | 0.534 ns | 0.417 ns | 38.22 ns | 0.51 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 768 | 503.91 ns | 6.466 ns | 6.048 ns | 501.58 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 2. AVX | Empty | 768 | 62.86 ns | 0.332 ns | 0.277 ns | 62.80 ns | 0.12 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 3. SSE | COMPlus_EnableAVX=0 | 768 | 64.59 ns | 0.469 ns | 0.415 ns | 64.62 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 768 | 110.51 ns | 0.592 ns | 0.554 ns | 110.33 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 2. AVX | Empty | 768 | 64.72 ns | 1.306 ns | 1.090 ns | 64.51 ns | 0.59 | 0.01 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 768 | 62.11 ns | 0.816 ns | 0.682 ns | 61.98 ns | 0.56 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1536 | 1,005.84 ns | 13.176 ns | 12.325 ns | 1,004.70 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 2. AVX | Empty | 1536 | 110.05 ns | 0.256 ns | 0.214 ns | 110.04 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4 | 3. SSE | COMPlus_EnableAVX=0 | 1536 | 110.23 ns | 0.545 ns | 0.483 ns | 110.09 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Pad3Shuffle4FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1536 | 220.37 ns | 1.601 ns | 1.419 ns | 220.13 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 2. AVX | Empty | 1536 | 111.54 ns | 2.173 ns | 2.901 ns | 111.27 ns | 0.51 | 0.01 | - | - | - | - |
|
|||
// | Pad3Shuffle4FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 1536 | 110.23 ns | 0.456 ns | 0.427 ns | 110.25 ns | 0.50 | 0.00 | - | - | - | - |
|
|||
|
|||
@ -1,68 +1,66 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk |
|||
{ |
|||
[Config(typeof(Config.ShortCore31))] |
|||
public class PremultiplyVector4 |
|||
{ |
|||
private static readonly Vector4[] Vectors = CreateVectors(); |
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void PremultiplyBaseline() |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference<Vector4>(Vectors); |
|||
[Config(typeof(Config.ShortCore31))] |
|||
public class PremultiplyVector4 |
|||
{ |
|||
private static readonly Vector4[] Vectors = CreateVectors(); |
|||
|
|||
for (int i = 0; i < Vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
Premultiply(ref v); |
|||
} |
|||
} |
|||
[Benchmark(Baseline = true)] |
|||
public void PremultiplyBaseline() |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference<Vector4>(Vectors); |
|||
|
|||
[Benchmark] |
|||
public void Premultiply() |
|||
for (int i = 0; i < Vectors.Length; i++) |
|||
{ |
|||
Numerics.Premultiply(Vectors); |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
Premultiply(ref v); |
|||
} |
|||
} |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private static void Premultiply(ref Vector4 source) |
|||
{ |
|||
float w = source.W; |
|||
source *= w; |
|||
source.W = w; |
|||
} |
|||
[Benchmark] |
|||
public void Premultiply() |
|||
{ |
|||
Numerics.Premultiply(Vectors); |
|||
} |
|||
|
|||
private static Vector4[] CreateVectors() |
|||
{ |
|||
var rnd = new Random(42); |
|||
return GenerateRandomVectorArray(rnd, 2048, 0, 1); |
|||
} |
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private static void Premultiply(ref Vector4 source) |
|||
{ |
|||
float w = source.W; |
|||
source *= w; |
|||
source.W = w; |
|||
} |
|||
|
|||
private static Vector4[] GenerateRandomVectorArray(Random rnd, int length, float minVal, float maxVal) |
|||
{ |
|||
var values = new Vector4[length]; |
|||
private static Vector4[] CreateVectors() |
|||
{ |
|||
var rnd = new Random(42); |
|||
return GenerateRandomVectorArray(rnd, 2048, 0, 1); |
|||
} |
|||
|
|||
for (int i = 0; i < length; i++) |
|||
{ |
|||
ref Vector4 v = ref values[i]; |
|||
v.X = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Y = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Z = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.W = GetRandomFloat(rnd, minVal, maxVal); |
|||
} |
|||
private static Vector4[] GenerateRandomVectorArray(Random rnd, int length, float minVal, float maxVal) |
|||
{ |
|||
var values = new Vector4[length]; |
|||
|
|||
return values; |
|||
for (int i = 0; i < length; i++) |
|||
{ |
|||
ref Vector4 v = ref values[i]; |
|||
v.X = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Y = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Z = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.W = GetRandomFloat(rnd, minVal, maxVal); |
|||
} |
|||
|
|||
private static float GetRandomFloat(Random rnd, float minVal, float maxVal) |
|||
=> ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; |
|||
return values; |
|||
} |
|||
|
|||
private static float GetRandomFloat(Random rnd, float minVal, float maxVal) |
|||
=> ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; |
|||
} |
|||
|
|||
@ -1,64 +1,62 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk |
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; |
|||
|
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class Shuffle3Channel |
|||
{ |
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class Shuffle3Channel |
|||
{ |
|||
private static readonly DefaultShuffle3 Control = new DefaultShuffle3(1, 0, 2); |
|||
private byte[] source; |
|||
private byte[] destination; |
|||
private static readonly DefaultShuffle3 Control = new DefaultShuffle3(1, 0, 2); |
|||
private byte[] source; |
|||
private byte[] destination; |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
new Random(this.Count).NextBytes(this.source); |
|||
this.destination = new byte[this.Count]; |
|||
} |
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
new Random(this.Count).NextBytes(this.source); |
|||
this.destination = new byte[this.Count]; |
|||
} |
|||
|
|||
[Params(96, 384, 768, 1536)] |
|||
public int Count { get; set; } |
|||
[Params(96, 384, 768, 1536)] |
|||
public int Count { get; set; } |
|||
|
|||
[Benchmark] |
|||
public void Shuffle3() |
|||
{ |
|||
SimdUtils.Shuffle3(this.source, this.destination, Control); |
|||
} |
|||
[Benchmark] |
|||
public void Shuffle3() |
|||
{ |
|||
SimdUtils.Shuffle3(this.source, this.destination, Control); |
|||
} |
|||
|
|||
// 2020-11-02
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |--------------------- |------------------- |-------------------------------------------------- |------ |----------:|---------:|---------:|----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 96 | 48.46 ns | 1.034 ns | 2.438 ns | 47.46 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 2. AVX | Empty | 96 | 32.42 ns | 0.537 ns | 0.476 ns | 32.34 ns | 0.66 | 0.04 | - | - | - | - |
|
|||
// | Shuffle3 | 3. SSE | COMPlus_EnableAVX=0 | 96 | 32.51 ns | 0.373 ns | 0.349 ns | 32.56 ns | 0.66 | 0.03 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 384 | 199.04 ns | 1.512 ns | 1.180 ns | 199.17 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 2. AVX | Empty | 384 | 71.20 ns | 2.654 ns | 7.784 ns | 69.60 ns | 0.41 | 0.02 | - | - | - | - |
|
|||
// | Shuffle3 | 3. SSE | COMPlus_EnableAVX=0 | 384 | 63.23 ns | 0.569 ns | 0.505 ns | 63.21 ns | 0.32 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 768 | 391.28 ns | 5.087 ns | 3.972 ns | 391.22 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 2. AVX | Empty | 768 | 109.12 ns | 2.149 ns | 2.010 ns | 108.66 ns | 0.28 | 0.01 | - | - | - | - |
|
|||
// | Shuffle3 | 3. SSE | COMPlus_EnableAVX=0 | 768 | 106.51 ns | 0.734 ns | 0.613 ns | 106.56 ns | 0.27 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1536 | 773.70 ns | 5.516 ns | 4.890 ns | 772.96 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 2. AVX | Empty | 1536 | 190.41 ns | 1.090 ns | 0.851 ns | 190.38 ns | 0.25 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 3. SSE | COMPlus_EnableAVX=0 | 1536 | 190.94 ns | 0.985 ns | 0.769 ns | 190.85 ns | 0.25 | 0.00 | - | - | - | - |
|
|||
} |
|||
|
|||
// 2020-11-02
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |--------------------- |------------------- |-------------------------------------------------- |------ |----------:|---------:|---------:|----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 96 | 48.46 ns | 1.034 ns | 2.438 ns | 47.46 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 2. AVX | Empty | 96 | 32.42 ns | 0.537 ns | 0.476 ns | 32.34 ns | 0.66 | 0.04 | - | - | - | - |
|
|||
// | Shuffle3 | 3. SSE | COMPlus_EnableAVX=0 | 96 | 32.51 ns | 0.373 ns | 0.349 ns | 32.56 ns | 0.66 | 0.03 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 384 | 199.04 ns | 1.512 ns | 1.180 ns | 199.17 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 2. AVX | Empty | 384 | 71.20 ns | 2.654 ns | 7.784 ns | 69.60 ns | 0.41 | 0.02 | - | - | - | - |
|
|||
// | Shuffle3 | 3. SSE | COMPlus_EnableAVX=0 | 384 | 63.23 ns | 0.569 ns | 0.505 ns | 63.21 ns | 0.32 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 768 | 391.28 ns | 5.087 ns | 3.972 ns | 391.22 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 2. AVX | Empty | 768 | 109.12 ns | 2.149 ns | 2.010 ns | 108.66 ns | 0.28 | 0.01 | - | - | - | - |
|
|||
// | Shuffle3 | 3. SSE | COMPlus_EnableAVX=0 | 768 | 106.51 ns | 0.734 ns | 0.613 ns | 106.56 ns | 0.27 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1536 | 773.70 ns | 5.516 ns | 4.890 ns | 772.96 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 2. AVX | Empty | 1536 | 190.41 ns | 1.090 ns | 0.851 ns | 190.38 ns | 0.25 | 0.00 | - | - | - | - |
|
|||
// | Shuffle3 | 3. SSE | COMPlus_EnableAVX=0 | 1536 | 190.94 ns | 0.985 ns | 0.769 ns | 190.85 ns | 0.25 | 0.00 | - | - | - | - |
|
|||
|
|||
@ -1,95 +1,93 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk |
|||
{ |
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class Shuffle4Slice3Channel |
|||
{ |
|||
private static readonly DefaultShuffle4Slice3 Control = new DefaultShuffle4Slice3(1, 0, 3, 2); |
|||
private static readonly XYZWShuffle4Slice3 ControlFast = default; |
|||
private byte[] source; |
|||
private byte[] destination; |
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
new Random(this.Count).NextBytes(this.source); |
|||
this.destination = new byte[(int)(this.Count * (3 / 4F))]; |
|||
} |
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class Shuffle4Slice3Channel |
|||
{ |
|||
private static readonly DefaultShuffle4Slice3 Control = new DefaultShuffle4Slice3(1, 0, 3, 2); |
|||
private static readonly XYZWShuffle4Slice3 ControlFast = default; |
|||
private byte[] source; |
|||
private byte[] destination; |
|||
|
|||
[Params(128, 256, 512, 1024, 2048)] |
|||
public int Count { get; set; } |
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
new Random(this.Count).NextBytes(this.source); |
|||
this.destination = new byte[(int)(this.Count * (3 / 4F))]; |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void Shuffle4Slice3() |
|||
{ |
|||
SimdUtils.Shuffle4Slice3(this.source, this.destination, Control); |
|||
} |
|||
[Params(128, 256, 512, 1024, 2048)] |
|||
public int Count { get; set; } |
|||
|
|||
[Benchmark] |
|||
public void Shuffle4Slice3FastFallback() |
|||
{ |
|||
SimdUtils.Shuffle4Slice3(this.source, this.destination, ControlFast); |
|||
} |
|||
[Benchmark] |
|||
public void Shuffle4Slice3() |
|||
{ |
|||
SimdUtils.Shuffle4Slice3(this.source, this.destination, Control); |
|||
} |
|||
|
|||
// 2020-10-29
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |--------------------------- |------------------- |-------------------------------------------------- |------ |----------:|---------:|---------:|----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 128 | 56.44 ns | 2.843 ns | 8.382 ns | 56.70 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 128 | 27.15 ns | 0.556 ns | 0.762 ns | 27.34 ns | 0.41 | 0.03 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 128 | 26.36 ns | 0.321 ns | 0.268 ns | 26.26 ns | 0.38 | 0.02 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 128 | 25.85 ns | 0.494 ns | 0.462 ns | 25.84 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 128 | 26.15 ns | 0.113 ns | 0.106 ns | 26.16 ns | 1.01 | 0.02 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 128 | 25.57 ns | 0.078 ns | 0.061 ns | 25.56 ns | 0.99 | 0.02 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 256 | 97.47 ns | 0.327 ns | 0.289 ns | 97.35 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 256 | 32.61 ns | 0.107 ns | 0.095 ns | 32.62 ns | 0.33 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 256 | 33.21 ns | 0.169 ns | 0.150 ns | 33.15 ns | 0.34 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 256 | 52.34 ns | 0.779 ns | 0.729 ns | 51.94 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 256 | 32.16 ns | 0.111 ns | 0.104 ns | 32.16 ns | 0.61 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 256 | 33.61 ns | 0.342 ns | 0.319 ns | 33.62 ns | 0.64 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 512 | 210.74 ns | 3.825 ns | 5.956 ns | 207.70 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 512 | 51.03 ns | 0.535 ns | 0.501 ns | 51.18 ns | 0.24 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 512 | 66.60 ns | 1.313 ns | 1.613 ns | 65.93 ns | 0.31 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 512 | 119.12 ns | 1.905 ns | 1.689 ns | 118.52 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 512 | 50.33 ns | 0.382 ns | 0.339 ns | 50.41 ns | 0.42 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 512 | 49.25 ns | 0.555 ns | 0.492 ns | 49.26 ns | 0.41 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1024 | 423.55 ns | 4.891 ns | 4.336 ns | 423.27 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 1024 | 77.13 ns | 1.355 ns | 2.264 ns | 76.19 ns | 0.19 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 1024 | 79.39 ns | 0.103 ns | 0.086 ns | 79.37 ns | 0.19 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1024 | 226.57 ns | 2.930 ns | 2.598 ns | 226.10 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 1024 | 80.25 ns | 1.647 ns | 2.082 ns | 80.98 ns | 0.35 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 1024 | 84.99 ns | 1.234 ns | 1.155 ns | 85.60 ns | 0.38 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 2048 | 794.96 ns | 1.735 ns | 1.538 ns | 795.15 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 2048 | 128.41 ns | 0.417 ns | 0.390 ns | 128.24 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 2048 | 127.24 ns | 0.294 ns | 0.229 ns | 127.23 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 2048 | 382.97 ns | 1.064 ns | 0.831 ns | 382.87 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 2048 | 126.93 ns | 0.382 ns | 0.339 ns | 126.94 ns | 0.33 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 2048 | 149.36 ns | 1.875 ns | 1.754 ns | 149.33 ns | 0.39 | 0.00 | - | - | - | - |
|
|||
[Benchmark] |
|||
public void Shuffle4Slice3FastFallback() |
|||
{ |
|||
SimdUtils.Shuffle4Slice3(this.source, this.destination, ControlFast); |
|||
} |
|||
} |
|||
|
|||
// 2020-10-29
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |--------------------------- |------------------- |-------------------------------------------------- |------ |----------:|---------:|---------:|----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 128 | 56.44 ns | 2.843 ns | 8.382 ns | 56.70 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 128 | 27.15 ns | 0.556 ns | 0.762 ns | 27.34 ns | 0.41 | 0.03 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 128 | 26.36 ns | 0.321 ns | 0.268 ns | 26.26 ns | 0.38 | 0.02 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 128 | 25.85 ns | 0.494 ns | 0.462 ns | 25.84 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 128 | 26.15 ns | 0.113 ns | 0.106 ns | 26.16 ns | 1.01 | 0.02 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 128 | 25.57 ns | 0.078 ns | 0.061 ns | 25.56 ns | 0.99 | 0.02 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 256 | 97.47 ns | 0.327 ns | 0.289 ns | 97.35 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 256 | 32.61 ns | 0.107 ns | 0.095 ns | 32.62 ns | 0.33 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 256 | 33.21 ns | 0.169 ns | 0.150 ns | 33.15 ns | 0.34 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 256 | 52.34 ns | 0.779 ns | 0.729 ns | 51.94 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 256 | 32.16 ns | 0.111 ns | 0.104 ns | 32.16 ns | 0.61 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 256 | 33.61 ns | 0.342 ns | 0.319 ns | 33.62 ns | 0.64 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 512 | 210.74 ns | 3.825 ns | 5.956 ns | 207.70 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 512 | 51.03 ns | 0.535 ns | 0.501 ns | 51.18 ns | 0.24 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 512 | 66.60 ns | 1.313 ns | 1.613 ns | 65.93 ns | 0.31 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 512 | 119.12 ns | 1.905 ns | 1.689 ns | 118.52 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 512 | 50.33 ns | 0.382 ns | 0.339 ns | 50.41 ns | 0.42 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 512 | 49.25 ns | 0.555 ns | 0.492 ns | 49.26 ns | 0.41 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1024 | 423.55 ns | 4.891 ns | 4.336 ns | 423.27 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 1024 | 77.13 ns | 1.355 ns | 2.264 ns | 76.19 ns | 0.19 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 1024 | 79.39 ns | 0.103 ns | 0.086 ns | 79.37 ns | 0.19 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1024 | 226.57 ns | 2.930 ns | 2.598 ns | 226.10 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 1024 | 80.25 ns | 1.647 ns | 2.082 ns | 80.98 ns | 0.35 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 1024 | 84.99 ns | 1.234 ns | 1.155 ns | 85.60 ns | 0.38 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 2048 | 794.96 ns | 1.735 ns | 1.538 ns | 795.15 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 2. AVX | Empty | 2048 | 128.41 ns | 0.417 ns | 0.390 ns | 128.24 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3 | 3. SSE | COMPlus_EnableAVX=0 | 2048 | 127.24 ns | 0.294 ns | 0.229 ns | 127.23 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | | |
|
|||
// | Shuffle4Slice3FastFallback | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 2048 | 382.97 ns | 1.064 ns | 0.831 ns | 382.87 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 2. AVX | Empty | 2048 | 126.93 ns | 0.382 ns | 0.339 ns | 126.94 ns | 0.33 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Slice3FastFallback | 3. SSE | COMPlus_EnableAVX=0 | 2048 | 149.36 ns | 1.875 ns | 1.754 ns | 149.33 ns | 0.39 | 0.00 | - | - | - | - |
|
|||
|
|||
@ -1,67 +1,65 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk |
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; |
|||
|
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class ShuffleByte4Channel |
|||
{ |
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class ShuffleByte4Channel |
|||
{ |
|||
private byte[] source; |
|||
private byte[] destination; |
|||
private byte[] source; |
|||
private byte[] destination; |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
new Random(this.Count).NextBytes(this.source); |
|||
this.destination = new byte[this.Count]; |
|||
} |
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
new Random(this.Count).NextBytes(this.source); |
|||
this.destination = new byte[this.Count]; |
|||
} |
|||
|
|||
[Params(128, 256, 512, 1024, 2048)] |
|||
public int Count { get; set; } |
|||
[Params(128, 256, 512, 1024, 2048)] |
|||
public int Count { get; set; } |
|||
|
|||
[Benchmark] |
|||
public void Shuffle4Channel() |
|||
{ |
|||
SimdUtils.Shuffle4<WXYZShuffle4>(this.source, this.destination, default); |
|||
} |
|||
[Benchmark] |
|||
public void Shuffle4Channel() |
|||
{ |
|||
SimdUtils.Shuffle4<WXYZShuffle4>(this.source, this.destination, default); |
|||
} |
|||
|
|||
// 2020-10-29
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |---------------- |------------------- |-------------------------------------------------- |------ |----------:|---------:|---------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 128 | 17.39 ns | 0.187 ns | 0.175 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 128 | 21.72 ns | 0.299 ns | 0.279 ns | 1.25 | 0.02 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 128 | 18.10 ns | 0.346 ns | 0.289 ns | 1.04 | 0.02 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 256 | 35.51 ns | 0.711 ns | 0.790 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 256 | 23.90 ns | 0.508 ns | 0.820 ns | 0.69 | 0.02 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 256 | 20.40 ns | 0.133 ns | 0.111 ns | 0.57 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 512 | 73.39 ns | 0.310 ns | 0.259 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 512 | 26.10 ns | 0.418 ns | 0.391 ns | 0.36 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 512 | 27.59 ns | 0.556 ns | 0.571 ns | 0.38 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1024 | 150.64 ns | 2.903 ns | 2.716 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 1024 | 38.67 ns | 0.801 ns | 1.889 ns | 0.24 | 0.02 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 1024 | 47.13 ns | 0.948 ns | 1.054 ns | 0.31 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 2048 | 315.29 ns | 5.206 ns | 6.583 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 2048 | 57.37 ns | 1.152 ns | 1.078 ns | 0.18 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 2048 | 65.75 ns | 1.198 ns | 1.600 ns | 0.21 | 0.01 | - | - | - | - |
|
|||
} |
|||
|
|||
// 2020-10-29
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |---------------- |------------------- |-------------------------------------------------- |------ |----------:|---------:|---------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 128 | 17.39 ns | 0.187 ns | 0.175 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 128 | 21.72 ns | 0.299 ns | 0.279 ns | 1.25 | 0.02 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 128 | 18.10 ns | 0.346 ns | 0.289 ns | 1.04 | 0.02 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 256 | 35.51 ns | 0.711 ns | 0.790 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 256 | 23.90 ns | 0.508 ns | 0.820 ns | 0.69 | 0.02 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 256 | 20.40 ns | 0.133 ns | 0.111 ns | 0.57 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 512 | 73.39 ns | 0.310 ns | 0.259 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 512 | 26.10 ns | 0.418 ns | 0.391 ns | 0.36 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 512 | 27.59 ns | 0.556 ns | 0.571 ns | 0.38 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1024 | 150.64 ns | 2.903 ns | 2.716 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 1024 | 38.67 ns | 0.801 ns | 1.889 ns | 0.24 | 0.02 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 1024 | 47.13 ns | 0.948 ns | 1.054 ns | 0.31 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 2048 | 315.29 ns | 5.206 ns | 6.583 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 2048 | 57.37 ns | 1.152 ns | 1.078 ns | 0.18 | 0.01 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 2048 | 65.75 ns | 1.198 ns | 1.600 ns | 0.21 | 0.01 | - | - | - | - |
|
|||
|
|||
@ -1,68 +1,66 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Tests; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk |
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; |
|||
|
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class ShuffleFloat4Channel |
|||
{ |
|||
[Config(typeof(Config.HwIntrinsics_SSE_AVX))] |
|||
public class ShuffleFloat4Channel |
|||
{ |
|||
private static readonly byte Control = default(WXYZShuffle4).Control; |
|||
private float[] source; |
|||
private float[] destination; |
|||
private static readonly byte Control = default(WXYZShuffle4).Control; |
|||
private float[] source; |
|||
private float[] destination; |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new Random(this.Count).GenerateRandomFloatArray(this.Count, 0, 256); |
|||
this.destination = new float[this.Count]; |
|||
} |
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new Random(this.Count).GenerateRandomFloatArray(this.Count, 0, 256); |
|||
this.destination = new float[this.Count]; |
|||
} |
|||
|
|||
[Params(128, 256, 512, 1024, 2048)] |
|||
public int Count { get; set; } |
|||
[Params(128, 256, 512, 1024, 2048)] |
|||
public int Count { get; set; } |
|||
|
|||
[Benchmark] |
|||
public void Shuffle4Channel() |
|||
{ |
|||
SimdUtils.Shuffle4(this.source, this.destination, Control); |
|||
} |
|||
[Benchmark] |
|||
public void Shuffle4Channel() |
|||
{ |
|||
SimdUtils.Shuffle4(this.source, this.destination, Control); |
|||
} |
|||
|
|||
// 2020-10-29
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |---------------- |------------------- |-------------------------------------------------- |------ |-----------:|----------:|----------:|------:|------:|------:|------:|----------:|
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 128 | 63.647 ns | 0.5475 ns | 0.4853 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 128 | 9.818 ns | 0.1457 ns | 0.1292 ns | 0.15 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 128 | 15.267 ns | 0.1005 ns | 0.0940 ns | 0.24 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 256 | 125.586 ns | 1.9312 ns | 1.8064 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 256 | 15.878 ns | 0.1983 ns | 0.1758 ns | 0.13 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 256 | 29.170 ns | 0.2925 ns | 0.2442 ns | 0.23 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 512 | 263.859 ns | 2.6660 ns | 2.3634 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 512 | 29.452 ns | 0.3334 ns | 0.3118 ns | 0.11 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 512 | 52.912 ns | 0.1932 ns | 0.1713 ns | 0.20 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1024 | 495.717 ns | 1.9850 ns | 1.8567 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 1024 | 53.757 ns | 0.3212 ns | 0.2847 ns | 0.11 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 1024 | 107.815 ns | 1.6201 ns | 1.3528 ns | 0.22 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 2048 | 980.134 ns | 3.7407 ns | 3.1237 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 2048 | 105.120 ns | 0.6140 ns | 0.5443 ns | 0.11 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 2048 | 216.473 ns | 2.3268 ns | 2.0627 ns | 0.22 | - | - | - | - |
|
|||
} |
|||
|
|||
// 2020-10-29
|
|||
// ##########
|
|||
//
|
|||
// BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.572 (2004/?/20H1)
|
|||
// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
|
|||
// .NET Core SDK=3.1.403
|
|||
// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 1. No HwIntrinsics : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 2. AVX : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
// 3. SSE : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT
|
|||
//
|
|||
// Runtime=.NET Core 3.1
|
|||
//
|
|||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |---------------- |------------------- |-------------------------------------------------- |------ |-----------:|----------:|----------:|------:|------:|------:|------:|----------:|
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 128 | 63.647 ns | 0.5475 ns | 0.4853 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 128 | 9.818 ns | 0.1457 ns | 0.1292 ns | 0.15 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 128 | 15.267 ns | 0.1005 ns | 0.0940 ns | 0.24 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 256 | 125.586 ns | 1.9312 ns | 1.8064 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 256 | 15.878 ns | 0.1983 ns | 0.1758 ns | 0.13 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 256 | 29.170 ns | 0.2925 ns | 0.2442 ns | 0.23 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 512 | 263.859 ns | 2.6660 ns | 2.3634 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 512 | 29.452 ns | 0.3334 ns | 0.3118 ns | 0.11 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 512 | 52.912 ns | 0.1932 ns | 0.1713 ns | 0.20 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 1024 | 495.717 ns | 1.9850 ns | 1.8567 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 1024 | 53.757 ns | 0.3212 ns | 0.2847 ns | 0.11 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 1024 | 107.815 ns | 1.6201 ns | 1.3528 ns | 0.22 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | Shuffle4Channel | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 2048 | 980.134 ns | 3.7407 ns | 3.1237 ns | 1.00 | - | - | - | - |
|
|||
// | Shuffle4Channel | 2. AVX | Empty | 2048 | 105.120 ns | 0.6140 ns | 0.5443 ns | 0.11 | - | - | - | - |
|
|||
// | Shuffle4Channel | 3. SSE | COMPlus_EnableAVX=0 | 2048 | 216.473 ns | 2.3268 ns | 2.0627 ns | 0.22 | - | - | - | - |
|
|||
|
|||
@ -1,68 +1,66 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk |
|||
{ |
|||
[Config(typeof(Config.ShortCore31))] |
|||
public class UnPremultiplyVector4 |
|||
{ |
|||
private static readonly Vector4[] Vectors = CreateVectors(); |
|||
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk; |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void UnPremultiplyBaseline() |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference<Vector4>(Vectors); |
|||
[Config(typeof(Config.ShortCore31))] |
|||
public class UnPremultiplyVector4 |
|||
{ |
|||
private static readonly Vector4[] Vectors = CreateVectors(); |
|||
|
|||
for (int i = 0; i < Vectors.Length; i++) |
|||
{ |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
UnPremultiply(ref v); |
|||
} |
|||
} |
|||
[Benchmark(Baseline = true)] |
|||
public void UnPremultiplyBaseline() |
|||
{ |
|||
ref Vector4 baseRef = ref MemoryMarshal.GetReference<Vector4>(Vectors); |
|||
|
|||
[Benchmark] |
|||
public void UnPremultiply() |
|||
for (int i = 0; i < Vectors.Length; i++) |
|||
{ |
|||
Numerics.UnPremultiply(Vectors); |
|||
ref Vector4 v = ref Unsafe.Add(ref baseRef, i); |
|||
UnPremultiply(ref v); |
|||
} |
|||
} |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private static void UnPremultiply(ref Vector4 source) |
|||
{ |
|||
float w = source.W; |
|||
source /= w; |
|||
source.W = w; |
|||
} |
|||
[Benchmark] |
|||
public void UnPremultiply() |
|||
{ |
|||
Numerics.UnPremultiply(Vectors); |
|||
} |
|||
|
|||
private static Vector4[] CreateVectors() |
|||
{ |
|||
var rnd = new Random(42); |
|||
return GenerateRandomVectorArray(rnd, 2048, 0, 1); |
|||
} |
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private static void UnPremultiply(ref Vector4 source) |
|||
{ |
|||
float w = source.W; |
|||
source /= w; |
|||
source.W = w; |
|||
} |
|||
|
|||
private static Vector4[] GenerateRandomVectorArray(Random rnd, int length, float minVal, float maxVal) |
|||
{ |
|||
var values = new Vector4[length]; |
|||
private static Vector4[] CreateVectors() |
|||
{ |
|||
var rnd = new Random(42); |
|||
return GenerateRandomVectorArray(rnd, 2048, 0, 1); |
|||
} |
|||
|
|||
for (int i = 0; i < length; i++) |
|||
{ |
|||
ref Vector4 v = ref values[i]; |
|||
v.X = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Y = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Z = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.W = GetRandomFloat(rnd, minVal, maxVal); |
|||
} |
|||
private static Vector4[] GenerateRandomVectorArray(Random rnd, int length, float minVal, float maxVal) |
|||
{ |
|||
var values = new Vector4[length]; |
|||
|
|||
return values; |
|||
for (int i = 0; i < length; i++) |
|||
{ |
|||
ref Vector4 v = ref values[i]; |
|||
v.X = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Y = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.Z = GetRandomFloat(rnd, minVal, maxVal); |
|||
v.W = GetRandomFloat(rnd, minVal, maxVal); |
|||
} |
|||
|
|||
private static float GetRandomFloat(Random rnd, float minVal, float maxVal) |
|||
=> ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; |
|||
return values; |
|||
} |
|||
|
|||
private static float GetRandomFloat(Random rnd, float minVal, float maxVal) |
|||
=> ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; |
|||
} |
|||
|
|||
@ -1,72 +1,70 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Compression.Zlib; |
|||
using SharpAdler32 = ICSharpCode.SharpZipLib.Checksum.Adler32; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class Adler32Benchmark |
|||
{ |
|||
private byte[] data; |
|||
private readonly SharpAdler32 adler = new SharpAdler32(); |
|||
namespace SixLabors.ImageSharp.Benchmarks.General; |
|||
|
|||
[Params(1024, 2048, 4096)] |
|||
public int Count { get; set; } |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class Adler32Benchmark |
|||
{ |
|||
private byte[] data; |
|||
private readonly SharpAdler32 adler = new SharpAdler32(); |
|||
|
|||
[GlobalSetup] |
|||
public void SetUp() |
|||
{ |
|||
this.data = new byte[this.Count]; |
|||
new Random(1).NextBytes(this.data); |
|||
} |
|||
[Params(1024, 2048, 4096)] |
|||
public int Count { get; set; } |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public long SharpZipLibCalculate() |
|||
{ |
|||
this.adler.Reset(); |
|||
this.adler.Update(this.data); |
|||
return this.adler.Value; |
|||
} |
|||
[GlobalSetup] |
|||
public void SetUp() |
|||
{ |
|||
this.data = new byte[this.Count]; |
|||
new Random(1).NextBytes(this.data); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public uint SixLaborsCalculate() |
|||
{ |
|||
return Adler32.Calculate(this.data); |
|||
} |
|||
[Benchmark(Baseline = true)] |
|||
public long SharpZipLibCalculate() |
|||
{ |
|||
this.adler.Reset(); |
|||
this.adler.Update(this.data); |
|||
return this.adler.Value; |
|||
} |
|||
|
|||
// ########## 17/05/2020 ##########
|
|||
//
|
|||
// | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |--------------------- |-------------- |------ |------------:|------------:|----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 793.18 ns | 775.66 ns | 42.516 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 1024 | 384.86 ns | 15.64 ns | 0.857 ns | 0.49 | 0.03 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 790.31 ns | 353.34 ns | 19.368 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 1024 | 465.28 ns | 652.41 ns | 35.761 ns | 0.59 | 0.03 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 877.25 ns | 97.89 ns | 5.365 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 1024 | 45.60 ns | 13.28 ns | 0.728 ns | 0.05 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 1,537.04 ns | 428.44 ns | 23.484 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 2048 | 849.76 ns | 1,066.34 ns | 58.450 ns | 0.55 | 0.04 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 1,616.97 ns | 276.70 ns | 15.167 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 2048 | 790.77 ns | 691.71 ns | 37.915 ns | 0.49 | 0.03 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 1,735.11 ns | 1,374.22 ns | 75.325 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 2048 | 87.80 ns | 56.84 ns | 3.116 ns | 0.05 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 3,054.53 ns | 796.41 ns | 43.654 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 4096 | 1,538.90 ns | 487.02 ns | 26.695 ns | 0.50 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 3,223.48 ns | 32.32 ns | 1.771 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 4096 | 1,547.60 ns | 309.72 ns | 16.977 ns | 0.48 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 3,672.33 ns | 1,095.81 ns | 60.065 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 4096 | 159.44 ns | 36.31 ns | 1.990 ns | 0.04 | 0.00 | - | - | - | - |
|
|||
[Benchmark] |
|||
public uint SixLaborsCalculate() |
|||
{ |
|||
return Adler32.Calculate(this.data); |
|||
} |
|||
} |
|||
|
|||
// ########## 17/05/2020 ##########
|
|||
//
|
|||
// | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |--------------------- |-------------- |------ |------------:|------------:|----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 793.18 ns | 775.66 ns | 42.516 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 1024 | 384.86 ns | 15.64 ns | 0.857 ns | 0.49 | 0.03 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 790.31 ns | 353.34 ns | 19.368 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 1024 | 465.28 ns | 652.41 ns | 35.761 ns | 0.59 | 0.03 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 877.25 ns | 97.89 ns | 5.365 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 1024 | 45.60 ns | 13.28 ns | 0.728 ns | 0.05 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 1,537.04 ns | 428.44 ns | 23.484 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 2048 | 849.76 ns | 1,066.34 ns | 58.450 ns | 0.55 | 0.04 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 1,616.97 ns | 276.70 ns | 15.167 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 2048 | 790.77 ns | 691.71 ns | 37.915 ns | 0.49 | 0.03 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 1,735.11 ns | 1,374.22 ns | 75.325 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 2048 | 87.80 ns | 56.84 ns | 3.116 ns | 0.05 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 3,054.53 ns | 796.41 ns | 43.654 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 4096 | 1,538.90 ns | 487.02 ns | 26.695 ns | 0.50 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 3,223.48 ns | 32.32 ns | 1.771 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 4096 | 1,547.60 ns | 309.72 ns | 16.977 ns | 0.48 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 3,672.33 ns | 1,095.81 ns | 60.065 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 4096 | 159.44 ns | 36.31 ns | 1.990 ns | 0.04 | 0.00 | - | - | - | - |
|
|||
|
|||
@ -1,130 +1,126 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using SixLabors.ImageSharp; |
|||
namespace SixLabors.ImageSharp.Benchmarks.General; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General |
|||
{ |
|||
/* |
|||
Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | |
|||
/* |
|||
Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | |
|||
-------------------------------------------- |------ |---------:|---------:|---------:|-------:|---------:| |
|||
'Emulated 2D array access using flat array' | 32 | 224.2 ns | 4.739 ns | 13.75 ns | 0.65 | 0.07 | |
|||
'Array access using 2D array' | 32 | 346.6 ns | 9.225 ns | 26.91 ns | 1.00 | 0.00 | |
|||
'Array access using a jagged array' | 32 | 229.3 ns | 6.028 ns | 17.58 ns | 0.67 | 0.07 | |
|||
'Array access using DenseMatrix' | 32 | 223.2 ns | 5.248 ns | 15.22 ns | 0.65 | 0.07 | |
|||
|
|||
* |
|||
*/ |
|||
public class Array2D |
|||
{ |
|||
private float[] flatArray; |
|||
'Emulated 2D array access using flat array' | 32 | 224.2 ns | 4.739 ns | 13.75 ns | 0.65 | 0.07 | |
|||
'Array access using 2D array' | 32 | 346.6 ns | 9.225 ns | 26.91 ns | 1.00 | 0.00 | |
|||
'Array access using a jagged array' | 32 | 229.3 ns | 6.028 ns | 17.58 ns | 0.67 | 0.07 | |
|||
'Array access using DenseMatrix' | 32 | 223.2 ns | 5.248 ns | 15.22 ns | 0.65 | 0.07 | |
|||
|
|||
* |
|||
*/ |
|||
public class Array2D |
|||
{ |
|||
private float[] flatArray; |
|||
|
|||
private float[,] array2D; |
|||
private float[,] array2D; |
|||
|
|||
private float[][] jaggedData; |
|||
private float[][] jaggedData; |
|||
|
|||
private DenseMatrix<float> matrix; |
|||
private DenseMatrix<float> matrix; |
|||
|
|||
[Params(4, 16, 32)] |
|||
public int Count { get; set; } |
|||
[Params(4, 16, 32)] |
|||
public int Count { get; set; } |
|||
|
|||
public int Min { get; private set; } |
|||
public int Min { get; private set; } |
|||
|
|||
public int Max { get; private set; } |
|||
public int Max { get; private set; } |
|||
|
|||
[GlobalSetup] |
|||
public void SetUp() |
|||
{ |
|||
this.flatArray = new float[this.Count * this.Count]; |
|||
this.array2D = new float[this.Count, this.Count]; |
|||
this.jaggedData = new float[this.Count][]; |
|||
[GlobalSetup] |
|||
public void SetUp() |
|||
{ |
|||
this.flatArray = new float[this.Count * this.Count]; |
|||
this.array2D = new float[this.Count, this.Count]; |
|||
this.jaggedData = new float[this.Count][]; |
|||
|
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
this.jaggedData[i] = new float[this.Count]; |
|||
} |
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
this.jaggedData[i] = new float[this.Count]; |
|||
} |
|||
|
|||
this.matrix = new DenseMatrix<float>(this.array2D); |
|||
this.matrix = new DenseMatrix<float>(this.array2D); |
|||
|
|||
this.Min = (this.Count / 2) - 10; |
|||
this.Min = Math.Max(0, this.Min); |
|||
this.Max = this.Min + Math.Min(10, this.Count); |
|||
} |
|||
this.Min = (this.Count / 2) - 10; |
|||
this.Min = Math.Max(0, this.Min); |
|||
this.Max = this.Min + Math.Min(10, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Emulated 2D array access using flat array")] |
|||
public float FlatArrayIndex() |
|||
[Benchmark(Description = "Emulated 2D array access using flat array")] |
|||
public float FlatArrayIndex() |
|||
{ |
|||
float[] a = this.flatArray; |
|||
float s = 0; |
|||
int count = this.Count; |
|||
for (int i = this.Min; i < this.Max; i++) |
|||
{ |
|||
float[] a = this.flatArray; |
|||
float s = 0; |
|||
int count = this.Count; |
|||
for (int i = this.Min; i < this.Max; i++) |
|||
for (int j = this.Min; j < this.Max; j++) |
|||
{ |
|||
for (int j = this.Min; j < this.Max; j++) |
|||
{ |
|||
ref float v = ref a[(count * i) + j]; |
|||
v = i * j; |
|||
s += v; |
|||
} |
|||
ref float v = ref a[(count * i) + j]; |
|||
v = i * j; |
|||
s += v; |
|||
} |
|||
|
|||
return s; |
|||
} |
|||
|
|||
[Benchmark(Baseline = true, Description = "Array access using 2D array")] |
|||
public float Array2DIndex() |
|||
return s; |
|||
} |
|||
|
|||
[Benchmark(Baseline = true, Description = "Array access using 2D array")] |
|||
public float Array2DIndex() |
|||
{ |
|||
float s = 0; |
|||
float[,] a = this.array2D; |
|||
for (int i = this.Min; i < this.Max; i++) |
|||
{ |
|||
float s = 0; |
|||
float[,] a = this.array2D; |
|||
for (int i = this.Min; i < this.Max; i++) |
|||
for (int j = this.Min; j < this.Max; j++) |
|||
{ |
|||
for (int j = this.Min; j < this.Max; j++) |
|||
{ |
|||
ref float v = ref a[i, j]; |
|||
v = i * j; |
|||
s += v; |
|||
} |
|||
ref float v = ref a[i, j]; |
|||
v = i * j; |
|||
s += v; |
|||
} |
|||
|
|||
return s; |
|||
} |
|||
|
|||
[Benchmark(Description = "Array access using a jagged array")] |
|||
public float ArrayJaggedIndex() |
|||
return s; |
|||
} |
|||
|
|||
[Benchmark(Description = "Array access using a jagged array")] |
|||
public float ArrayJaggedIndex() |
|||
{ |
|||
float s = 0; |
|||
float[][] a = this.jaggedData; |
|||
for (int i = this.Min; i < this.Max; i++) |
|||
{ |
|||
float s = 0; |
|||
float[][] a = this.jaggedData; |
|||
for (int i = this.Min; i < this.Max; i++) |
|||
for (int j = this.Min; j < this.Max; j++) |
|||
{ |
|||
for (int j = this.Min; j < this.Max; j++) |
|||
{ |
|||
ref float v = ref a[i][j]; |
|||
v = i * j; |
|||
s += v; |
|||
} |
|||
ref float v = ref a[i][j]; |
|||
v = i * j; |
|||
s += v; |
|||
} |
|||
|
|||
return s; |
|||
} |
|||
|
|||
[Benchmark(Description = "Array access using DenseMatrix")] |
|||
public float ArrayMatrixIndex() |
|||
return s; |
|||
} |
|||
|
|||
[Benchmark(Description = "Array access using DenseMatrix")] |
|||
public float ArrayMatrixIndex() |
|||
{ |
|||
float s = 0; |
|||
DenseMatrix<float> a = this.matrix; |
|||
for (int i = this.Min; i < this.Max; i++) |
|||
{ |
|||
float s = 0; |
|||
DenseMatrix<float> a = this.matrix; |
|||
for (int i = this.Min; i < this.Max; i++) |
|||
for (int j = this.Min; j < this.Max; j++) |
|||
{ |
|||
for (int j = this.Min; j < this.Max; j++) |
|||
{ |
|||
ref float v = ref a[i, j]; |
|||
v = i * j; |
|||
s += v; |
|||
} |
|||
ref float v = ref a[i, j]; |
|||
v = i * j; |
|||
s += v; |
|||
} |
|||
|
|||
return s; |
|||
} |
|||
|
|||
return s; |
|||
} |
|||
} |
|||
|
|||
@ -1,59 +1,57 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General |
|||
namespace SixLabors.ImageSharp.Benchmarks.General; |
|||
|
|||
public class ArrayReverse |
|||
{ |
|||
public class ArrayReverse |
|||
{ |
|||
[Params(4, 16, 32)] |
|||
public int Count { get; set; } |
|||
[Params(4, 16, 32)] |
|||
public int Count { get; set; } |
|||
|
|||
private byte[] source; |
|||
private byte[] source; |
|||
|
|||
private byte[] destination; |
|||
private byte[] destination; |
|||
|
|||
[GlobalSetup] |
|||
public void SetUp() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
this.destination = new byte[this.Count]; |
|||
} |
|||
[GlobalSetup] |
|||
public void SetUp() |
|||
{ |
|||
this.source = new byte[this.Count]; |
|||
this.destination = new byte[this.Count]; |
|||
} |
|||
|
|||
[Benchmark(Baseline = true, Description = "Copy using Array.Reverse()")] |
|||
public void ReverseArray() |
|||
{ |
|||
Array.Reverse(this.source, 0, this.Count); |
|||
} |
|||
[Benchmark(Baseline = true, Description = "Copy using Array.Reverse()")] |
|||
public void ReverseArray() |
|||
{ |
|||
Array.Reverse(this.source, 0, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Reverse using loop")] |
|||
public void ReverseLoop() |
|||
{ |
|||
this.ReverseBytes(this.source, 0, this.Count); |
|||
|
|||
[Benchmark(Description = "Reverse using loop")] |
|||
public void ReverseLoop() |
|||
/* |
|||
for (int i = 0; i < this.source.Length / 2; i++) |
|||
{ |
|||
this.ReverseBytes(this.source, 0, this.Count); |
|||
|
|||
/* |
|||
for (int i = 0; i < this.source.Length / 2; i++) |
|||
{ |
|||
byte tmp = this.source[i]; |
|||
this.source[i] = this.source[this.source.Length - i - 1]; |
|||
this.source[this.source.Length - i - 1] = tmp; |
|||
}*/ |
|||
} |
|||
byte tmp = this.source[i]; |
|||
this.source[i] = this.source[this.source.Length - i - 1]; |
|||
this.source[this.source.Length - i - 1] = tmp; |
|||
}*/ |
|||
} |
|||
|
|||
public void ReverseBytes(byte[] source, int index, int length) |
|||
public void ReverseBytes(byte[] source, int index, int length) |
|||
{ |
|||
int i = index; |
|||
int j = index + length - 1; |
|||
while (i < j) |
|||
{ |
|||
int i = index; |
|||
int j = index + length - 1; |
|||
while (i < j) |
|||
{ |
|||
byte temp = source[i]; |
|||
source[i] = source[j]; |
|||
source[j] = temp; |
|||
i++; |
|||
j--; |
|||
} |
|||
byte temp = source[i]; |
|||
source[i] = source[j]; |
|||
source[j] = temp; |
|||
i++; |
|||
j--; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,43 +1,41 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath |
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath; |
|||
|
|||
public class Abs |
|||
{ |
|||
public class Abs |
|||
{ |
|||
[Params(-1, 1)] |
|||
public int X { get; set; } |
|||
[Params(-1, 1)] |
|||
public int X { get; set; } |
|||
|
|||
[Benchmark(Baseline = true, Description = "Maths Abs")] |
|||
public int MathAbs() |
|||
{ |
|||
int x = this.X; |
|||
return Math.Abs(x); |
|||
} |
|||
[Benchmark(Baseline = true, Description = "Maths Abs")] |
|||
public int MathAbs() |
|||
{ |
|||
int x = this.X; |
|||
return Math.Abs(x); |
|||
} |
|||
|
|||
[Benchmark(Description = "Conditional Abs")] |
|||
public int ConditionalAbs() |
|||
{ |
|||
int x = this.X; |
|||
return x < 0 ? -x : x; |
|||
} |
|||
[Benchmark(Description = "Conditional Abs")] |
|||
public int ConditionalAbs() |
|||
{ |
|||
int x = this.X; |
|||
return x < 0 ? -x : x; |
|||
} |
|||
|
|||
[Benchmark(Description = "Bitwise Abs")] |
|||
public int AbsBitwise() |
|||
{ |
|||
int x = this.X; |
|||
return (x ^ (x >> 31)) - (x >> 31); |
|||
} |
|||
[Benchmark(Description = "Bitwise Abs")] |
|||
public int AbsBitwise() |
|||
{ |
|||
int x = this.X; |
|||
return (x ^ (x >> 31)) - (x >> 31); |
|||
} |
|||
|
|||
[Benchmark(Description = "Bitwise Abs With Variable")] |
|||
public int AbsBitwiseVer() |
|||
{ |
|||
int x = this.X; |
|||
int y = x >> 31; |
|||
return (x ^ y) - y; |
|||
} |
|||
[Benchmark(Description = "Bitwise Abs With Variable")] |
|||
public int AbsBitwiseVer() |
|||
{ |
|||
int x = this.X; |
|||
int y = x >> 31; |
|||
return (x ^ y) - y; |
|||
} |
|||
} |
|||
|
|||
@ -1,70 +1,68 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath |
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath; |
|||
|
|||
public class ClampFloat |
|||
{ |
|||
public class ClampFloat |
|||
private readonly float min = -1.5f; |
|||
private readonly float max = 2.5f; |
|||
private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 }; |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public float UsingMathF() |
|||
{ |
|||
private readonly float min = -1.5f; |
|||
private readonly float max = 2.5f; |
|||
private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 }; |
|||
float acc = 0; |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public float UsingMathF() |
|||
for (int i = 0; i < Values.Length; i++) |
|||
{ |
|||
float acc = 0; |
|||
acc += ClampUsingMathF(Values[i], this.min, this.max); |
|||
} |
|||
|
|||
for (int i = 0; i < Values.Length; i++) |
|||
{ |
|||
acc += ClampUsingMathF(Values[i], this.min, this.max); |
|||
} |
|||
return acc; |
|||
} |
|||
|
|||
return acc; |
|||
} |
|||
[Benchmark] |
|||
public float UsingBranching() |
|||
{ |
|||
float acc = 0; |
|||
|
|||
[Benchmark] |
|||
public float UsingBranching() |
|||
for (int i = 0; i < Values.Length; i++) |
|||
{ |
|||
float acc = 0; |
|||
acc += ClampUsingBranching(Values[i], this.min, this.max); |
|||
} |
|||
|
|||
for (int i = 0; i < Values.Length; i++) |
|||
{ |
|||
acc += ClampUsingBranching(Values[i], this.min, this.max); |
|||
} |
|||
return acc; |
|||
} |
|||
|
|||
return acc; |
|||
} |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float ClampUsingMathF(float x, float min, float max) |
|||
{ |
|||
return Math.Min(max, Math.Max(min, x)); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float ClampUsingMathF(float x, float min, float max) |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float ClampUsingBranching(float x, float min, float max) |
|||
{ |
|||
if (x >= max) |
|||
{ |
|||
return Math.Min(max, Math.Max(min, x)); |
|||
return max; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float ClampUsingBranching(float x, float min, float max) |
|||
if (x <= min) |
|||
{ |
|||
if (x >= max) |
|||
{ |
|||
return max; |
|||
} |
|||
|
|||
if (x <= min) |
|||
{ |
|||
return min; |
|||
} |
|||
|
|||
return x; |
|||
return min; |
|||
} |
|||
|
|||
// RESULTS:
|
|||
// Method | Mean | Error | StdDev | Scaled |
|
|||
// --------------- |---------:|----------:|----------:|-------:|
|
|||
// UsingMathF | 30.37 ns | 0.3764 ns | 0.3337 ns | 1.00 |
|
|||
// UsingBranching | 18.66 ns | 0.1043 ns | 0.0871 ns | 0.61 |
|
|||
return x; |
|||
} |
|||
|
|||
// RESULTS:
|
|||
// Method | Mean | Error | StdDev | Scaled |
|
|||
// --------------- |---------:|----------:|----------:|-------:|
|
|||
// UsingMathF | 30.37 ns | 0.3764 ns | 0.3337 ns | 1.00 |
|
|||
// UsingBranching | 18.66 ns | 0.1043 ns | 0.0871 ns | 0.61 |
|
|||
} |
|||
|
|||
@ -1,92 +1,90 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath |
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath; |
|||
|
|||
public class ClampInt32IntoByte |
|||
{ |
|||
public class ClampInt32IntoByte |
|||
[Params(-1, 0, 255, 256)] |
|||
public int Value { get; set; } |
|||
|
|||
[Benchmark(Baseline = true, Description = "Maths Clamp")] |
|||
public byte ClampMaths() |
|||
{ |
|||
[Params(-1, 0, 255, 256)] |
|||
public int Value { get; set; } |
|||
int value = this.Value; |
|||
return (byte)Math.Min(Math.Max(byte.MinValue, value), byte.MaxValue); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true, Description = "Maths Clamp")] |
|||
public byte ClampMaths() |
|||
{ |
|||
int value = this.Value; |
|||
return (byte)Math.Min(Math.Max(byte.MinValue, value), byte.MaxValue); |
|||
} |
|||
[Benchmark(Description = "No Maths Clamp")] |
|||
public byte ClampNoMaths() |
|||
{ |
|||
int value = this.Value; |
|||
value = value >= byte.MaxValue ? byte.MaxValue : value; |
|||
return (byte)(value <= byte.MinValue ? byte.MinValue : value); |
|||
} |
|||
|
|||
[Benchmark(Description = "No Maths Clamp")] |
|||
public byte ClampNoMaths() |
|||
{ |
|||
int value = this.Value; |
|||
value = value >= byte.MaxValue ? byte.MaxValue : value; |
|||
return (byte)(value <= byte.MinValue ? byte.MinValue : value); |
|||
} |
|||
[Benchmark(Description = "No Maths No Equals Clamp")] |
|||
public byte ClampNoMathsNoEquals() |
|||
{ |
|||
int value = this.Value; |
|||
value = value > byte.MaxValue ? byte.MaxValue : value; |
|||
return (byte)(value < byte.MinValue ? byte.MinValue : value); |
|||
} |
|||
|
|||
[Benchmark(Description = "No Maths No Equals Clamp")] |
|||
public byte ClampNoMathsNoEquals() |
|||
[Benchmark(Description = "No Maths Clamp No Ternary")] |
|||
public byte ClampNoMathsNoTernary() |
|||
{ |
|||
int value = this.Value; |
|||
|
|||
if (value >= byte.MaxValue) |
|||
{ |
|||
int value = this.Value; |
|||
value = value > byte.MaxValue ? byte.MaxValue : value; |
|||
return (byte)(value < byte.MinValue ? byte.MinValue : value); |
|||
return byte.MaxValue; |
|||
} |
|||
|
|||
[Benchmark(Description = "No Maths Clamp No Ternary")] |
|||
public byte ClampNoMathsNoTernary() |
|||
if (value <= byte.MinValue) |
|||
{ |
|||
int value = this.Value; |
|||
|
|||
if (value >= byte.MaxValue) |
|||
{ |
|||
return byte.MaxValue; |
|||
} |
|||
|
|||
if (value <= byte.MinValue) |
|||
{ |
|||
return byte.MinValue; |
|||
} |
|||
|
|||
return (byte)value; |
|||
return byte.MinValue; |
|||
} |
|||
|
|||
[Benchmark(Description = "No Maths No Equals Clamp No Ternary")] |
|||
public byte ClampNoMathsEqualsNoTernary() |
|||
{ |
|||
int value = this.Value; |
|||
return (byte)value; |
|||
} |
|||
|
|||
if (value > byte.MaxValue) |
|||
{ |
|||
return byte.MaxValue; |
|||
} |
|||
[Benchmark(Description = "No Maths No Equals Clamp No Ternary")] |
|||
public byte ClampNoMathsEqualsNoTernary() |
|||
{ |
|||
int value = this.Value; |
|||
|
|||
if (value < byte.MinValue) |
|||
{ |
|||
return byte.MinValue; |
|||
} |
|||
if (value > byte.MaxValue) |
|||
{ |
|||
return byte.MaxValue; |
|||
} |
|||
|
|||
return (byte)value; |
|||
} |
|||
if (value < byte.MinValue) |
|||
{ |
|||
return byte.MinValue; |
|||
} |
|||
|
|||
[Benchmark(Description = "Clamp using Bitwise Abs")] |
|||
public byte ClampBitwise() |
|||
{ |
|||
int x = this.Value; |
|||
int absMax = byte.MaxValue - x; |
|||
x = (x + byte.MaxValue - AbsBitwiseVer(ref absMax)) >> 1; |
|||
x = (x + byte.MinValue + AbsBitwiseVer(ref x)) >> 1; |
|||
return (byte)value; |
|||
} |
|||
|
|||
return (byte)x; |
|||
} |
|||
[Benchmark(Description = "Clamp using Bitwise Abs")] |
|||
public byte ClampBitwise() |
|||
{ |
|||
int x = this.Value; |
|||
int absMax = byte.MaxValue - x; |
|||
x = (x + byte.MaxValue - AbsBitwiseVer(ref absMax)) >> 1; |
|||
x = (x + byte.MinValue + AbsBitwiseVer(ref x)) >> 1; |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static int AbsBitwiseVer(ref int x) |
|||
{ |
|||
int y = x >> 31; |
|||
return (x ^ y) - y; |
|||
} |
|||
return (byte)x; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static int AbsBitwiseVer(ref int x) |
|||
{ |
|||
int y = x >> 31; |
|||
return (x ^ y) - y; |
|||
} |
|||
} |
|||
|
|||
@ -1,42 +1,40 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath |
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath; |
|||
|
|||
public class Pow |
|||
{ |
|||
public class Pow |
|||
{ |
|||
[Params(-1.333F, 1.333F)] |
|||
public float X { get; set; } |
|||
[Params(-1.333F, 1.333F)] |
|||
public float X { get; set; } |
|||
|
|||
[Benchmark(Baseline = true, Description = "Math.Pow 2")] |
|||
public float MathPow() |
|||
{ |
|||
float x = this.X; |
|||
return (float)Math.Pow(x, 2); |
|||
} |
|||
[Benchmark(Baseline = true, Description = "Math.Pow 2")] |
|||
public float MathPow() |
|||
{ |
|||
float x = this.X; |
|||
return (float)Math.Pow(x, 2); |
|||
} |
|||
|
|||
[Benchmark(Description = "Pow x2")] |
|||
public float PowMult() |
|||
{ |
|||
float x = this.X; |
|||
return x * x; |
|||
} |
|||
[Benchmark(Description = "Pow x2")] |
|||
public float PowMult() |
|||
{ |
|||
float x = this.X; |
|||
return x * x; |
|||
} |
|||
|
|||
[Benchmark(Description = "Math.Pow 3")] |
|||
public float MathPow3() |
|||
{ |
|||
float x = this.X; |
|||
return (float)Math.Pow(x, 3); |
|||
} |
|||
[Benchmark(Description = "Math.Pow 3")] |
|||
public float MathPow3() |
|||
{ |
|||
float x = this.X; |
|||
return (float)Math.Pow(x, 3); |
|||
} |
|||
|
|||
[Benchmark(Description = "Pow x3")] |
|||
public float PowMult3() |
|||
{ |
|||
float x = this.X; |
|||
return x * x * x; |
|||
} |
|||
[Benchmark(Description = "Pow x3")] |
|||
public float PowMult3() |
|||
{ |
|||
float x = this.X; |
|||
return x * x * x; |
|||
} |
|||
} |
|||
|
|||
@ -1,25 +1,23 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath |
|||
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath; |
|||
|
|||
public class Round |
|||
{ |
|||
public class Round |
|||
{ |
|||
private const float Input = .51F; |
|||
private const float Input = .51F; |
|||
|
|||
[Benchmark] |
|||
public int ConvertTo() => Convert.ToInt32(Input); |
|||
[Benchmark] |
|||
public int ConvertTo() => Convert.ToInt32(Input); |
|||
|
|||
[Benchmark] |
|||
public int MathRound() => (int)Math.Round(Input); |
|||
[Benchmark] |
|||
public int MathRound() => (int)Math.Round(Input); |
|||
|
|||
// Results 20th Jan 2019
|
|||
// Method | Mean | Error | StdDev | Median |
|
|||
//---------- |----------:|----------:|----------:|----------:|
|
|||
// ConvertTo | 3.1967 ns | 0.1234 ns | 0.2129 ns | 3.2340 ns |
|
|||
// MathRound | 0.0528 ns | 0.0374 ns | 0.1079 ns | 0.0000 ns |
|
|||
} |
|||
// Results 20th Jan 2019
|
|||
// Method | Mean | Error | StdDev | Median |
|
|||
//---------- |----------:|----------:|----------:|----------:|
|
|||
// ConvertTo | 3.1967 ns | 0.1234 ns | 0.2129 ns | 3.2340 ns |
|
|||
// MathRound | 0.0528 ns | 0.0374 ns | 0.1079 ns | 0.0000 ns |
|
|||
} |
|||
|
|||
@ -1,228 +1,226 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General |
|||
namespace SixLabors.ImageSharp.Benchmarks.General; |
|||
|
|||
/// <summary>
|
|||
/// Compare different methods for copying native and/or managed buffers.
|
|||
/// Conclusions:
|
|||
/// - Span.CopyTo() has terrible performance on classic .NET Framework
|
|||
/// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning)
|
|||
/// </summary>
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class CopyBuffers |
|||
{ |
|||
/// <summary>
|
|||
/// Compare different methods for copying native and/or managed buffers.
|
|||
/// Conclusions:
|
|||
/// - Span.CopyTo() has terrible performance on classic .NET Framework
|
|||
/// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning)
|
|||
/// </summary>
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class CopyBuffers |
|||
private byte[] destArray; |
|||
|
|||
private MemoryHandle destHandle; |
|||
|
|||
private Memory<byte> destMemory; |
|||
|
|||
private byte[] sourceArray; |
|||
|
|||
private MemoryHandle sourceHandle; |
|||
|
|||
private Memory<byte> sourceMemory; |
|||
|
|||
[Params(10, 50, 100, 1000, 10000)] |
|||
public int Count { get; set; } |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.sourceArray = new byte[this.Count]; |
|||
this.sourceMemory = new Memory<byte>(this.sourceArray); |
|||
this.sourceHandle = this.sourceMemory.Pin(); |
|||
|
|||
this.destArray = new byte[this.Count]; |
|||
this.destMemory = new Memory<byte>(this.destArray); |
|||
this.destHandle = this.destMemory.Pin(); |
|||
} |
|||
|
|||
[GlobalCleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.sourceHandle.Dispose(); |
|||
this.destHandle.Dispose(); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true, Description = "Array.Copy()")] |
|||
public void ArrayCopy() |
|||
{ |
|||
Array.Copy(this.sourceArray, this.destArray, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Buffer.BlockCopy()")] |
|||
public void BufferBlockCopy() |
|||
{ |
|||
Buffer.BlockCopy(this.sourceArray, 0, this.destArray, 0, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Buffer.MemoryCopy()")] |
|||
public unsafe void BufferMemoryCopy() |
|||
{ |
|||
void* pinnedDestination = this.destHandle.Pointer; |
|||
void* pinnedSource = this.sourceHandle.Pointer; |
|||
Buffer.MemoryCopy(pinnedSource, pinnedDestination, this.Count, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Marshal.Copy()")] |
|||
public unsafe void MarshalCopy() |
|||
{ |
|||
void* pinnedDestination = this.destHandle.Pointer; |
|||
Marshal.Copy(this.sourceArray, 0, (IntPtr)pinnedDestination, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Span.CopyTo()")] |
|||
public void SpanCopyTo() |
|||
{ |
|||
this.sourceMemory.Span.CopyTo(this.destMemory.Span); |
|||
} |
|||
|
|||
[Benchmark(Description = "Unsafe.CopyBlock(ref)")] |
|||
public void UnsafeCopyBlockReferences() |
|||
{ |
|||
private byte[] destArray; |
|||
|
|||
private MemoryHandle destHandle; |
|||
|
|||
private Memory<byte> destMemory; |
|||
|
|||
private byte[] sourceArray; |
|||
|
|||
private MemoryHandle sourceHandle; |
|||
|
|||
private Memory<byte> sourceMemory; |
|||
|
|||
[Params(10, 50, 100, 1000, 10000)] |
|||
public int Count { get; set; } |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.sourceArray = new byte[this.Count]; |
|||
this.sourceMemory = new Memory<byte>(this.sourceArray); |
|||
this.sourceHandle = this.sourceMemory.Pin(); |
|||
|
|||
this.destArray = new byte[this.Count]; |
|||
this.destMemory = new Memory<byte>(this.destArray); |
|||
this.destHandle = this.destMemory.Pin(); |
|||
} |
|||
|
|||
[GlobalCleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.sourceHandle.Dispose(); |
|||
this.destHandle.Dispose(); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true, Description = "Array.Copy()")] |
|||
public void ArrayCopy() |
|||
{ |
|||
Array.Copy(this.sourceArray, this.destArray, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Buffer.BlockCopy()")] |
|||
public void BufferBlockCopy() |
|||
{ |
|||
Buffer.BlockCopy(this.sourceArray, 0, this.destArray, 0, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Buffer.MemoryCopy()")] |
|||
public unsafe void BufferMemoryCopy() |
|||
{ |
|||
void* pinnedDestination = this.destHandle.Pointer; |
|||
void* pinnedSource = this.sourceHandle.Pointer; |
|||
Buffer.MemoryCopy(pinnedSource, pinnedDestination, this.Count, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Marshal.Copy()")] |
|||
public unsafe void MarshalCopy() |
|||
{ |
|||
void* pinnedDestination = this.destHandle.Pointer; |
|||
Marshal.Copy(this.sourceArray, 0, (IntPtr)pinnedDestination, this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Span.CopyTo()")] |
|||
public void SpanCopyTo() |
|||
{ |
|||
this.sourceMemory.Span.CopyTo(this.destMemory.Span); |
|||
} |
|||
|
|||
[Benchmark(Description = "Unsafe.CopyBlock(ref)")] |
|||
public void UnsafeCopyBlockReferences() |
|||
{ |
|||
Unsafe.CopyBlock(ref this.destArray[0], ref this.sourceArray[0], (uint)this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Unsafe.CopyBlock(ptr)")] |
|||
public unsafe void UnsafeCopyBlockPointers() |
|||
{ |
|||
void* pinnedDestination = this.destHandle.Pointer; |
|||
void* pinnedSource = this.sourceHandle.Pointer; |
|||
Unsafe.CopyBlock(pinnedDestination, pinnedSource, (uint)this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Unsafe.CopyBlockUnaligned(ref)")] |
|||
public void UnsafeCopyBlockUnalignedReferences() |
|||
{ |
|||
Unsafe.CopyBlockUnaligned(ref this.destArray[0], ref this.sourceArray[0], (uint)this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Unsafe.CopyBlockUnaligned(ptr)")] |
|||
public unsafe void UnsafeCopyBlockUnalignedPointers() |
|||
{ |
|||
void* pinnedDestination = this.destHandle.Pointer; |
|||
void* pinnedSource = this.sourceHandle.Pointer; |
|||
Unsafe.CopyBlockUnaligned(pinnedDestination, pinnedSource, (uint)this.Count); |
|||
} |
|||
|
|||
// BenchmarkDotNet=v0.11.3, OS=Windows 10.0.17134.706 (1803/April2018Update/Redstone4)
|
|||
// Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
|
|||
// Frequency=2742189 Hz, Resolution=364.6722 ns, Timer=TSC
|
|||
// .NET Core SDK=2.2.202
|
|||
// [Host] : .NET Core 2.1.9 (CoreCLR 4.6.27414.06, CoreFX 4.6.27415.01), 64bit RyuJIT
|
|||
// Clr : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3394.0
|
|||
// Core : .NET Core 2.1.9 (CoreCLR 4.6.27414.06, CoreFX 4.6.27415.01), 64bit RyuJIT
|
|||
//
|
|||
// IterationCount=3 LaunchCount=1 WarmupCount=3
|
|||
//
|
|||
// | Method | Job | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |------------------------------- |----- |-------- |------ |-----------:|-----------:|----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Array.Copy() | Clr | Clr | 10 | 23.636 ns | 2.5299 ns | 0.1387 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 10 | 11.420 ns | 2.3341 ns | 0.1279 ns | 0.48 | 0.01 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 10 | 2.861 ns | 0.5059 ns | 0.0277 ns | 0.12 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 10 | 14.870 ns | 2.4541 ns | 0.1345 ns | 0.63 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 10 | 31.906 ns | 1.2213 ns | 0.0669 ns | 1.35 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 10 | 3.513 ns | 0.7392 ns | 0.0405 ns | 0.15 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 10 | 3.053 ns | 0.2010 ns | 0.0110 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 10 | 3.497 ns | 0.4911 ns | 0.0269 ns | 0.15 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 10 | 3.109 ns | 0.5958 ns | 0.0327 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 10 | 19.709 ns | 2.1867 ns | 0.1199 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 10 | 7.377 ns | 1.1582 ns | 0.0635 ns | 0.37 | 0.01 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 10 | 2.581 ns | 1.1607 ns | 0.0636 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 10 | 15.197 ns | 2.8446 ns | 0.1559 ns | 0.77 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 10 | 25.394 ns | 0.9782 ns | 0.0536 ns | 1.29 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 10 | 2.254 ns | 0.1590 ns | 0.0087 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 10 | 1.878 ns | 0.1035 ns | 0.0057 ns | 0.10 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 10 | 2.263 ns | 0.1383 ns | 0.0076 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 10 | 1.877 ns | 0.0602 ns | 0.0033 ns | 0.10 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Clr | Clr | 50 | 35.068 ns | 5.9137 ns | 0.3242 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 50 | 23.299 ns | 2.3797 ns | 0.1304 ns | 0.66 | 0.01 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 50 | 3.598 ns | 4.8536 ns | 0.2660 ns | 0.10 | 0.01 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 50 | 27.720 ns | 4.6602 ns | 0.2554 ns | 0.79 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 50 | 35.673 ns | 16.2972 ns | 0.8933 ns | 1.02 | 0.03 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 50 | 5.534 ns | 2.8119 ns | 0.1541 ns | 0.16 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 50 | 4.511 ns | 0.9555 ns | 0.0524 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 50 | 5.613 ns | 1.6679 ns | 0.0914 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 50 | 4.884 ns | 7.3153 ns | 0.4010 ns | 0.14 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 50 | 20.232 ns | 1.5720 ns | 0.0862 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 50 | 8.142 ns | 0.7860 ns | 0.0431 ns | 0.40 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 50 | 2.962 ns | 0.0611 ns | 0.0033 ns | 0.15 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 50 | 16.802 ns | 2.9686 ns | 0.1627 ns | 0.83 | 0.00 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 50 | 26.571 ns | 0.9228 ns | 0.0506 ns | 1.31 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 50 | 2.219 ns | 0.7191 ns | 0.0394 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 50 | 1.751 ns | 0.1884 ns | 0.0103 ns | 0.09 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 50 | 2.177 ns | 0.4489 ns | 0.0246 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 50 | 1.806 ns | 0.1063 ns | 0.0058 ns | 0.09 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Clr | Clr | 100 | 39.158 ns | 4.3068 ns | 0.2361 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 100 | 27.623 ns | 0.4611 ns | 0.0253 ns | 0.71 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 100 | 5.018 ns | 0.5689 ns | 0.0312 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 100 | 33.527 ns | 1.9019 ns | 0.1042 ns | 0.86 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 100 | 35.604 ns | 2.7039 ns | 0.1482 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 100 | 7.853 ns | 0.4925 ns | 0.0270 ns | 0.20 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 100 | 7.406 ns | 1.9733 ns | 0.1082 ns | 0.19 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 100 | 7.822 ns | 0.6837 ns | 0.0375 ns | 0.20 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 100 | 7.392 ns | 1.2832 ns | 0.0703 ns | 0.19 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 100 | 22.909 ns | 2.9754 ns | 0.1631 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 100 | 10.687 ns | 1.1262 ns | 0.0617 ns | 0.47 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 100 | 4.063 ns | 0.1607 ns | 0.0088 ns | 0.18 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 100 | 18.067 ns | 4.0557 ns | 0.2223 ns | 0.79 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 100 | 28.352 ns | 1.2762 ns | 0.0700 ns | 1.24 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 100 | 4.130 ns | 0.2013 ns | 0.0110 ns | 0.18 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 100 | 4.096 ns | 0.2460 ns | 0.0135 ns | 0.18 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 100 | 4.160 ns | 0.3174 ns | 0.0174 ns | 0.18 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 100 | 3.480 ns | 1.1683 ns | 0.0640 ns | 0.15 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Clr | Clr | 1000 | 49.059 ns | 2.0729 ns | 0.1136 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 1000 | 38.270 ns | 23.6970 ns | 1.2989 ns | 0.78 | 0.03 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 1000 | 27.599 ns | 6.8328 ns | 0.3745 ns | 0.56 | 0.01 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 1000 | 42.752 ns | 5.1357 ns | 0.2815 ns | 0.87 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 1000 | 69.983 ns | 2.1860 ns | 0.1198 ns | 1.43 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 1000 | 44.822 ns | 0.1625 ns | 0.0089 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 1000 | 45.072 ns | 1.4053 ns | 0.0770 ns | 0.92 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 1000 | 45.306 ns | 5.2646 ns | 0.2886 ns | 0.92 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 1000 | 44.813 ns | 0.9117 ns | 0.0500 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 1000 | 51.907 ns | 3.1827 ns | 0.1745 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 1000 | 40.700 ns | 3.1488 ns | 0.1726 ns | 0.78 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 1000 | 23.711 ns | 1.3004 ns | 0.0713 ns | 0.46 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 1000 | 42.586 ns | 2.5390 ns | 0.1392 ns | 0.82 | 0.00 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 1000 | 44.109 ns | 4.5604 ns | 0.2500 ns | 0.85 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 1000 | 33.926 ns | 5.1633 ns | 0.2830 ns | 0.65 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 1000 | 33.267 ns | 0.2708 ns | 0.0148 ns | 0.64 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 1000 | 34.018 ns | 2.3238 ns | 0.1274 ns | 0.66 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 1000 | 33.667 ns | 2.1983 ns | 0.1205 ns | 0.65 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Clr | Clr | 10000 | 153.429 ns | 6.1735 ns | 0.3384 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 10000 | 201.373 ns | 4.3670 ns | 0.2394 ns | 1.31 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 10000 | 211.768 ns | 71.3510 ns | 3.9110 ns | 1.38 | 0.02 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 10000 | 215.299 ns | 17.2677 ns | 0.9465 ns | 1.40 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 10000 | 486.325 ns | 32.4445 ns | 1.7784 ns | 3.17 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 10000 | 452.314 ns | 33.0593 ns | 1.8121 ns | 2.95 | 0.02 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 10000 | 455.600 ns | 56.7534 ns | 3.1108 ns | 2.97 | 0.02 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 10000 | 452.279 ns | 8.6457 ns | 0.4739 ns | 2.95 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 10000 | 453.146 ns | 12.3776 ns | 0.6785 ns | 2.95 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 10000 | 204.508 ns | 3.1652 ns | 0.1735 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 10000 | 193.345 ns | 1.3742 ns | 0.0753 ns | 0.95 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 10000 | 196.978 ns | 18.3279 ns | 1.0046 ns | 0.96 | 0.01 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 10000 | 206.878 ns | 6.9938 ns | 0.3834 ns | 1.01 | 0.00 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 10000 | 215.733 ns | 15.4824 ns | 0.8486 ns | 1.05 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 10000 | 186.894 ns | 8.7617 ns | 0.4803 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 10000 | 186.662 ns | 10.6059 ns | 0.5813 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 10000 | 187.489 ns | 13.1527 ns | 0.7209 ns | 0.92 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 10000 | 186.586 ns | 4.6274 ns | 0.2536 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
Unsafe.CopyBlock(ref this.destArray[0], ref this.sourceArray[0], (uint)this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Unsafe.CopyBlock(ptr)")] |
|||
public unsafe void UnsafeCopyBlockPointers() |
|||
{ |
|||
void* pinnedDestination = this.destHandle.Pointer; |
|||
void* pinnedSource = this.sourceHandle.Pointer; |
|||
Unsafe.CopyBlock(pinnedDestination, pinnedSource, (uint)this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Unsafe.CopyBlockUnaligned(ref)")] |
|||
public void UnsafeCopyBlockUnalignedReferences() |
|||
{ |
|||
Unsafe.CopyBlockUnaligned(ref this.destArray[0], ref this.sourceArray[0], (uint)this.Count); |
|||
} |
|||
|
|||
[Benchmark(Description = "Unsafe.CopyBlockUnaligned(ptr)")] |
|||
public unsafe void UnsafeCopyBlockUnalignedPointers() |
|||
{ |
|||
void* pinnedDestination = this.destHandle.Pointer; |
|||
void* pinnedSource = this.sourceHandle.Pointer; |
|||
Unsafe.CopyBlockUnaligned(pinnedDestination, pinnedSource, (uint)this.Count); |
|||
} |
|||
|
|||
// BenchmarkDotNet=v0.11.3, OS=Windows 10.0.17134.706 (1803/April2018Update/Redstone4)
|
|||
// Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
|
|||
// Frequency=2742189 Hz, Resolution=364.6722 ns, Timer=TSC
|
|||
// .NET Core SDK=2.2.202
|
|||
// [Host] : .NET Core 2.1.9 (CoreCLR 4.6.27414.06, CoreFX 4.6.27415.01), 64bit RyuJIT
|
|||
// Clr : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3394.0
|
|||
// Core : .NET Core 2.1.9 (CoreCLR 4.6.27414.06, CoreFX 4.6.27415.01), 64bit RyuJIT
|
|||
//
|
|||
// IterationCount=3 LaunchCount=1 WarmupCount=3
|
|||
//
|
|||
// | Method | Job | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |------------------------------- |----- |-------- |------ |-----------:|-----------:|----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | Array.Copy() | Clr | Clr | 10 | 23.636 ns | 2.5299 ns | 0.1387 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 10 | 11.420 ns | 2.3341 ns | 0.1279 ns | 0.48 | 0.01 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 10 | 2.861 ns | 0.5059 ns | 0.0277 ns | 0.12 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 10 | 14.870 ns | 2.4541 ns | 0.1345 ns | 0.63 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 10 | 31.906 ns | 1.2213 ns | 0.0669 ns | 1.35 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 10 | 3.513 ns | 0.7392 ns | 0.0405 ns | 0.15 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 10 | 3.053 ns | 0.2010 ns | 0.0110 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 10 | 3.497 ns | 0.4911 ns | 0.0269 ns | 0.15 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 10 | 3.109 ns | 0.5958 ns | 0.0327 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 10 | 19.709 ns | 2.1867 ns | 0.1199 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 10 | 7.377 ns | 1.1582 ns | 0.0635 ns | 0.37 | 0.01 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 10 | 2.581 ns | 1.1607 ns | 0.0636 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 10 | 15.197 ns | 2.8446 ns | 0.1559 ns | 0.77 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 10 | 25.394 ns | 0.9782 ns | 0.0536 ns | 1.29 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 10 | 2.254 ns | 0.1590 ns | 0.0087 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 10 | 1.878 ns | 0.1035 ns | 0.0057 ns | 0.10 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 10 | 2.263 ns | 0.1383 ns | 0.0076 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 10 | 1.877 ns | 0.0602 ns | 0.0033 ns | 0.10 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Clr | Clr | 50 | 35.068 ns | 5.9137 ns | 0.3242 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 50 | 23.299 ns | 2.3797 ns | 0.1304 ns | 0.66 | 0.01 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 50 | 3.598 ns | 4.8536 ns | 0.2660 ns | 0.10 | 0.01 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 50 | 27.720 ns | 4.6602 ns | 0.2554 ns | 0.79 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 50 | 35.673 ns | 16.2972 ns | 0.8933 ns | 1.02 | 0.03 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 50 | 5.534 ns | 2.8119 ns | 0.1541 ns | 0.16 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 50 | 4.511 ns | 0.9555 ns | 0.0524 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 50 | 5.613 ns | 1.6679 ns | 0.0914 ns | 0.16 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 50 | 4.884 ns | 7.3153 ns | 0.4010 ns | 0.14 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 50 | 20.232 ns | 1.5720 ns | 0.0862 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 50 | 8.142 ns | 0.7860 ns | 0.0431 ns | 0.40 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 50 | 2.962 ns | 0.0611 ns | 0.0033 ns | 0.15 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 50 | 16.802 ns | 2.9686 ns | 0.1627 ns | 0.83 | 0.00 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 50 | 26.571 ns | 0.9228 ns | 0.0506 ns | 1.31 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 50 | 2.219 ns | 0.7191 ns | 0.0394 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 50 | 1.751 ns | 0.1884 ns | 0.0103 ns | 0.09 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 50 | 2.177 ns | 0.4489 ns | 0.0246 ns | 0.11 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 50 | 1.806 ns | 0.1063 ns | 0.0058 ns | 0.09 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Clr | Clr | 100 | 39.158 ns | 4.3068 ns | 0.2361 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 100 | 27.623 ns | 0.4611 ns | 0.0253 ns | 0.71 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 100 | 5.018 ns | 0.5689 ns | 0.0312 ns | 0.13 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 100 | 33.527 ns | 1.9019 ns | 0.1042 ns | 0.86 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 100 | 35.604 ns | 2.7039 ns | 0.1482 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 100 | 7.853 ns | 0.4925 ns | 0.0270 ns | 0.20 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 100 | 7.406 ns | 1.9733 ns | 0.1082 ns | 0.19 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 100 | 7.822 ns | 0.6837 ns | 0.0375 ns | 0.20 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 100 | 7.392 ns | 1.2832 ns | 0.0703 ns | 0.19 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 100 | 22.909 ns | 2.9754 ns | 0.1631 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 100 | 10.687 ns | 1.1262 ns | 0.0617 ns | 0.47 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 100 | 4.063 ns | 0.1607 ns | 0.0088 ns | 0.18 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 100 | 18.067 ns | 4.0557 ns | 0.2223 ns | 0.79 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 100 | 28.352 ns | 1.2762 ns | 0.0700 ns | 1.24 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 100 | 4.130 ns | 0.2013 ns | 0.0110 ns | 0.18 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 100 | 4.096 ns | 0.2460 ns | 0.0135 ns | 0.18 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 100 | 4.160 ns | 0.3174 ns | 0.0174 ns | 0.18 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 100 | 3.480 ns | 1.1683 ns | 0.0640 ns | 0.15 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Clr | Clr | 1000 | 49.059 ns | 2.0729 ns | 0.1136 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 1000 | 38.270 ns | 23.6970 ns | 1.2989 ns | 0.78 | 0.03 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 1000 | 27.599 ns | 6.8328 ns | 0.3745 ns | 0.56 | 0.01 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 1000 | 42.752 ns | 5.1357 ns | 0.2815 ns | 0.87 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 1000 | 69.983 ns | 2.1860 ns | 0.1198 ns | 1.43 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 1000 | 44.822 ns | 0.1625 ns | 0.0089 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 1000 | 45.072 ns | 1.4053 ns | 0.0770 ns | 0.92 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 1000 | 45.306 ns | 5.2646 ns | 0.2886 ns | 0.92 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 1000 | 44.813 ns | 0.9117 ns | 0.0500 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 1000 | 51.907 ns | 3.1827 ns | 0.1745 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 1000 | 40.700 ns | 3.1488 ns | 0.1726 ns | 0.78 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 1000 | 23.711 ns | 1.3004 ns | 0.0713 ns | 0.46 | 0.00 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 1000 | 42.586 ns | 2.5390 ns | 0.1392 ns | 0.82 | 0.00 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 1000 | 44.109 ns | 4.5604 ns | 0.2500 ns | 0.85 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 1000 | 33.926 ns | 5.1633 ns | 0.2830 ns | 0.65 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 1000 | 33.267 ns | 0.2708 ns | 0.0148 ns | 0.64 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 1000 | 34.018 ns | 2.3238 ns | 0.1274 ns | 0.66 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 1000 | 33.667 ns | 2.1983 ns | 0.1205 ns | 0.65 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Clr | Clr | 10000 | 153.429 ns | 6.1735 ns | 0.3384 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Clr | Clr | 10000 | 201.373 ns | 4.3670 ns | 0.2394 ns | 1.31 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Clr | Clr | 10000 | 211.768 ns | 71.3510 ns | 3.9110 ns | 1.38 | 0.02 | - | - | - | - |
|
|||
// | Marshal.Copy() | Clr | Clr | 10000 | 215.299 ns | 17.2677 ns | 0.9465 ns | 1.40 | 0.01 | - | - | - | - |
|
|||
// | Span.CopyTo() | Clr | Clr | 10000 | 486.325 ns | 32.4445 ns | 1.7784 ns | 3.17 | 0.01 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Clr | Clr | 10000 | 452.314 ns | 33.0593 ns | 1.8121 ns | 2.95 | 0.02 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Clr | Clr | 10000 | 455.600 ns | 56.7534 ns | 3.1108 ns | 2.97 | 0.02 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Clr | Clr | 10000 | 452.279 ns | 8.6457 ns | 0.4739 ns | 2.95 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Clr | Clr | 10000 | 453.146 ns | 12.3776 ns | 0.6785 ns | 2.95 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | | |
|
|||
// | Array.Copy() | Core | Core | 10000 | 204.508 ns | 3.1652 ns | 0.1735 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | Buffer.BlockCopy() | Core | Core | 10000 | 193.345 ns | 1.3742 ns | 0.0753 ns | 0.95 | 0.00 | - | - | - | - |
|
|||
// | Buffer.MemoryCopy() | Core | Core | 10000 | 196.978 ns | 18.3279 ns | 1.0046 ns | 0.96 | 0.01 | - | - | - | - |
|
|||
// | Marshal.Copy() | Core | Core | 10000 | 206.878 ns | 6.9938 ns | 0.3834 ns | 1.01 | 0.00 | - | - | - | - |
|
|||
// | Span.CopyTo() | Core | Core | 10000 | 215.733 ns | 15.4824 ns | 0.8486 ns | 1.05 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ref) | Core | Core | 10000 | 186.894 ns | 8.7617 ns | 0.4803 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlock(ptr) | Core | Core | 10000 | 186.662 ns | 10.6059 ns | 0.5813 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ref) | Core | Core | 10000 | 187.489 ns | 13.1527 ns | 0.7209 ns | 0.92 | 0.00 | - | - | - | - |
|
|||
// | Unsafe.CopyBlockUnaligned(ptr) | Core | Core | 10000 | 186.586 ns | 4.6274 ns | 0.2536 ns | 0.91 | 0.00 | - | - | - | - |
|
|||
} |
|||
|
|||
@ -1,72 +1,70 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.Compression.Zlib; |
|||
using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class Crc32Benchmark |
|||
{ |
|||
private byte[] data; |
|||
private readonly SharpCrc32 crc = new SharpCrc32(); |
|||
namespace SixLabors.ImageSharp.Benchmarks.General; |
|||
|
|||
[Params(1024, 2048, 4096)] |
|||
public int Count { get; set; } |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class Crc32Benchmark |
|||
{ |
|||
private byte[] data; |
|||
private readonly SharpCrc32 crc = new SharpCrc32(); |
|||
|
|||
[GlobalSetup] |
|||
public void SetUp() |
|||
{ |
|||
this.data = new byte[this.Count]; |
|||
new Random(1).NextBytes(this.data); |
|||
} |
|||
[Params(1024, 2048, 4096)] |
|||
public int Count { get; set; } |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public long SharpZipLibCalculate() |
|||
{ |
|||
this.crc.Reset(); |
|||
this.crc.Update(this.data); |
|||
return this.crc.Value; |
|||
} |
|||
[GlobalSetup] |
|||
public void SetUp() |
|||
{ |
|||
this.data = new byte[this.Count]; |
|||
new Random(1).NextBytes(this.data); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public long SixLaborsCalculate() |
|||
{ |
|||
return Crc32.Calculate(this.data); |
|||
} |
|||
[Benchmark(Baseline = true)] |
|||
public long SharpZipLibCalculate() |
|||
{ |
|||
this.crc.Reset(); |
|||
this.crc.Update(this.data); |
|||
return this.crc.Value; |
|||
} |
|||
|
|||
// ########## 17/05/2020 ##########
|
|||
//
|
|||
// | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |--------------------- |-------------- |------ |-------------:|-------------:|-----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 2,797.77 ns | 278.697 ns | 15.276 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 1024 | 2,275.56 ns | 216.100 ns | 11.845 ns | 0.81 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 2,923.43 ns | 2,656.882 ns | 145.633 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 1024 | 2,257.79 ns | 75.081 ns | 4.115 ns | 0.77 | 0.04 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 2,764.14 ns | 86.281 ns | 4.729 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 1024 | 49.32 ns | 1.813 ns | 0.099 ns | 0.02 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 5,603.71 ns | 427.240 ns | 23.418 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 2048 | 4,525.02 ns | 33.931 ns | 1.860 ns | 0.81 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 5,563.32 ns | 49.337 ns | 2.704 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 2048 | 4,519.61 ns | 29.837 ns | 1.635 ns | 0.81 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 5,543.37 ns | 518.551 ns | 28.424 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 2048 | 89.07 ns | 3.312 ns | 0.182 ns | 0.02 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 11,396.95 ns | 373.450 ns | 20.470 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 4096 | 9,070.35 ns | 271.083 ns | 14.859 ns | 0.80 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 11,127.81 ns | 239.177 ns | 13.110 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 4096 | 9,050.46 ns | 230.916 ns | 12.657 ns | 0.81 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 11,098.62 ns | 687.978 ns | 37.710 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 4096 | 168.11 ns | 3.633 ns | 0.199 ns | 0.02 | 0.00 | - | - | - | - |
|
|||
[Benchmark] |
|||
public long SixLaborsCalculate() |
|||
{ |
|||
return Crc32.Calculate(this.data); |
|||
} |
|||
} |
|||
|
|||
// ########## 17/05/2020 ##########
|
|||
//
|
|||
// | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|
|||
// |--------------------- |-------------- |------ |-------------:|-------------:|-----------:|------:|--------:|------:|------:|------:|----------:|
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 2,797.77 ns | 278.697 ns | 15.276 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 1024 | 2,275.56 ns | 216.100 ns | 11.845 ns | 0.81 | 0.01 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 2,923.43 ns | 2,656.882 ns | 145.633 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 1024 | 2,257.79 ns | 75.081 ns | 4.115 ns | 0.77 | 0.04 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 2,764.14 ns | 86.281 ns | 4.729 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 1024 | 49.32 ns | 1.813 ns | 0.099 ns | 0.02 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 5,603.71 ns | 427.240 ns | 23.418 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 2048 | 4,525.02 ns | 33.931 ns | 1.860 ns | 0.81 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 5,563.32 ns | 49.337 ns | 2.704 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 2048 | 4,519.61 ns | 29.837 ns | 1.635 ns | 0.81 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 5,543.37 ns | 518.551 ns | 28.424 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 2048 | 89.07 ns | 3.312 ns | 0.182 ns | 0.02 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 11,396.95 ns | 373.450 ns | 20.470 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET 4.7.2 | 4096 | 9,070.35 ns | 271.083 ns | 14.859 ns | 0.80 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 11,127.81 ns | 239.177 ns | 13.110 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 2.1 | 4096 | 9,050.46 ns | 230.916 ns | 12.657 ns | 0.81 | 0.00 | - | - | - | - |
|
|||
// | | | | | | | | | | | | |
|
|||
// | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 11,098.62 ns | 687.978 ns | 37.710 ns | 1.00 | 0.00 | - | - | - | - |
|
|||
// | SixLaborsCalculate | .NET Core 3.1 | 4096 | 168.11 ns | 3.633 ns | 0.199 ns | 0.02 | 0.00 | - | - | - | - |
|
|||
|
|||
@ -1,279 +1,276 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.IO; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.IO |
|||
namespace SixLabors.ImageSharp.Benchmarks.IO; |
|||
|
|||
/// <summary>
|
|||
/// A readonly stream wrapper that add a secondary level buffer in addition to native stream
|
|||
/// buffered reading to reduce the overhead of small incremental reads.
|
|||
/// </summary>
|
|||
internal sealed unsafe class BufferedReadStreamWrapper : IDisposable |
|||
{ |
|||
/// <summary>
|
|||
/// A readonly stream wrapper that add a secondary level buffer in addition to native stream
|
|||
/// buffered reading to reduce the overhead of small incremental reads.
|
|||
/// The length, in bytes, of the underlying buffer.
|
|||
/// </summary>
|
|||
internal sealed unsafe class BufferedReadStreamWrapper : IDisposable |
|||
{ |
|||
/// <summary>
|
|||
/// The length, in bytes, of the underlying buffer.
|
|||
/// </summary>
|
|||
public const int BufferLength = 8192; |
|||
|
|||
private const int MaxBufferIndex = BufferLength - 1; |
|||
|
|||
private readonly Stream stream; |
|||
public const int BufferLength = 8192; |
|||
|
|||
private readonly byte[] readBuffer; |
|||
private const int MaxBufferIndex = BufferLength - 1; |
|||
|
|||
private MemoryHandle readBufferHandle; |
|||
private readonly Stream stream; |
|||
|
|||
private readonly byte* pinnedReadBuffer; |
|||
private readonly byte[] readBuffer; |
|||
|
|||
// Index within our buffer, not reader position.
|
|||
private int readBufferIndex; |
|||
private MemoryHandle readBufferHandle; |
|||
|
|||
// Matches what the stream position would be without buffering
|
|||
private long readerPosition; |
|||
private readonly byte* pinnedReadBuffer; |
|||
|
|||
private bool isDisposed; |
|||
// Index within our buffer, not reader position.
|
|||
private int readBufferIndex; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BufferedReadStreamWrapper"/> class.
|
|||
/// </summary>
|
|||
/// <param name="stream">The input stream.</param>
|
|||
public BufferedReadStreamWrapper(Stream stream) |
|||
{ |
|||
Guard.IsTrue(stream.CanRead, nameof(stream), "Stream must be readable."); |
|||
Guard.IsTrue(stream.CanSeek, nameof(stream), "Stream must be seekable."); |
|||
|
|||
// Ensure all underlying buffers have been flushed before we attempt to read the stream.
|
|||
// User streams may have opted to throw from Flush if CanWrite is false
|
|||
// (although the abstract Stream does not do so).
|
|||
if (stream.CanWrite) |
|||
{ |
|||
stream.Flush(); |
|||
} |
|||
// Matches what the stream position would be without buffering
|
|||
private long readerPosition; |
|||
|
|||
this.stream = stream; |
|||
this.Position = (int)stream.Position; |
|||
this.Length = stream.Length; |
|||
private bool isDisposed; |
|||
|
|||
this.readBuffer = ArrayPool<byte>.Shared.Rent(BufferLength); |
|||
this.readBufferHandle = new Memory<byte>(this.readBuffer).Pin(); |
|||
this.pinnedReadBuffer = (byte*)this.readBufferHandle.Pointer; |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BufferedReadStreamWrapper"/> class.
|
|||
/// </summary>
|
|||
/// <param name="stream">The input stream.</param>
|
|||
public BufferedReadStreamWrapper(Stream stream) |
|||
{ |
|||
Guard.IsTrue(stream.CanRead, nameof(stream), "Stream must be readable."); |
|||
Guard.IsTrue(stream.CanSeek, nameof(stream), "Stream must be seekable."); |
|||
|
|||
// This triggers a full read on first attempt.
|
|||
this.readBufferIndex = BufferLength; |
|||
// Ensure all underlying buffers have been flushed before we attempt to read the stream.
|
|||
// User streams may have opted to throw from Flush if CanWrite is false
|
|||
// (although the abstract Stream does not do so).
|
|||
if (stream.CanWrite) |
|||
{ |
|||
stream.Flush(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the length, in bytes, of the stream.
|
|||
/// </summary>
|
|||
public long Length { get; } |
|||
this.stream = stream; |
|||
this.Position = (int)stream.Position; |
|||
this.Length = stream.Length; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the current position within the stream.
|
|||
/// </summary>
|
|||
public long Position |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.readerPosition; |
|||
this.readBuffer = ArrayPool<byte>.Shared.Rent(BufferLength); |
|||
this.readBufferHandle = new Memory<byte>(this.readBuffer).Pin(); |
|||
this.pinnedReadBuffer = (byte*)this.readBufferHandle.Pointer; |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
set |
|||
{ |
|||
// Only reset readBufferIndex if we are out of bounds of our working buffer
|
|||
// otherwise we should simply move the value by the diff.
|
|||
if (this.IsInReadBuffer(value, out long index)) |
|||
{ |
|||
this.readBufferIndex = (int)index; |
|||
this.readerPosition = value; |
|||
} |
|||
else |
|||
{ |
|||
// Base stream seek will throw for us if invalid.
|
|||
this.stream.Seek(value, SeekOrigin.Begin); |
|||
this.readerPosition = value; |
|||
this.readBufferIndex = BufferLength; |
|||
} |
|||
} |
|||
} |
|||
// This triggers a full read on first attempt.
|
|||
this.readBufferIndex = BufferLength; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the length, in bytes, of the stream.
|
|||
/// </summary>
|
|||
public long Length { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the current position within the stream.
|
|||
/// </summary>
|
|||
public long Position |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public int ReadByte() |
|||
get => this.readerPosition; |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
set |
|||
{ |
|||
if (this.readerPosition >= this.Length) |
|||
// Only reset readBufferIndex if we are out of bounds of our working buffer
|
|||
// otherwise we should simply move the value by the diff.
|
|||
if (this.IsInReadBuffer(value, out long index)) |
|||
{ |
|||
return -1; |
|||
this.readBufferIndex = (int)index; |
|||
this.readerPosition = value; |
|||
} |
|||
|
|||
// Our buffer has been read.
|
|||
// We need to refill and start again.
|
|||
if (this.readBufferIndex > MaxBufferIndex) |
|||
else |
|||
{ |
|||
this.FillReadBuffer(); |
|||
// Base stream seek will throw for us if invalid.
|
|||
this.stream.Seek(value, SeekOrigin.Begin); |
|||
this.readerPosition = value; |
|||
this.readBufferIndex = BufferLength; |
|||
} |
|||
} |
|||
} |
|||
|
|||
this.readerPosition++; |
|||
return this.pinnedReadBuffer[this.readBufferIndex++]; |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public int ReadByte() |
|||
{ |
|||
if (this.readerPosition >= this.Length) |
|||
{ |
|||
return -1; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public int Read(byte[] buffer, int offset, int count) |
|||
// Our buffer has been read.
|
|||
// We need to refill and start again.
|
|||
if (this.readBufferIndex > MaxBufferIndex) |
|||
{ |
|||
// Too big for our buffer. Read directly from the stream.
|
|||
if (count > BufferLength) |
|||
{ |
|||
return this.ReadToBufferDirectSlow(buffer, offset, count); |
|||
} |
|||
this.FillReadBuffer(); |
|||
} |
|||
|
|||
// Too big for remaining buffer but less than entire buffer length
|
|||
// Copy to buffer then read from there.
|
|||
if (count + this.readBufferIndex > BufferLength) |
|||
{ |
|||
return this.ReadToBufferViaCopySlow(buffer, offset, count); |
|||
} |
|||
this.readerPosition++; |
|||
return this.pinnedReadBuffer[this.readBufferIndex++]; |
|||
} |
|||
|
|||
return this.ReadToBufferViaCopyFast(buffer, offset, count); |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public int Read(byte[] buffer, int offset, int count) |
|||
{ |
|||
// Too big for our buffer. Read directly from the stream.
|
|||
if (count > BufferLength) |
|||
{ |
|||
return this.ReadToBufferDirectSlow(buffer, offset, count); |
|||
} |
|||
|
|||
public void Flush() |
|||
// Too big for remaining buffer but less than entire buffer length
|
|||
// Copy to buffer then read from there.
|
|||
if (count + this.readBufferIndex > BufferLength) |
|||
{ |
|||
// Reset the stream position to match reader position.
|
|||
if (this.readerPosition != this.stream.Position) |
|||
{ |
|||
this.stream.Seek(this.readerPosition, SeekOrigin.Begin); |
|||
this.readerPosition = (int)this.stream.Position; |
|||
} |
|||
|
|||
// Reset to trigger full read on next attempt.
|
|||
this.readBufferIndex = BufferLength; |
|||
return this.ReadToBufferViaCopySlow(buffer, offset, count); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public long Seek(long offset, SeekOrigin origin) |
|||
return this.ReadToBufferViaCopyFast(buffer, offset, count); |
|||
} |
|||
|
|||
public void Flush() |
|||
{ |
|||
// Reset the stream position to match reader position.
|
|||
if (this.readerPosition != this.stream.Position) |
|||
{ |
|||
switch (origin) |
|||
{ |
|||
case SeekOrigin.Begin: |
|||
this.Position = offset; |
|||
break; |
|||
this.stream.Seek(this.readerPosition, SeekOrigin.Begin); |
|||
this.readerPosition = (int)this.stream.Position; |
|||
} |
|||
|
|||
case SeekOrigin.Current: |
|||
this.Position += offset; |
|||
break; |
|||
// Reset to trigger full read on next attempt.
|
|||
this.readBufferIndex = BufferLength; |
|||
} |
|||
|
|||
case SeekOrigin.End: |
|||
this.Position = this.Length - offset; |
|||
break; |
|||
} |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public long Seek(long offset, SeekOrigin origin) |
|||
{ |
|||
switch (origin) |
|||
{ |
|||
case SeekOrigin.Begin: |
|||
this.Position = offset; |
|||
break; |
|||
|
|||
return this.readerPosition; |
|||
case SeekOrigin.Current: |
|||
this.Position += offset; |
|||
break; |
|||
|
|||
case SeekOrigin.End: |
|||
this.Position = this.Length - offset; |
|||
break; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Dispose() |
|||
return this.readerPosition; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public void Dispose() |
|||
{ |
|||
if (!this.isDisposed) |
|||
{ |
|||
if (!this.isDisposed) |
|||
{ |
|||
this.isDisposed = true; |
|||
this.readBufferHandle.Dispose(); |
|||
ArrayPool<byte>.Shared.Return(this.readBuffer); |
|||
this.Flush(); |
|||
} |
|||
this.isDisposed = true; |
|||
this.readBufferHandle.Dispose(); |
|||
ArrayPool<byte>.Shared.Return(this.readBuffer); |
|||
this.Flush(); |
|||
} |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private bool IsInReadBuffer(long newPosition, out long index) |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private bool IsInReadBuffer(long newPosition, out long index) |
|||
{ |
|||
index = newPosition - this.readerPosition + this.readBufferIndex; |
|||
return index > -1 && index < BufferLength; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private void FillReadBuffer() |
|||
{ |
|||
if (this.readerPosition != this.stream.Position) |
|||
{ |
|||
index = newPosition - this.readerPosition + this.readBufferIndex; |
|||
return index > -1 && index < BufferLength; |
|||
this.stream.Seek(this.readerPosition, SeekOrigin.Begin); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private void FillReadBuffer() |
|||
{ |
|||
if (this.readerPosition != this.stream.Position) |
|||
{ |
|||
this.stream.Seek(this.readerPosition, SeekOrigin.Begin); |
|||
} |
|||
this.stream.Read(this.readBuffer, 0, BufferLength); |
|||
this.readBufferIndex = 0; |
|||
} |
|||
|
|||
this.stream.Read(this.readBuffer, 0, BufferLength); |
|||
this.readBufferIndex = 0; |
|||
} |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private int ReadToBufferViaCopyFast(byte[] buffer, int offset, int count) |
|||
{ |
|||
int n = this.GetCopyCount(count); |
|||
this.CopyBytes(buffer, offset, n); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private int ReadToBufferViaCopyFast(byte[] buffer, int offset, int count) |
|||
{ |
|||
int n = this.GetCopyCount(count); |
|||
this.CopyBytes(buffer, offset, n); |
|||
this.readerPosition += n; |
|||
this.readBufferIndex += n; |
|||
|
|||
this.readerPosition += n; |
|||
this.readBufferIndex += n; |
|||
return n; |
|||
} |
|||
|
|||
return n; |
|||
} |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private int ReadToBufferViaCopySlow(byte[] buffer, int offset, int count) |
|||
{ |
|||
// Refill our buffer then copy.
|
|||
this.FillReadBuffer(); |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private int ReadToBufferViaCopySlow(byte[] buffer, int offset, int count) |
|||
{ |
|||
// Refill our buffer then copy.
|
|||
this.FillReadBuffer(); |
|||
return this.ReadToBufferViaCopyFast(buffer, offset, count); |
|||
} |
|||
|
|||
return this.ReadToBufferViaCopyFast(buffer, offset, count); |
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private int ReadToBufferDirectSlow(byte[] buffer, int offset, int count) |
|||
{ |
|||
// Read to target but don't copy to our read buffer.
|
|||
if (this.readerPosition != this.stream.Position) |
|||
{ |
|||
this.stream.Seek(this.readerPosition, SeekOrigin.Begin); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private int ReadToBufferDirectSlow(byte[] buffer, int offset, int count) |
|||
{ |
|||
// Read to target but don't copy to our read buffer.
|
|||
if (this.readerPosition != this.stream.Position) |
|||
{ |
|||
this.stream.Seek(this.readerPosition, SeekOrigin.Begin); |
|||
} |
|||
int n = this.stream.Read(buffer, offset, count); |
|||
this.Position += n; |
|||
|
|||
int n = this.stream.Read(buffer, offset, count); |
|||
this.Position += n; |
|||
return n; |
|||
} |
|||
|
|||
return n; |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private int GetCopyCount(int count) |
|||
{ |
|||
long n = this.Length - this.readerPosition; |
|||
if (n > count) |
|||
{ |
|||
return count; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private int GetCopyCount(int count) |
|||
if (n < 0) |
|||
{ |
|||
long n = this.Length - this.readerPosition; |
|||
if (n > count) |
|||
{ |
|||
return count; |
|||
} |
|||
|
|||
if (n < 0) |
|||
{ |
|||
return 0; |
|||
} |
|||
|
|||
return (int)n; |
|||
return 0; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private void CopyBytes(byte[] buffer, int offset, int count) |
|||
return (int)n; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private void CopyBytes(byte[] buffer, int offset, int count) |
|||
{ |
|||
// Same as MemoryStream.
|
|||
if (count < 9) |
|||
{ |
|||
// Same as MemoryStream.
|
|||
if (count < 9) |
|||
{ |
|||
int byteCount = count; |
|||
int read = this.readBufferIndex; |
|||
byte* pinned = this.pinnedReadBuffer; |
|||
|
|||
while (--byteCount > -1) |
|||
{ |
|||
buffer[offset + byteCount] = pinned[read + byteCount]; |
|||
} |
|||
} |
|||
else |
|||
int byteCount = count; |
|||
int read = this.readBufferIndex; |
|||
byte* pinned = this.pinnedReadBuffer; |
|||
|
|||
while (--byteCount > -1) |
|||
{ |
|||
Buffer.BlockCopy(this.readBuffer, this.readBufferIndex, buffer, offset, count); |
|||
buffer[offset + byteCount] = pinned[read + byteCount]; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
Buffer.BlockCopy(this.readBuffer, this.readBufferIndex, buffer, offset, count); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,261 +1,258 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.IO; |
|||
using BenchmarkDotNet.Attributes; |
|||
using SixLabors.ImageSharp.IO; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.IO |
|||
namespace SixLabors.ImageSharp.Benchmarks.IO; |
|||
|
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class BufferedStreams |
|||
{ |
|||
[Config(typeof(Config.ShortMultiFramework))] |
|||
public class BufferedStreams |
|||
private readonly byte[] buffer = CreateTestBytes(); |
|||
private readonly byte[] chunk1 = new byte[2]; |
|||
private readonly byte[] chunk2 = new byte[2]; |
|||
|
|||
private MemoryStream stream1; |
|||
private MemoryStream stream2; |
|||
private MemoryStream stream3; |
|||
private MemoryStream stream4; |
|||
private MemoryStream stream5; |
|||
private MemoryStream stream6; |
|||
private ChunkedMemoryStream chunkedMemoryStream1; |
|||
private ChunkedMemoryStream chunkedMemoryStream2; |
|||
private BufferedReadStream bufferedStream1; |
|||
private BufferedReadStream bufferedStream2; |
|||
private BufferedReadStream bufferedStream3; |
|||
private BufferedReadStream bufferedStream4; |
|||
private BufferedReadStreamWrapper bufferedStreamWrap1; |
|||
private BufferedReadStreamWrapper bufferedStreamWrap2; |
|||
|
|||
[GlobalSetup] |
|||
public void CreateStreams() |
|||
{ |
|||
private readonly byte[] buffer = CreateTestBytes(); |
|||
private readonly byte[] chunk1 = new byte[2]; |
|||
private readonly byte[] chunk2 = new byte[2]; |
|||
|
|||
private MemoryStream stream1; |
|||
private MemoryStream stream2; |
|||
private MemoryStream stream3; |
|||
private MemoryStream stream4; |
|||
private MemoryStream stream5; |
|||
private MemoryStream stream6; |
|||
private ChunkedMemoryStream chunkedMemoryStream1; |
|||
private ChunkedMemoryStream chunkedMemoryStream2; |
|||
private BufferedReadStream bufferedStream1; |
|||
private BufferedReadStream bufferedStream2; |
|||
private BufferedReadStream bufferedStream3; |
|||
private BufferedReadStream bufferedStream4; |
|||
private BufferedReadStreamWrapper bufferedStreamWrap1; |
|||
private BufferedReadStreamWrapper bufferedStreamWrap2; |
|||
|
|||
[GlobalSetup] |
|||
public void CreateStreams() |
|||
{ |
|||
this.stream1 = new MemoryStream(this.buffer); |
|||
this.stream2 = new MemoryStream(this.buffer); |
|||
this.stream3 = new MemoryStream(this.buffer); |
|||
this.stream4 = new MemoryStream(this.buffer); |
|||
this.stream5 = new MemoryStream(this.buffer); |
|||
this.stream6 = new MemoryStream(this.buffer); |
|||
this.stream6 = new MemoryStream(this.buffer); |
|||
|
|||
this.chunkedMemoryStream1 = new ChunkedMemoryStream(Configuration.Default.MemoryAllocator); |
|||
this.chunkedMemoryStream1.Write(this.buffer); |
|||
this.chunkedMemoryStream1.Position = 0; |
|||
|
|||
this.chunkedMemoryStream2 = new ChunkedMemoryStream(Configuration.Default.MemoryAllocator); |
|||
this.chunkedMemoryStream2.Write(this.buffer); |
|||
this.chunkedMemoryStream2.Position = 0; |
|||
|
|||
this.bufferedStream1 = new BufferedReadStream(Configuration.Default, this.stream3); |
|||
this.bufferedStream2 = new BufferedReadStream(Configuration.Default, this.stream4); |
|||
this.bufferedStream3 = new BufferedReadStream(Configuration.Default, this.chunkedMemoryStream1); |
|||
this.bufferedStream4 = new BufferedReadStream(Configuration.Default, this.chunkedMemoryStream2); |
|||
this.bufferedStreamWrap1 = new BufferedReadStreamWrapper(this.stream5); |
|||
this.bufferedStreamWrap2 = new BufferedReadStreamWrapper(this.stream6); |
|||
} |
|||
|
|||
[GlobalCleanup] |
|||
public void DestroyStreams() |
|||
{ |
|||
this.bufferedStream1?.Dispose(); |
|||
this.bufferedStream2?.Dispose(); |
|||
this.bufferedStream3?.Dispose(); |
|||
this.bufferedStream4?.Dispose(); |
|||
this.bufferedStreamWrap1?.Dispose(); |
|||
this.bufferedStreamWrap2?.Dispose(); |
|||
this.chunkedMemoryStream1?.Dispose(); |
|||
this.chunkedMemoryStream2?.Dispose(); |
|||
this.stream1?.Dispose(); |
|||
this.stream2?.Dispose(); |
|||
this.stream3?.Dispose(); |
|||
this.stream4?.Dispose(); |
|||
this.stream5?.Dispose(); |
|||
this.stream6?.Dispose(); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public int StandardStreamRead() |
|||
{ |
|||
int r = 0; |
|||
Stream stream = this.stream1; |
|||
byte[] b = this.chunk1; |
|||
this.stream1 = new MemoryStream(this.buffer); |
|||
this.stream2 = new MemoryStream(this.buffer); |
|||
this.stream3 = new MemoryStream(this.buffer); |
|||
this.stream4 = new MemoryStream(this.buffer); |
|||
this.stream5 = new MemoryStream(this.buffer); |
|||
this.stream6 = new MemoryStream(this.buffer); |
|||
this.stream6 = new MemoryStream(this.buffer); |
|||
|
|||
this.chunkedMemoryStream1 = new ChunkedMemoryStream(Configuration.Default.MemoryAllocator); |
|||
this.chunkedMemoryStream1.Write(this.buffer); |
|||
this.chunkedMemoryStream1.Position = 0; |
|||
|
|||
this.chunkedMemoryStream2 = new ChunkedMemoryStream(Configuration.Default.MemoryAllocator); |
|||
this.chunkedMemoryStream2.Write(this.buffer); |
|||
this.chunkedMemoryStream2.Position = 0; |
|||
|
|||
this.bufferedStream1 = new BufferedReadStream(Configuration.Default, this.stream3); |
|||
this.bufferedStream2 = new BufferedReadStream(Configuration.Default, this.stream4); |
|||
this.bufferedStream3 = new BufferedReadStream(Configuration.Default, this.chunkedMemoryStream1); |
|||
this.bufferedStream4 = new BufferedReadStream(Configuration.Default, this.chunkedMemoryStream2); |
|||
this.bufferedStreamWrap1 = new BufferedReadStreamWrapper(this.stream5); |
|||
this.bufferedStreamWrap2 = new BufferedReadStreamWrapper(this.stream6); |
|||
} |
|||
|
|||
for (int i = 0; i < stream.Length / 2; i++) |
|||
{ |
|||
r += stream.Read(b, 0, 2); |
|||
} |
|||
[GlobalCleanup] |
|||
public void DestroyStreams() |
|||
{ |
|||
this.bufferedStream1?.Dispose(); |
|||
this.bufferedStream2?.Dispose(); |
|||
this.bufferedStream3?.Dispose(); |
|||
this.bufferedStream4?.Dispose(); |
|||
this.bufferedStreamWrap1?.Dispose(); |
|||
this.bufferedStreamWrap2?.Dispose(); |
|||
this.chunkedMemoryStream1?.Dispose(); |
|||
this.chunkedMemoryStream2?.Dispose(); |
|||
this.stream1?.Dispose(); |
|||
this.stream2?.Dispose(); |
|||
this.stream3?.Dispose(); |
|||
this.stream4?.Dispose(); |
|||
this.stream5?.Dispose(); |
|||
this.stream6?.Dispose(); |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
[Benchmark] |
|||
public int StandardStreamRead() |
|||
{ |
|||
int r = 0; |
|||
Stream stream = this.stream1; |
|||
byte[] b = this.chunk1; |
|||
|
|||
[Benchmark] |
|||
public int BufferedReadStreamRead() |
|||
for (int i = 0; i < stream.Length / 2; i++) |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStream reader = this.bufferedStream1; |
|||
byte[] b = this.chunk2; |
|||
r += stream.Read(b, 0, 2); |
|||
} |
|||
|
|||
for (int i = 0; i < reader.Length / 2; i++) |
|||
{ |
|||
r += reader.Read(b, 0, 2); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
[Benchmark] |
|||
public int BufferedReadStreamRead() |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStream reader = this.bufferedStream1; |
|||
byte[] b = this.chunk2; |
|||
|
|||
[Benchmark] |
|||
public int BufferedReadStreamChunkedRead() |
|||
for (int i = 0; i < reader.Length / 2; i++) |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStream reader = this.bufferedStream3; |
|||
byte[] b = this.chunk2; |
|||
r += reader.Read(b, 0, 2); |
|||
} |
|||
|
|||
for (int i = 0; i < reader.Length / 2; i++) |
|||
{ |
|||
r += reader.Read(b, 0, 2); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
[Benchmark] |
|||
public int BufferedReadStreamChunkedRead() |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStream reader = this.bufferedStream3; |
|||
byte[] b = this.chunk2; |
|||
|
|||
[Benchmark] |
|||
public int BufferedReadStreamWrapRead() |
|||
for (int i = 0; i < reader.Length / 2; i++) |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStreamWrapper reader = this.bufferedStreamWrap1; |
|||
byte[] b = this.chunk2; |
|||
r += reader.Read(b, 0, 2); |
|||
} |
|||
|
|||
for (int i = 0; i < reader.Length / 2; i++) |
|||
{ |
|||
r += reader.Read(b, 0, 2); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
[Benchmark] |
|||
public int BufferedReadStreamWrapRead() |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStreamWrapper reader = this.bufferedStreamWrap1; |
|||
byte[] b = this.chunk2; |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public int StandardStreamReadByte() |
|||
for (int i = 0; i < reader.Length / 2; i++) |
|||
{ |
|||
int r = 0; |
|||
Stream stream = this.stream2; |
|||
r += reader.Read(b, 0, 2); |
|||
} |
|||
|
|||
for (int i = 0; i < stream.Length; i++) |
|||
{ |
|||
r += stream.ReadByte(); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
[Benchmark(Baseline = true)] |
|||
public int StandardStreamReadByte() |
|||
{ |
|||
int r = 0; |
|||
Stream stream = this.stream2; |
|||
|
|||
[Benchmark] |
|||
public int BufferedReadStreamReadByte() |
|||
for (int i = 0; i < stream.Length; i++) |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStream reader = this.bufferedStream2; |
|||
r += stream.ReadByte(); |
|||
} |
|||
|
|||
for (int i = 0; i < reader.Length; i++) |
|||
{ |
|||
r += reader.ReadByte(); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
[Benchmark] |
|||
public int BufferedReadStreamReadByte() |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStream reader = this.bufferedStream2; |
|||
|
|||
[Benchmark] |
|||
public int BufferedReadStreamChunkedReadByte() |
|||
for (int i = 0; i < reader.Length; i++) |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStream reader = this.bufferedStream4; |
|||
r += reader.ReadByte(); |
|||
} |
|||
|
|||
for (int i = 0; i < reader.Length; i++) |
|||
{ |
|||
r += reader.ReadByte(); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
[Benchmark] |
|||
public int BufferedReadStreamChunkedReadByte() |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStream reader = this.bufferedStream4; |
|||
|
|||
[Benchmark] |
|||
public int BufferedReadStreamWrapReadByte() |
|||
for (int i = 0; i < reader.Length; i++) |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStreamWrapper reader = this.bufferedStreamWrap2; |
|||
r += reader.ReadByte(); |
|||
} |
|||
|
|||
for (int i = 0; i < reader.Length; i++) |
|||
{ |
|||
r += reader.ReadByte(); |
|||
} |
|||
return r; |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
[Benchmark] |
|||
public int BufferedReadStreamWrapReadByte() |
|||
{ |
|||
int r = 0; |
|||
BufferedReadStreamWrapper reader = this.bufferedStreamWrap2; |
|||
|
|||
[Benchmark] |
|||
public int ArrayReadByte() |
|||
for (int i = 0; i < reader.Length; i++) |
|||
{ |
|||
byte[] b = this.buffer; |
|||
int r = 0; |
|||
for (int i = 0; i < b.Length; i++) |
|||
{ |
|||
r += b[i]; |
|||
} |
|||
|
|||
return r; |
|||
r += reader.ReadByte(); |
|||
} |
|||
|
|||
private static byte[] CreateTestBytes() |
|||
{ |
|||
var buffer = new byte[Configuration.Default.StreamProcessingBufferSize * 3]; |
|||
var random = new Random(); |
|||
random.NextBytes(buffer); |
|||
return r; |
|||
} |
|||
|
|||
return buffer; |
|||
[Benchmark] |
|||
public int ArrayReadByte() |
|||
{ |
|||
byte[] b = this.buffer; |
|||
int r = 0; |
|||
for (int i = 0; i < b.Length; i++) |
|||
{ |
|||
r += b[i]; |
|||
} |
|||
|
|||
return r; |
|||
} |
|||
|
|||
/* |
|||
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.450 (2004/?/20H1) |
|||
Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores |
|||
.NET Core SDK=3.1.401 |
|||
[Host] : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT |
|||
Job-OKZLUV : .NET Framework 4.8 (4.8.4084.0), X64 RyuJIT |
|||
Job-CPYMXV : .NET Core 2.1.21 (CoreCLR 4.6.29130.01, CoreFX 4.6.29130.02), X64 RyuJIT |
|||
Job-BSGVGU : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT |
|||
|
|||
IterationCount=3 LaunchCount=1 WarmupCount=3 |
|||
|
|||
| Method | Job | Runtime | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | |
|||
|---------------------------------- |----------- |-------------- |-----------:|----------:|----------:|------:|--------:|------:|------:|------:|----------:| |
|||
| StandardStreamRead | Job-OKZLUV | .NET 4.7.2 | 66.785 us | 15.768 us | 0.8643 us | 0.83 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamRead | Job-OKZLUV | .NET 4.7.2 | 97.389 us | 17.658 us | 0.9679 us | 1.21 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamChunkedRead | Job-OKZLUV | .NET 4.7.2 | 96.006 us | 16.286 us | 0.8927 us | 1.20 | 0.02 | - | - | - | - | |
|||
| BufferedReadStreamWrapRead | Job-OKZLUV | .NET 4.7.2 | 37.064 us | 14.640 us | 0.8024 us | 0.46 | 0.02 | - | - | - | - | |
|||
| StandardStreamReadByte | Job-OKZLUV | .NET 4.7.2 | 80.315 us | 26.676 us | 1.4622 us | 1.00 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamReadByte | Job-OKZLUV | .NET 4.7.2 | 118.706 us | 38.013 us | 2.0836 us | 1.48 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamChunkedReadByte | Job-OKZLUV | .NET 4.7.2 | 115.437 us | 33.352 us | 1.8282 us | 1.44 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamWrapReadByte | Job-OKZLUV | .NET 4.7.2 | 16.449 us | 11.400 us | 0.6249 us | 0.20 | 0.00 | - | - | - | - | |
|||
| ArrayReadByte | Job-OKZLUV | .NET 4.7.2 | 10.416 us | 1.866 us | 0.1023 us | 0.13 | 0.00 | - | - | - | - | |
|||
| | | | | | | | | | | | | |
|||
| StandardStreamRead | Job-CPYMXV | .NET Core 2.1 | 71.425 us | 50.441 us | 2.7648 us | 0.82 | 0.03 | - | - | - | - | |
|||
| BufferedReadStreamRead | Job-CPYMXV | .NET Core 2.1 | 32.816 us | 6.655 us | 0.3648 us | 0.38 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamChunkedRead | Job-CPYMXV | .NET Core 2.1 | 31.995 us | 7.751 us | 0.4249 us | 0.37 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamWrapRead | Job-CPYMXV | .NET Core 2.1 | 31.970 us | 4.170 us | 0.2286 us | 0.37 | 0.01 | - | - | - | - | |
|||
| StandardStreamReadByte | Job-CPYMXV | .NET Core 2.1 | 86.909 us | 18.565 us | 1.0176 us | 1.00 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamReadByte | Job-CPYMXV | .NET Core 2.1 | 14.596 us | 10.889 us | 0.5969 us | 0.17 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamChunkedReadByte | Job-CPYMXV | .NET Core 2.1 | 13.629 us | 1.569 us | 0.0860 us | 0.16 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamWrapReadByte | Job-CPYMXV | .NET Core 2.1 | 13.566 us | 1.743 us | 0.0956 us | 0.16 | 0.00 | - | - | - | - | |
|||
| ArrayReadByte | Job-CPYMXV | .NET Core 2.1 | 9.771 us | 6.658 us | 0.3650 us | 0.11 | 0.00 | - | - | - | - | |
|||
| | | | | | | | | | | | | |
|||
| StandardStreamRead | Job-BSGVGU | .NET Core 3.1 | 53.265 us | 65.819 us | 3.6078 us | 0.81 | 0.05 | - | - | - | - | |
|||
| BufferedReadStreamRead | Job-BSGVGU | .NET Core 3.1 | 33.163 us | 9.569 us | 0.5245 us | 0.51 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamChunkedRead | Job-BSGVGU | .NET Core 3.1 | 33.001 us | 6.114 us | 0.3351 us | 0.50 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamWrapRead | Job-BSGVGU | .NET Core 3.1 | 29.448 us | 7.120 us | 0.3902 us | 0.45 | 0.01 | - | - | - | - | |
|||
| StandardStreamReadByte | Job-BSGVGU | .NET Core 3.1 | 65.619 us | 6.732 us | 0.3690 us | 1.00 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamReadByte | Job-BSGVGU | .NET Core 3.1 | 13.989 us | 3.464 us | 0.1899 us | 0.21 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamChunkedReadByte | Job-BSGVGU | .NET Core 3.1 | 13.806 us | 1.710 us | 0.0938 us | 0.21 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamWrapReadByte | Job-BSGVGU | .NET Core 3.1 | 13.690 us | 1.523 us | 0.0835 us | 0.21 | 0.00 | - | - | - | - | |
|||
| ArrayReadByte | Job-BSGVGU | .NET Core 3.1 | 10.792 us | 8.228 us | 0.4510 us | 0.16 | 0.01 | - | - | - | - | |
|||
*/ |
|||
private static byte[] CreateTestBytes() |
|||
{ |
|||
var buffer = new byte[Configuration.Default.StreamProcessingBufferSize * 3]; |
|||
var random = new Random(); |
|||
random.NextBytes(buffer); |
|||
|
|||
return buffer; |
|||
} |
|||
} |
|||
|
|||
/* |
|||
BenchmarkDotNet=v0.12.1, OS=Windows 10.0.19041.450 (2004/?/20H1) |
|||
Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores |
|||
.NET Core SDK=3.1.401 |
|||
[Host] : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT |
|||
Job-OKZLUV : .NET Framework 4.8 (4.8.4084.0), X64 RyuJIT |
|||
Job-CPYMXV : .NET Core 2.1.21 (CoreCLR 4.6.29130.01, CoreFX 4.6.29130.02), X64 RyuJIT |
|||
Job-BSGVGU : .NET Core 3.1.7 (CoreCLR 4.700.20.36602, CoreFX 4.700.20.37001), X64 RyuJIT |
|||
|
|||
IterationCount=3 LaunchCount=1 WarmupCount=3 |
|||
|
|||
| Method | Job | Runtime | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | |
|||
|---------------------------------- |----------- |-------------- |-----------:|----------:|----------:|------:|--------:|------:|------:|------:|----------:| |
|||
| StandardStreamRead | Job-OKZLUV | .NET 4.7.2 | 66.785 us | 15.768 us | 0.8643 us | 0.83 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamRead | Job-OKZLUV | .NET 4.7.2 | 97.389 us | 17.658 us | 0.9679 us | 1.21 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamChunkedRead | Job-OKZLUV | .NET 4.7.2 | 96.006 us | 16.286 us | 0.8927 us | 1.20 | 0.02 | - | - | - | - | |
|||
| BufferedReadStreamWrapRead | Job-OKZLUV | .NET 4.7.2 | 37.064 us | 14.640 us | 0.8024 us | 0.46 | 0.02 | - | - | - | - | |
|||
| StandardStreamReadByte | Job-OKZLUV | .NET 4.7.2 | 80.315 us | 26.676 us | 1.4622 us | 1.00 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamReadByte | Job-OKZLUV | .NET 4.7.2 | 118.706 us | 38.013 us | 2.0836 us | 1.48 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamChunkedReadByte | Job-OKZLUV | .NET 4.7.2 | 115.437 us | 33.352 us | 1.8282 us | 1.44 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamWrapReadByte | Job-OKZLUV | .NET 4.7.2 | 16.449 us | 11.400 us | 0.6249 us | 0.20 | 0.00 | - | - | - | - | |
|||
| ArrayReadByte | Job-OKZLUV | .NET 4.7.2 | 10.416 us | 1.866 us | 0.1023 us | 0.13 | 0.00 | - | - | - | - | |
|||
| | | | | | | | | | | | | |
|||
| StandardStreamRead | Job-CPYMXV | .NET Core 2.1 | 71.425 us | 50.441 us | 2.7648 us | 0.82 | 0.03 | - | - | - | - | |
|||
| BufferedReadStreamRead | Job-CPYMXV | .NET Core 2.1 | 32.816 us | 6.655 us | 0.3648 us | 0.38 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamChunkedRead | Job-CPYMXV | .NET Core 2.1 | 31.995 us | 7.751 us | 0.4249 us | 0.37 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamWrapRead | Job-CPYMXV | .NET Core 2.1 | 31.970 us | 4.170 us | 0.2286 us | 0.37 | 0.01 | - | - | - | - | |
|||
| StandardStreamReadByte | Job-CPYMXV | .NET Core 2.1 | 86.909 us | 18.565 us | 1.0176 us | 1.00 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamReadByte | Job-CPYMXV | .NET Core 2.1 | 14.596 us | 10.889 us | 0.5969 us | 0.17 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamChunkedReadByte | Job-CPYMXV | .NET Core 2.1 | 13.629 us | 1.569 us | 0.0860 us | 0.16 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamWrapReadByte | Job-CPYMXV | .NET Core 2.1 | 13.566 us | 1.743 us | 0.0956 us | 0.16 | 0.00 | - | - | - | - | |
|||
| ArrayReadByte | Job-CPYMXV | .NET Core 2.1 | 9.771 us | 6.658 us | 0.3650 us | 0.11 | 0.00 | - | - | - | - | |
|||
| | | | | | | | | | | | | |
|||
| StandardStreamRead | Job-BSGVGU | .NET Core 3.1 | 53.265 us | 65.819 us | 3.6078 us | 0.81 | 0.05 | - | - | - | - | |
|||
| BufferedReadStreamRead | Job-BSGVGU | .NET Core 3.1 | 33.163 us | 9.569 us | 0.5245 us | 0.51 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamChunkedRead | Job-BSGVGU | .NET Core 3.1 | 33.001 us | 6.114 us | 0.3351 us | 0.50 | 0.01 | - | - | - | - | |
|||
| BufferedReadStreamWrapRead | Job-BSGVGU | .NET Core 3.1 | 29.448 us | 7.120 us | 0.3902 us | 0.45 | 0.01 | - | - | - | - | |
|||
| StandardStreamReadByte | Job-BSGVGU | .NET Core 3.1 | 65.619 us | 6.732 us | 0.3690 us | 1.00 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamReadByte | Job-BSGVGU | .NET Core 3.1 | 13.989 us | 3.464 us | 0.1899 us | 0.21 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamChunkedReadByte | Job-BSGVGU | .NET Core 3.1 | 13.806 us | 1.710 us | 0.0938 us | 0.21 | 0.00 | - | - | - | - | |
|||
| BufferedReadStreamWrapReadByte | Job-BSGVGU | .NET Core 3.1 | 13.690 us | 1.523 us | 0.0835 us | 0.21 | 0.00 | - | - | - | - | |
|||
| ArrayReadByte | Job-BSGVGU | .NET Core 3.1 | 10.792 us | 8.228 us | 0.4510 us | 0.16 | 0.01 | - | - | - | - | |
|||
*/ |
|||
|
|||
@ -1,179 +1,177 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion |
|||
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; |
|||
|
|||
public class PixelConversion_Rgba32_To_Argb32 |
|||
{ |
|||
public class PixelConversion_Rgba32_To_Argb32 |
|||
{ |
|||
private Rgba32[] source; |
|||
private Rgba32[] source; |
|||
|
|||
private Argb32[] dest; |
|||
private Argb32[] dest; |
|||
|
|||
[Params(64)] |
|||
public int Count { get; set; } |
|||
[Params(64)] |
|||
public int Count { get; set; } |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new Rgba32[this.Count]; |
|||
this.dest = new Argb32[this.Count]; |
|||
} |
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.source = new Rgba32[this.Count]; |
|||
this.dest = new Argb32[this.Count]; |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void Default() |
|||
{ |
|||
ref Rgba32 sBase = ref this.source[0]; |
|||
ref Argb32 dBase = ref this.dest[0]; |
|||
|
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
Rgba32 s = Unsafe.Add(ref sBase, i); |
|||
Unsafe.Add(ref dBase, i).FromRgba32(s); |
|||
} |
|||
} |
|||
[Benchmark(Baseline = true)] |
|||
public void Default() |
|||
{ |
|||
ref Rgba32 sBase = ref this.source[0]; |
|||
ref Argb32 dBase = ref this.dest[0]; |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private static void Default_GenericImpl<TPixel>(ReadOnlySpan<Rgba32> source, Span<TPixel> dest) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); |
|||
ref TPixel dBase = ref MemoryMarshal.GetReference(dest); |
|||
|
|||
for (int i = 0; i < source.Length; i++) |
|||
{ |
|||
Rgba32 s = Unsafe.Add(ref sBase, i); |
|||
Unsafe.Add(ref dBase, i).FromRgba32(s); |
|||
} |
|||
Rgba32 s = Unsafe.Add(ref sBase, i); |
|||
Unsafe.Add(ref dBase, i).FromRgba32(s); |
|||
} |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.NoInlining)] |
|||
private static void Default_GenericImpl<TPixel>(ReadOnlySpan<Rgba32> source, Span<TPixel> dest) |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); |
|||
ref TPixel dBase = ref MemoryMarshal.GetReference(dest); |
|||
|
|||
[Benchmark] |
|||
public void Default_Generic() |
|||
for (int i = 0; i < source.Length; i++) |
|||
{ |
|||
Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); |
|||
Rgba32 s = Unsafe.Add(ref sBase, i); |
|||
Unsafe.Add(ref dBase, i).FromRgba32(s); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void Default_Generic() |
|||
{ |
|||
Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void Default_Group2() |
|||
{ |
|||
ref Rgba32 sBase = ref this.source[0]; |
|||
ref Argb32 dBase = ref this.dest[0]; |
|||
|
|||
[Benchmark] |
|||
public void Default_Group2() |
|||
for (int i = 0; i < this.Count; i += 2) |
|||
{ |
|||
ref Rgba32 sBase = ref this.source[0]; |
|||
ref Argb32 dBase = ref this.dest[0]; |
|||
|
|||
for (int i = 0; i < this.Count; i += 2) |
|||
{ |
|||
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); |
|||
Rgba32 s1 = Unsafe.Add(ref s0, 1); |
|||
|
|||
ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); |
|||
d0.FromRgba32(s0); |
|||
Unsafe.Add(ref d0, 1).FromRgba32(s1); |
|||
} |
|||
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); |
|||
Rgba32 s1 = Unsafe.Add(ref s0, 1); |
|||
|
|||
ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); |
|||
d0.FromRgba32(s0); |
|||
Unsafe.Add(ref d0, 1).FromRgba32(s1); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void Default_Group4() |
|||
{ |
|||
ref Rgba32 sBase = ref this.source[0]; |
|||
ref Argb32 dBase = ref this.dest[0]; |
|||
|
|||
[Benchmark] |
|||
public void Default_Group4() |
|||
for (int i = 0; i < this.Count; i += 4) |
|||
{ |
|||
ref Rgba32 sBase = ref this.source[0]; |
|||
ref Argb32 dBase = ref this.dest[0]; |
|||
|
|||
for (int i = 0; i < this.Count; i += 4) |
|||
{ |
|||
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); |
|||
ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); |
|||
ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); |
|||
Rgba32 s3 = Unsafe.Add(ref s2, 1); |
|||
|
|||
ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); |
|||
ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); |
|||
ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); |
|||
|
|||
d0.FromRgba32(s0); |
|||
d1.FromRgba32(s1); |
|||
d2.FromRgba32(s2); |
|||
Unsafe.Add(ref d2, 1).FromRgba32(s3); |
|||
} |
|||
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); |
|||
ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); |
|||
ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); |
|||
Rgba32 s3 = Unsafe.Add(ref s2, 1); |
|||
|
|||
ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); |
|||
ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); |
|||
ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); |
|||
|
|||
d0.FromRgba32(s0); |
|||
d1.FromRgba32(s1); |
|||
d2.FromRgba32(s2); |
|||
Unsafe.Add(ref d2, 1).FromRgba32(s3); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void BitOps() |
|||
{ |
|||
ref uint sBase = ref Unsafe.As<Rgba32, uint>(ref this.source[0]); |
|||
ref uint dBase = ref Unsafe.As<Argb32, uint>(ref this.dest[0]); |
|||
|
|||
[Benchmark] |
|||
public void BitOps() |
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
ref uint sBase = ref Unsafe.As<Rgba32, uint>(ref this.source[0]); |
|||
ref uint dBase = ref Unsafe.As<Argb32, uint>(ref this.dest[0]); |
|||
|
|||
for (int i = 0; i < this.Count; i++) |
|||
{ |
|||
uint s = Unsafe.Add(ref sBase, i); |
|||
Unsafe.Add(ref dBase, i) = FromRgba32.ToArgb32(s); |
|||
} |
|||
uint s = Unsafe.Add(ref sBase, i); |
|||
Unsafe.Add(ref dBase, i) = FromRgba32.ToArgb32(s); |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void BitOps_GroupAsULong() |
|||
{ |
|||
ref ulong sBase = ref Unsafe.As<Rgba32, ulong>(ref this.source[0]); |
|||
ref ulong dBase = ref Unsafe.As<Argb32, ulong>(ref this.dest[0]); |
|||
[Benchmark] |
|||
public void BitOps_GroupAsULong() |
|||
{ |
|||
ref ulong sBase = ref Unsafe.As<Rgba32, ulong>(ref this.source[0]); |
|||
ref ulong dBase = ref Unsafe.As<Argb32, ulong>(ref this.dest[0]); |
|||
|
|||
for (int i = 0; i < this.Count / 2; i++) |
|||
{ |
|||
ulong s = Unsafe.Add(ref sBase, i); |
|||
uint lo = (uint)s; |
|||
uint hi = (uint)(s >> 32); |
|||
lo = FromRgba32.ToArgb32(lo); |
|||
hi = FromRgba32.ToArgb32(hi); |
|||
for (int i = 0; i < this.Count / 2; i++) |
|||
{ |
|||
ulong s = Unsafe.Add(ref sBase, i); |
|||
uint lo = (uint)s; |
|||
uint hi = (uint)(s >> 32); |
|||
lo = FromRgba32.ToArgb32(lo); |
|||
hi = FromRgba32.ToArgb32(hi); |
|||
|
|||
s = (ulong)(hi << 32) | lo; |
|||
s = (ulong)(hi << 32) | lo; |
|||
|
|||
Unsafe.Add(ref dBase, i) = s; |
|||
} |
|||
Unsafe.Add(ref dBase, i) = s; |
|||
} |
|||
} |
|||
|
|||
public static class FromRgba32 |
|||
public static class FromRgba32 |
|||
{ |
|||
/// <summary>
|
|||
/// Converts a packed <see cref="Rgba32"/> to <see cref="Argb32"/>.
|
|||
/// </summary>
|
|||
/// <returns>The argb value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static uint ToArgb32(uint packedRgba) |
|||
{ |
|||
/// <summary>
|
|||
/// Converts a packed <see cref="Rgba32"/> to <see cref="Argb32"/>.
|
|||
/// </summary>
|
|||
/// <returns>The argb value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static uint ToArgb32(uint packedRgba) |
|||
{ |
|||
// packedRgba = [aa bb gg rr]
|
|||
// ROL(8, packedRgba) = [bb gg rr aa]
|
|||
return (packedRgba << 8) | (packedRgba >> 24); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a packed <see cref="Rgba32"/> to <see cref="Bgra32"/>.
|
|||
/// </summary>
|
|||
/// <returns>The bgra value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static uint ToBgra32(uint packedRgba) |
|||
{ |
|||
// packedRgba = [aa bb gg rr]
|
|||
// tmp1 = [aa 00 gg 00]
|
|||
// tmp2 = [00 bb 00 rr]
|
|||
// tmp3=ROL(16, tmp2) = [00 rr 00 bb]
|
|||
// tmp1 + tmp3 = [aa rr gg bb]
|
|||
uint tmp1 = packedRgba & 0xFF00FF00; |
|||
uint tmp2 = packedRgba & 0x00FF00FF; |
|||
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); |
|||
return tmp1 + tmp3; |
|||
} |
|||
// packedRgba = [aa bb gg rr]
|
|||
// ROL(8, packedRgba) = [bb gg rr aa]
|
|||
return (packedRgba << 8) | (packedRgba >> 24); |
|||
} |
|||
|
|||
// RESULTS:
|
|||
// Method | Count | Mean | Error | StdDev | Scaled |
|
|||
// -------------------- |------ |----------:|----------:|----------:|-------:|
|
|||
// Default | 64 | 107.33 ns | 1.0633 ns | 0.9426 ns | 1.00 |
|
|||
// Default_Generic | 64 | 111.15 ns | 0.3789 ns | 0.3544 ns | 1.04 |
|
|||
// Default_Group2 | 64 | 90.36 ns | 0.7779 ns | 0.6896 ns | 0.84 |
|
|||
// Default_Group4 | 64 | 82.39 ns | 0.2726 ns | 0.2550 ns | 0.77 |
|
|||
// BitOps | 64 | 39.25 ns | 0.3266 ns | 0.2895 ns | 0.37 |
|
|||
// BitOps_GroupAsULong | 64 | 41.80 ns | 0.2227 ns | 0.2083 ns | 0.39 |
|
|||
/// <summary>
|
|||
/// Converts a packed <see cref="Rgba32"/> to <see cref="Bgra32"/>.
|
|||
/// </summary>
|
|||
/// <returns>The bgra value.</returns>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static uint ToBgra32(uint packedRgba) |
|||
{ |
|||
// packedRgba = [aa bb gg rr]
|
|||
// tmp1 = [aa 00 gg 00]
|
|||
// tmp2 = [00 bb 00 rr]
|
|||
// tmp3=ROL(16, tmp2) = [00 rr 00 bb]
|
|||
// tmp1 + tmp3 = [aa rr gg bb]
|
|||
uint tmp1 = packedRgba & 0xFF00FF00; |
|||
uint tmp2 = packedRgba & 0x00FF00FF; |
|||
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); |
|||
return tmp1 + tmp3; |
|||
} |
|||
} |
|||
|
|||
// RESULTS:
|
|||
// Method | Count | Mean | Error | StdDev | Scaled |
|
|||
// -------------------- |------ |----------:|----------:|----------:|-------:|
|
|||
// Default | 64 | 107.33 ns | 1.0633 ns | 0.9426 ns | 1.00 |
|
|||
// Default_Generic | 64 | 111.15 ns | 0.3789 ns | 0.3544 ns | 1.04 |
|
|||
// Default_Group2 | 64 | 90.36 ns | 0.7779 ns | 0.6896 ns | 0.84 |
|
|||
// Default_Group4 | 64 | 82.39 ns | 0.2726 ns | 0.2550 ns | 0.77 |
|
|||
// BitOps | 64 | 39.25 ns | 0.3266 ns | 0.2895 ns | 0.37 |
|
|||
// BitOps_GroupAsULong | 64 | 41.80 ns | 0.2227 ns | 0.2083 ns | 0.39 |
|
|||
} |
|||
|
|||
@ -1,62 +1,60 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
namespace SixLabors.ImageSharp.Benchmarks.General |
|||
namespace SixLabors.ImageSharp.Benchmarks.General; |
|||
|
|||
/// <summary>
|
|||
/// Has it any effect on performance to store SIMD constants as static readonly fields? Is it OK to always inline them?
|
|||
/// Spoiler: the difference seems to be statistically insignificant!
|
|||
/// </summary>
|
|||
public class Vector4Constants |
|||
{ |
|||
/// <summary>
|
|||
/// Has it any effect on performance to store SIMD constants as static readonly fields? Is it OK to always inline them?
|
|||
/// Spoiler: the difference seems to be statistically insignificant!
|
|||
/// </summary>
|
|||
public class Vector4Constants |
|||
private static readonly Vector4 A = new Vector4(1.2f); |
|||
private static readonly Vector4 B = new Vector4(3.4f); |
|||
private static readonly Vector4 C = new Vector4(5.6f); |
|||
private static readonly Vector4 D = new Vector4(7.8f); |
|||
|
|||
private Random random; |
|||
|
|||
private Vector4 parameter; |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
private static readonly Vector4 A = new Vector4(1.2f); |
|||
private static readonly Vector4 B = new Vector4(3.4f); |
|||
private static readonly Vector4 C = new Vector4(5.6f); |
|||
private static readonly Vector4 D = new Vector4(7.8f); |
|||
|
|||
private Random random; |
|||
|
|||
private Vector4 parameter; |
|||
|
|||
[GlobalSetup] |
|||
public void Setup() |
|||
{ |
|||
this.random = new Random(42); |
|||
this.parameter = new Vector4( |
|||
this.GetRandomFloat(), |
|||
this.GetRandomFloat(), |
|||
this.GetRandomFloat(), |
|||
this.GetRandomFloat()); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public Vector4 Static() |
|||
{ |
|||
Vector4 p = this.parameter; |
|||
|
|||
Vector4 x = (p * A / B) + (p * C / D); |
|||
Vector4 y = (p / A * B) + (p / C * D); |
|||
var z = Vector4.Min(p, A); |
|||
var w = Vector4.Max(p, B); |
|||
return x + y + z + w; |
|||
} |
|||
|
|||
[Benchmark] |
|||
public Vector4 Inlined() |
|||
{ |
|||
Vector4 p = this.parameter; |
|||
|
|||
Vector4 x = (p * new Vector4(1.2f) / new Vector4(2.3f)) + (p * new Vector4(4.5f) / new Vector4(6.7f)); |
|||
Vector4 y = (p / new Vector4(1.2f) * new Vector4(2.3f)) + (p / new Vector4(4.5f) * new Vector4(6.7f)); |
|||
var z = Vector4.Min(p, new Vector4(1.2f)); |
|||
var w = Vector4.Max(p, new Vector4(2.3f)); |
|||
return x + y + z + w; |
|||
} |
|||
|
|||
private float GetRandomFloat() => (float)this.random.NextDouble(); |
|||
this.random = new Random(42); |
|||
this.parameter = new Vector4( |
|||
this.GetRandomFloat(), |
|||
this.GetRandomFloat(), |
|||
this.GetRandomFloat(), |
|||
this.GetRandomFloat()); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public Vector4 Static() |
|||
{ |
|||
Vector4 p = this.parameter; |
|||
|
|||
Vector4 x = (p * A / B) + (p * C / D); |
|||
Vector4 y = (p / A * B) + (p / C * D); |
|||
var z = Vector4.Min(p, A); |
|||
var w = Vector4.Max(p, B); |
|||
return x + y + z + w; |
|||
} |
|||
|
|||
[Benchmark] |
|||
public Vector4 Inlined() |
|||
{ |
|||
Vector4 p = this.parameter; |
|||
|
|||
Vector4 x = (p * new Vector4(1.2f) / new Vector4(2.3f)) + (p * new Vector4(4.5f) / new Vector4(6.7f)); |
|||
Vector4 y = (p / new Vector4(1.2f) * new Vector4(2.3f)) + (p / new Vector4(4.5f) * new Vector4(6.7f)); |
|||
var z = Vector4.Min(p, new Vector4(1.2f)); |
|||
var w = Vector4.Max(p, new Vector4(2.3f)); |
|||
return x + y + z + w; |
|||
} |
|||
|
|||
private float GetRandomFloat() => (float)this.random.NextDouble(); |
|||
} |
|||
|
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue