mirror of https://github.com/SixLabors/ImageSharp
4 changed files with 335 additions and 0 deletions
@ -0,0 +1,74 @@ |
|||
namespace ImageSharp.Benchmarks |
|||
{ |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using ImageSharp; |
|||
|
|||
/// <summary>
|
|||
/// Compares two implementation candidates for general BulkPixelOperations.ToVector4():
|
|||
/// - One iterating with pointers
|
|||
/// - One iterating with ref locals
|
|||
/// </summary>
|
|||
public unsafe class PackFromVector4ReferenceVsPointer |
|||
{ |
|||
private PinnedBuffer<ImageSharp.Color> destination; |
|||
|
|||
private PinnedBuffer<Vector4> source; |
|||
|
|||
[Params(16, 128, 1024)] |
|||
public int Count { get; set; } |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.destination = new PinnedBuffer<ImageSharp.Color>(this.Count); |
|||
this.source = new PinnedBuffer<Vector4>(this.Count * 4); |
|||
} |
|||
|
|||
[Cleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.source.Dispose(); |
|||
this.destination.Dispose(); |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public void PackUsingPointers() |
|||
{ |
|||
Vector4* sp = (Vector4*)this.source.Pointer; |
|||
byte* dp = (byte*)this.destination.Pointer; |
|||
int count = this.Count; |
|||
int size = sizeof(ImageSharp.Color); |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
Vector4 v = Unsafe.Read<Vector4>(sp); |
|||
ImageSharp.Color c = default(ImageSharp.Color); |
|||
c.PackFromVector4(v); |
|||
Unsafe.Write(dp, c); |
|||
|
|||
sp++; |
|||
dp += size; |
|||
} |
|||
} |
|||
|
|||
[Benchmark] |
|||
public void PackUsingReferences() |
|||
{ |
|||
ref Vector4 sp = ref this.source.Array[0]; |
|||
ref ImageSharp.Color dp = ref this.destination.Array[0]; |
|||
int count = this.Count; |
|||
|
|||
for (int i = 0; i < count; i++) |
|||
{ |
|||
dp.PackFromVector4(sp); |
|||
|
|||
sp = Unsafe.Add(ref sp, 1); |
|||
dp = Unsafe.Add(ref dp, 1); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,238 @@ |
|||
namespace ImageSharp.Benchmarks.General |
|||
{ |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
public abstract unsafe class PixelIndexing |
|||
{ |
|||
/// <summary>
|
|||
/// https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/Pinnable.cs
|
|||
/// </summary>
|
|||
protected class Pinnable<T> |
|||
{ |
|||
public T Data; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The indexer methods are encapsulated into a struct to make sure everything is inlined.
|
|||
/// </summary>
|
|||
internal struct Data |
|||
{ |
|||
private Vector4* pointer; |
|||
|
|||
private Pinnable<Vector4> pinnable; |
|||
|
|||
private int width; |
|||
|
|||
public Data(PinnedImageBuffer<Vector4> buffer) |
|||
{ |
|||
this.pointer = (Vector4*)buffer.Pointer; |
|||
this.pinnable = Unsafe.As<Pinnable<Vector4>>(buffer.Array); |
|||
this.width = buffer.Width; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 GetPointersBasicImpl(int x, int y) |
|||
{ |
|||
return this.pointer[y * this.width + x]; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 GetPointersSrcsUnsafeImpl(int x, int y) |
|||
{ |
|||
return Unsafe.Read<Vector4>((byte*)this.pointer + (((y * this.width) + x) * Unsafe.SizeOf<Vector4>())); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Vector4 GetReferencesImpl(int x, int y) |
|||
{ |
|||
int elementOffset = (y * this.width) + x; |
|||
return Unsafe.Add(ref this.pinnable.Data, elementOffset); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public ref Vector4 GetReferencesRefReturnsImpl(int x, int y) |
|||
{ |
|||
int elementOffset = (y * this.width) + x; |
|||
return ref Unsafe.Add(ref this.pinnable.Data, elementOffset); |
|||
} |
|||
|
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void IndexWithPointersBasicImpl(int x, int y, Vector4 v) |
|||
{ |
|||
this.pointer[y * this.width + x] = v; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void IndexWithPointersSrcsUnsafeImpl(int x, int y, Vector4 v) |
|||
{ |
|||
Unsafe.Write((byte*)this.pointer + (((y * this.width) + x) * Unsafe.SizeOf<Vector4>()), v); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public void IndexWithReferencesImpl(int x, int y, Vector4 v) |
|||
{ |
|||
int elementOffset = (y * this.width) + x; |
|||
Unsafe.Add(ref this.pinnable.Data, elementOffset) = v; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public ref Vector4 IndexWithReferencesRefReturnImpl(int x, int y) |
|||
{ |
|||
int elementOffset = (y * this.width) + x; |
|||
return ref Unsafe.Add(ref this.pinnable.Data, elementOffset); |
|||
} |
|||
} |
|||
|
|||
internal PinnedImageBuffer<Vector4> buffer; |
|||
|
|||
protected int width; |
|||
|
|||
protected int startIndex; |
|||
|
|||
protected int endIndex; |
|||
|
|||
protected Vector4* pointer; |
|||
|
|||
protected Vector4[] array; |
|||
|
|||
protected Pinnable<Vector4> pinnable; |
|||
|
|||
[Params(64, 256, 1024)] |
|||
public int Count { get; set; } |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
this.width = 2048; |
|||
this.buffer = new PinnedImageBuffer<Vector4>(2048, 2048); |
|||
this.pointer = (Vector4*)this.buffer.Pointer; |
|||
this.array = this.buffer.Array; |
|||
this.pinnable = Unsafe.As<Pinnable<Vector4>>(this.array); |
|||
|
|||
this.startIndex = 2048 / 2 - (this.Count / 2); |
|||
this.endIndex = 2048 / 2 + (this.Count / 2); |
|||
} |
|||
|
|||
[Cleanup] |
|||
public void Cleanup() |
|||
{ |
|||
this.buffer.Dispose(); |
|||
} |
|||
|
|||
} |
|||
|
|||
public unsafe class PixelIndexingGetter : PixelIndexing |
|||
{ |
|||
[Benchmark(Description = "Index.Get: Pointers+arithmetics", Baseline = true)] |
|||
public Vector4 IndexWithPointersBasic() |
|||
{ |
|||
Vector4 sum = Vector4.Zero; |
|||
Data data = new Data(this.buffer); |
|||
|
|||
for (int i = this.startIndex; i < this.endIndex; i++) |
|||
{ |
|||
sum += data.GetPointersBasicImpl(i, i); |
|||
} |
|||
|
|||
return sum; |
|||
} |
|||
|
|||
[Benchmark(Description = "Index.Get: Pointers+SRCS.Unsafe")] |
|||
public Vector4 IndexWithPointersSrcsUnsafe() |
|||
{ |
|||
Vector4 sum = Vector4.Zero; |
|||
Data data = new Data(this.buffer); |
|||
|
|||
for (int i = this.startIndex; i < this.endIndex; i++) |
|||
{ |
|||
sum += data.GetPointersSrcsUnsafeImpl(i, i); |
|||
} |
|||
|
|||
return sum; |
|||
} |
|||
|
|||
[Benchmark(Description = "Index.Get: References")] |
|||
public Vector4 IndexWithReferences() |
|||
{ |
|||
Vector4 sum = Vector4.Zero; |
|||
Data data = new Data(this.buffer); |
|||
|
|||
for (int i = this.startIndex; i < this.endIndex; i++) |
|||
{ |
|||
sum += data.GetReferencesImpl(i, i); |
|||
} |
|||
|
|||
return sum; |
|||
} |
|||
|
|||
[Benchmark(Description = "Index.Get: References+refreturns")] |
|||
public Vector4 IndexWithReferencesRefReturns() |
|||
{ |
|||
Vector4 sum = Vector4.Zero; |
|||
Data data = new Data(this.buffer); |
|||
|
|||
for (int i = this.startIndex; i < this.endIndex; i++) |
|||
{ |
|||
sum += data.GetReferencesRefReturnsImpl(i, i); |
|||
} |
|||
|
|||
return sum; |
|||
} |
|||
} |
|||
|
|||
public unsafe class PixelIndexingSetter : PixelIndexing |
|||
{ |
|||
[Benchmark(Description = "Index.Set: Pointers+arithmetics", Baseline = true)] |
|||
public void IndexWithPointersBasic() |
|||
{ |
|||
Vector4 v = new Vector4(1, 2, 3, 4); |
|||
Data data = new Data(this.buffer); |
|||
|
|||
for (int i = this.startIndex; i < this.endIndex; i++) |
|||
{ |
|||
data.IndexWithPointersBasicImpl(i, i, v); |
|||
} |
|||
} |
|||
|
|||
[Benchmark(Description = "Index.Set: Pointers+SRCS.Unsafe")] |
|||
public void IndexWithPointersSrcsUnsafe() |
|||
{ |
|||
Vector4 v = new Vector4(1, 2, 3, 4); |
|||
Data data = new Data(this.buffer); |
|||
|
|||
for (int i = this.startIndex; i < this.endIndex; i++) |
|||
{ |
|||
data.IndexWithPointersSrcsUnsafeImpl(i, i, v); |
|||
} |
|||
} |
|||
|
|||
[Benchmark(Description = "Index.Set: References")] |
|||
public void IndexWithReferencesBasic() |
|||
{ |
|||
Vector4 v = new Vector4(1, 2, 3, 4); |
|||
Data data = new Data(this.buffer); |
|||
|
|||
for (int i = this.startIndex; i < this.endIndex; i++) |
|||
{ |
|||
data.IndexWithReferencesImpl(i, i, v); |
|||
} |
|||
} |
|||
|
|||
[Benchmark(Description = "Index.Set: References+refreturn")] |
|||
public void IndexWithReferencesRefReturn() |
|||
{ |
|||
Vector4 v = new Vector4(1, 2, 3, 4); |
|||
Data data = new Data(this.buffer); |
|||
|
|||
for (int i = this.startIndex; i < this.endIndex; i++) |
|||
{ |
|||
data.IndexWithReferencesRefReturnImpl(i, i) = v; |
|||
} |
|||
} |
|||
|
|||
} |
|||
} |
|||
Loading…
Reference in new issue