Browse Source

benchmarks

pull/126/head
Anton Firszov 9 years ago
parent
commit
79537eb16e
  1. 5
      src/ImageSharp/Common/Memory/BufferPointer{T}.cs
  2. 1
      src/ImageSharp/project.json
  3. 63
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
  4. 129
      tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs
  5. 61
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  6. 70
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
  7. 23
      tests/ImageSharp.Benchmarks/Image/EncodePng.cs
  8. 7
      tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj
  9. 4
      tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs

5
src/ImageSharp/Common/Memory/BufferPointer{T}.cs

@ -63,6 +63,11 @@ namespace ImageSharp
/// </summary>
public int Offset { get; private set; }
/// <summary>
/// Gets the offset inside <see cref="Array"/> in bytes.
/// </summary>
public int ByteOffset => this.Offset * Unsafe.SizeOf<T>();
/// <summary>
/// Gets the pointer to the offseted array position
/// </summary>

1
src/ImageSharp/project.json

@ -98,6 +98,7 @@
},
"net461": {
"dependencies": {
"System.Numerics.Vectors": "4.1.1",
"System.Threading.Tasks.Parallel": "4.0.0"
},
"frameworkAssemblies": {

63
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs

@ -0,0 +1,63 @@
// ReSharper disable InconsistentNaming
namespace ImageSharp.Benchmarks.Color.Bulk
{
using BenchmarkDotNet.Attributes;
using Color = ImageSharp.Color;
public abstract class PackFromXyzw<TColor>
where TColor : struct, IPixel<TColor>
{
private PinnedBuffer<TColor> destination;
private PinnedBuffer<byte> source;
[Params(16, 128, 1024)]
public int Count { get; set; }
[Setup]
public void Setup()
{
this.destination = new PinnedBuffer<TColor>(this.Count);
this.source = new PinnedBuffer<byte>(this.Count * 4);
}
[Cleanup]
public void Cleanup()
{
this.destination.Dispose();
this.source.Dispose();
}
[Benchmark(Baseline = true)]
public void PerElement()
{
byte[] s = this.source.Array;
TColor[] d = this.destination.Array;
for (int i = 0; i < this.Count; i++)
{
int i4 = i * 4;
TColor c = default(TColor);
c.PackFromBytes(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3]);
d[i] = c;
}
}
[Benchmark]
public void CommonBulk()
{
new BulkPixelOperations<TColor>().PackFromXyzwBytes(this.source, this.destination, this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
BulkPixelOperations<TColor>.Instance.PackFromXyzwBytes(this.source, this.destination, this.Count);
}
}
public class PackFromXyzw_Color : PackFromXyzw<Color>
{
}
}

129
tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs

@ -1,129 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ImageSharp.Benchmarks.Color.Bulk
{
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using Color = ImageSharp.Color;
/// <summary>
/// Benchmark to measure the effect of using virtual bulk-copy calls inside PixelAccessor methods
/// </summary>
public unsafe class PixelAccessorVirtualCopy
{
abstract class CopyExecutor
{
internal abstract void VirtualCopy(BufferPointer<Color> destination, BufferPointer<byte> source, int count);
}
class UnsafeCopyExecutor : CopyExecutor
{
[MethodImpl(MethodImplOptions.NoInlining)]
internal override unsafe void VirtualCopy(BufferPointer<Color> destination, BufferPointer<byte> source, int count)
{
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)count*4);
}
}
private PixelAccessor<Color> pixelAccessor;
private PixelArea<Color> area;
private CopyExecutor executor;
[Params(64, 256, 512)]
public int Width { get; set; }
public int Height { get; set; } = 256;
[Setup]
public void Setup()
{
this.pixelAccessor = new PixelAccessor<ImageSharp.Color>(this.Width, this.Height);
this.area = new PixelArea<Color>(this.Width / 2, this.Height, ComponentOrder.Xyzw);
this.executor = new UnsafeCopyExecutor();
}
[Cleanup]
public void Cleanup()
{
this.pixelAccessor.Dispose();
this.area.Dispose();
}
[Benchmark(Baseline = true)]
public void CopyRawUnsafeInlined()
{
uint byteCount = (uint)this.area.Width * 4;
int targetX = this.Width / 4;
int targetY = 0;
for (int y = 0; y < this.Height; y++)
{
byte* source = this.area.PixelBase + (y * this.area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y);
Unsafe.CopyBlock(destination, source, byteCount);
}
}
[Benchmark]
public void CopyBufferPointerUnsafeInlined()
{
uint byteCount = (uint)this.area.Width * 4;
int targetX = this.Width / 4;
int targetY = 0;
for (int y = 0; y < this.Height; y++)
{
BufferPointer<byte> source = this.GetAreaRow(y);
BufferPointer<Color> destination = this.GetPixelAccessorRow(targetX, targetY + y);
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount);
}
}
[Benchmark]
public void CopyBufferPointerUnsafeVirtual()
{
int targetX = this.Width / 4;
int targetY = 0;
for (int y = 0; y < this.Height; y++)
{
BufferPointer<byte> source = this.GetAreaRow(y);
BufferPointer<Color> destination = this.GetPixelAccessorRow(targetX, targetY + y);
this.executor.VirtualCopy(destination, source, this.area.Width);
}
}
private byte* GetRowPointer(int x, int y)
{
return (byte*)this.pixelAccessor.DataPointer + (((y * this.pixelAccessor.Width) + x) * Unsafe.SizeOf<Color>());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private BufferPointer<Color> GetPixelAccessorRow(int x, int y)
{
return new BufferPointer<ImageSharp.Color>(
this.pixelAccessor.PixelArray,
(void*)this.pixelAccessor.DataPointer,
(y * this.pixelAccessor.Width) + x
);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private BufferPointer<byte> GetAreaRow(int y)
{
return new BufferPointer<byte>(this.area.Bytes, this.area.PixelBase, y * this.area.RowStride);
}
}
}

61
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs

@ -0,0 +1,61 @@
// ReSharper disable InconsistentNaming
namespace ImageSharp.Benchmarks.Color.Bulk
{
using BenchmarkDotNet.Attributes;
using Color = ImageSharp.Color;
public abstract class ToXyz<TColor>
where TColor : struct, IPixel<TColor>
{
private PinnedBuffer<TColor> source;
private PinnedBuffer<byte> destination;
[Params(16, 128, 1024)]
public int Count { get; set; }
[Setup]
public void Setup()
{
this.source = new PinnedBuffer<TColor>(this.Count);
this.destination = new PinnedBuffer<byte>(this.Count * 3);
}
[Cleanup]
public void Cleanup()
{
this.source.Dispose();
this.destination.Dispose();
}
[Benchmark(Baseline = true)]
public void PerElement()
{
TColor[] s = this.source.Array;
byte[] d = this.destination.Array;
for (int i = 0; i < this.Count; i++)
{
TColor c = s[i];
c.ToXyzBytes(d, i * 4);
}
}
[Benchmark]
public void CommonBulk()
{
new BulkPixelOperations<TColor>().ToXyzBytes(this.source, this.destination, this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
BulkPixelOperations<TColor>.Instance.ToXyzBytes(this.source, this.destination, this.Count);
}
}
public class ToXyz_Color : ToXyz<Color>
{
}
}

70
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
// ReSharper disable InconsistentNaming
namespace ImageSharp.Benchmarks.Color.Bulk
{
using BenchmarkDotNet.Attributes;
using Color = ImageSharp.Color;
public abstract class ToXyzw<TColor>
where TColor : struct, IPixel<TColor>
{
private PinnedBuffer<TColor> source;
private PinnedBuffer<byte> destination;
[Params(16, 128, 1024)]
public int Count { get; set; }
[Setup]
public void Setup()
{
this.source = new PinnedBuffer<TColor>(this.Count);
this.destination = new PinnedBuffer<byte>(this.Count * 4);
}
[Cleanup]
public void Cleanup()
{
this.source.Dispose();
this.destination.Dispose();
}
[Benchmark(Baseline = true)]
public void PerElement()
{
TColor[] s = this.source.Array;
byte[] d = this.destination.Array;
for (int i = 0; i < this.Count; i++)
{
TColor c = s[i];
c.ToXyzwBytes(d, i * 4);
}
}
[Benchmark]
public void CommonBulk()
{
new BulkPixelOperations<TColor>().ToXyzwBytes(this.source, this.destination, this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
BulkPixelOperations<TColor>.Instance.ToXyzwBytes(this.source, this.destination, this.Count);
}
}
public class ToXyzw_Color : ToXyzw<Color>
{
}
public class ToXyzw_Argb : ToXyzw<Argb>
{
}
}

23
tests/ImageSharp.Benchmarks/Image/EncodePng.cs

@ -10,6 +10,10 @@ namespace ImageSharp.Benchmarks.Image
using System.IO;
using BenchmarkDotNet.Attributes;
using ImageSharp.Formats;
using ImageSharp.Quantizers;
using CoreImage = ImageSharp.Image;
public class EncodePng : BenchmarkBase
@ -19,12 +23,21 @@ namespace ImageSharp.Benchmarks.Image
private Image bmpDrawing;
private CoreImage bmpCore;
[Params(false, true)]
public bool LargeImage { get; set; }
[Params(false, true)]
public bool UseOctreeQuantizer { get; set; }
[Setup]
public void ReadImages()
{
if (this.bmpStream == null)
{
this.bmpStream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp");
string path = this.LargeImage
? "../ImageSharp.Tests/TestImages/Formats/Jpg/baseline/jpeg420exif.jpg"
: "../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp";
this.bmpStream = File.OpenRead(path);
this.bmpCore = new CoreImage(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream);
@ -53,7 +66,13 @@ namespace ImageSharp.Benchmarks.Image
{
using (MemoryStream memoryStream = new MemoryStream())
{
this.bmpCore.SaveAsPng(memoryStream);
Quantizer<ImageSharp.Color> quantizer = this.UseOctreeQuantizer
? (Quantizer<ImageSharp.Color>)
new OctreeQuantizer<ImageSharp.Color>()
: new PaletteQuantizer<ImageSharp.Color>();
PngEncoderOptions options = new PngEncoderOptions() { Quantizer = quantizer };
this.bmpCore.SaveAsPng(memoryStream, options);
}
}
}

7
tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj

@ -206,9 +206,6 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="..\ImageSharp.Benchmarks\Color\Bulk\PixelAccessorVirtualCopy.cs">
<Link>Benchmarks\PixelAccessorVirtualCopy.cs</Link>
</Compile>
<Compile Include="..\ImageSharp.Tests\Colors\BulkPixelOperationsTests.cs">
<Link>Tests\Colors\BulkPixelOperationsTests.cs</Link>
</Compile>
@ -346,7 +343,9 @@
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="Benchmarks\" />
</ItemGroup>
<ItemGroup>
<Analyzer Include="..\..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
<Analyzer Include="..\..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />

4
tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs

@ -10,7 +10,7 @@
public class Color : BulkPixelOperationsTests<ImageSharp.Color>
{
// For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class:
public static TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
[Fact]
public void IsSpecialImplementation()
@ -35,7 +35,7 @@
public class Argb : BulkPixelOperationsTests<ImageSharp.Argb>
{
// For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class:
public static TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
}
[Theory]

Loading…
Cancel
Save