mirror of https://github.com/SixLabors/ImageSharp
3 changed files with 204 additions and 9 deletions
@ -0,0 +1,156 @@ |
|||||
|
namespace ImageSharp.Benchmarks.General |
||||
|
{ |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
using BenchmarkDotNet.Attributes; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer?
|
||||
|
/// 1. Rgba32 ToRgba32();
|
||||
|
/// OR
|
||||
|
/// 2. void CopyToRgba32(ref Rgba32 dest);
|
||||
|
/// ?
|
||||
|
/// </summary>
|
||||
|
public class PixelConversion |
||||
|
{ |
||||
|
interface ITestPixel<T> |
||||
|
where T : struct, ITestPixel<T> |
||||
|
{ |
||||
|
Rgba32 ToRgba32(); |
||||
|
|
||||
|
void CopyToRgba32(ref Rgba32 dest); |
||||
|
} |
||||
|
|
||||
|
[StructLayout(LayoutKind.Sequential)] |
||||
|
struct TestArgb : ITestPixel<TestArgb> |
||||
|
{ |
||||
|
private byte a, r, g, b; |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public Rgba32 ToRgba32() |
||||
|
{ |
||||
|
return new Rgba32(this.r, this.g, this.b, this.a); |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public void CopyToRgba32(ref Rgba32 dest) |
||||
|
{ |
||||
|
dest.R = this.r; |
||||
|
dest.G = this.g; |
||||
|
dest.B = this.b; |
||||
|
dest.A = this.a; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[StructLayout(LayoutKind.Sequential)] |
||||
|
struct TestRgba : ITestPixel<TestRgba> |
||||
|
{ |
||||
|
private byte r, g, b, a; |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public Rgba32 ToRgba32() |
||||
|
{ |
||||
|
return Unsafe.As<TestRgba, Rgba32>(ref this); |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public void CopyToRgba32(ref Rgba32 dest) |
||||
|
{ |
||||
|
dest = Unsafe.As<TestRgba, Rgba32>(ref this); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
struct ConversionRunner<T> |
||||
|
where T : struct, ITestPixel<T> |
||||
|
{ |
||||
|
private T[] source; |
||||
|
|
||||
|
private Rgba32[] dest; |
||||
|
|
||||
|
public ConversionRunner(int count) |
||||
|
{ |
||||
|
this.source = new T[count]; |
||||
|
this.dest = new Rgba32[count]; |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public void RunRetvalConversion() |
||||
|
{ |
||||
|
int count = this.source.Length; |
||||
|
|
||||
|
ref T sourceBaseRef = ref this.source[0]; |
||||
|
ref Rgba32 destBaseRef = ref this.dest[0]; |
||||
|
|
||||
|
for (int i = 0; i < count; i++) |
||||
|
{ |
||||
|
Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToRgba32(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
||||
|
public void RunCopyToConversion() |
||||
|
{ |
||||
|
int count = this.source.Length; |
||||
|
|
||||
|
ref T sourceBaseRef = ref this.source[0]; |
||||
|
ref Rgba32 destBaseRef = ref this.dest[0]; |
||||
|
|
||||
|
for (int i = 0; i < count; i++) |
||||
|
{ |
||||
|
Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref Unsafe.Add(ref destBaseRef, i)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private ConversionRunner<TestRgba> inOrderRunner; |
||||
|
|
||||
|
private ConversionRunner<TestArgb> permutedRunner; |
||||
|
|
||||
|
[Params(128)] |
||||
|
public int Count { get; set; } |
||||
|
|
||||
|
[Setup] |
||||
|
public void Setup() |
||||
|
{ |
||||
|
this.inOrderRunner = new ConversionRunner<TestRgba>(this.Count); |
||||
|
this.permutedRunner = new ConversionRunner<TestArgb>(this.Count); |
||||
|
} |
||||
|
|
||||
|
[Benchmark(Baseline = true)] |
||||
|
public void InOrderRetval() |
||||
|
{ |
||||
|
this.inOrderRunner.RunRetvalConversion(); |
||||
|
} |
||||
|
|
||||
|
[Benchmark] |
||||
|
public void InOrderCopyTo() |
||||
|
{ |
||||
|
this.inOrderRunner.RunCopyToConversion(); |
||||
|
} |
||||
|
|
||||
|
[Benchmark] |
||||
|
public void PermutedRetval() |
||||
|
{ |
||||
|
this.permutedRunner.RunRetvalConversion(); |
||||
|
} |
||||
|
|
||||
|
[Benchmark] |
||||
|
public void PermutedCopyTo() |
||||
|
{ |
||||
|
this.permutedRunner.RunCopyToConversion(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Results: |
||||
|
* |
||||
|
* Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | |
||||
|
* --------------- |------ |------------ |---------- |------- |-------------- | |
||||
|
* InOrderRetval | 128 | 89.7358 ns | 2.2389 ns | 1.00 | 0.00 | |
||||
|
* InOrderCopyTo | 128 | 89.4112 ns | 2.2901 ns | 1.00 | 0.03 | |
||||
|
* PermutedRetval | 128 | 845.4038 ns | 5.6154 ns | 9.43 | 0.23 | |
||||
|
* PermutedCopyTo | 128 | 155.6004 ns | 3.8870 ns | 1.73 | 0.06 | |
||||
|
* |
||||
|
*/ |
||||
|
} |
||||
Loading…
Reference in new issue