Browse Source

benchmarking benchmarking benchmarking

pull/34/head
Anton Firszov 10 years ago
parent
commit
57cc5c5f30
  1. 79
      src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs
  2. 259
      tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs

79
src/ImageSharp46/Formats/Jpg/Components/Block8x8.cs

@ -1,6 +1,8 @@
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace ImageSharp.Formats namespace ImageSharp.Formats
@ -35,30 +37,47 @@ namespace ImageSharp.Formats
public const int VectorCount = 16; public const int VectorCount = 16;
public const int ScalarCount = VectorCount * 4; public const int ScalarCount = VectorCount * 4;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void LoadFrom(Span<float> source) public unsafe void LoadFrom(Span<float> source)
{ {
fixed (Vector4* ptr = &V0L) fixed (Vector4* ptr = &V0L)
{ {
float* fp = (float*)ptr; Marshal.Copy(source.Data, source.Offset, (IntPtr)ptr, ScalarCount);
for (int i = 0; i < ScalarCount; i++) //float* fp = (float*)ptr;
{ //for (int i = 0; i < ScalarCount; i++)
fp[i] = source[i]; //{
} // fp[i] = source[i];
//}
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void CopyTo(Span<float> dest) public unsafe void CopyTo(Span<float> dest)
{ {
fixed (Vector4* ptr = &V0L) fixed (Vector4* ptr = &V0L)
{ {
float* fp = (float*)ptr; Marshal.Copy((IntPtr)ptr, dest.Data, dest.Offset, ScalarCount);
for (int i = 0; i < ScalarCount; i++) //float* fp = (float*)ptr;
{ //for (int i = 0; i < ScalarCount; i++)
dest[i] = fp[i]; //{
} // dest[i] = fp[i];
//}
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void LoadFrom(Block8x8* blockPtr, Span<float> source)
{
Marshal.Copy(source.Data, source.Offset, (IntPtr)blockPtr, ScalarCount);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void CopyTo(Block8x8* blockPtr, Span<float> dest)
{
Marshal.Copy((IntPtr)blockPtr, dest.Data, dest.Offset, ScalarCount);
}
internal unsafe void LoadFrom(Span<int> source) internal unsafe void LoadFrom(Span<int> source)
{ {
fixed (Vector4* ptr = &V0L) fixed (Vector4* ptr = &V0L)
@ -104,7 +123,7 @@ namespace ImageSharp.Formats
} }
/// <summary> /// <summary>
/// Used as a reference implementation for benchmarking /// Reference implementation we can benchmark against
/// </summary> /// </summary>
internal unsafe void TransposeInto_PinningImpl(ref Block8x8 destination) internal unsafe void TransposeInto_PinningImpl(ref Block8x8 destination)
{ {
@ -145,9 +164,7 @@ namespace ImageSharp.Formats
} }
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyAllInplace(Vector4 s) public void MultiplyAllInplace(Vector4 s)
{ {
@ -411,5 +428,41 @@ namespace ImageSharp.Formats
source.IDCTInto(ref dest, ref temp); source.IDCTInto(ref dest, ref temp);
dest.CopyTo(block.Data); dest.CopyTo(block.Data);
} }
public unsafe float this[int idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
fixed (Block8x8* p = &this)
{
float* fp = (float*) p;
return fp[idx];
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
fixed (Block8x8* p = &this)
{
float* fp = (float*)p;
fp[idx] = value;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe float GetScalarAt(Block8x8* blockPtr, int idx)
{
float* fp = (float*) blockPtr;
return fp[idx];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe void SetScalarAt(Block8x8* blockPtr, int idx, float value)
{
float* fp = (float*)blockPtr;
fp[idx] = value;
}
} }
} }

259
tests/ImageSharp.Tests46/Formats/Jpg/Block8x8Tests.cs

@ -1,7 +1,11 @@
using System; // Uncomment this to turn unit tests into benchmarks:
#define BENCHMARKING
using System;
using System.Diagnostics; using System.Diagnostics;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using ImageSharp.Formats; using ImageSharp.Formats;
using Xunit; using Xunit;
@ -12,17 +16,84 @@ namespace ImageSharp.Tests.Formats.Jpg
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
public class Block8x8Tests : UtilityTestClassBase public class Block8x8Tests : UtilityTestClassBase
{ {
#if BENCHMARKING
public const int Times = 1000000;
#else
public const int Times = 1;
#endif
public Block8x8Tests(ITestOutputHelper output) : base(output) public Block8x8Tests(ITestOutputHelper output) : base(output)
{ {
} }
[Theory] [Fact]
[InlineData(1)] public void Indexer()
[InlineData(1000000)] {
public void Load_Store_FloatArray(int times) float sum = 0;
Measure(Times, () =>
{
Block8x8 block = new Block8x8();
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
block[i] = i;
}
sum = 0;
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
sum += block[i];
}
});
Assert.Equal(sum, 64f*63f*0.5f);
}
[Fact]
public unsafe void Indexer_GetScalarAt_SetScalarAt()
{
float sum = 0;
Measure(Times, () =>
{
Block8x8 block = new Block8x8();
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
Block8x8.SetScalarAt(&block, i, i);
}
sum = 0;
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
sum += Block8x8.GetScalarAt(&block, i);
}
});
Assert.Equal(sum, 64f * 63f * 0.5f);
}
[Fact]
public void Indexer_ReferenceBenchmarkWithArray()
{ {
float sum = 0;
float[] block = new float[64];
Measure(Times, () =>
{
//Block8x8 block = new Block8x8();
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
block[i] = i;
}
sum = 0;
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
sum += block[i];
}
});
Assert.Equal(sum, 64f * 63f * 0.5f);
}
[Fact]
public void Load_Store_FloatArray()
{
float[] data = new float[Block8x8.ScalarCount]; float[] data = new float[Block8x8.ScalarCount];
float[] mirror = new float[Block8x8.ScalarCount]; float[] mirror = new float[Block8x8.ScalarCount];
@ -30,24 +101,41 @@ namespace ImageSharp.Tests.Formats.Jpg
{ {
data[i] = i; data[i] = i;
} }
Measure(times, () => Measure(Times, () =>
{ {
Block8x8 v = new Block8x8(); Block8x8 b = new Block8x8();
v.LoadFrom(data); b.LoadFrom(data);
v.CopyTo(mirror); b.CopyTo(mirror);
}); });
Assert.Equal(data, mirror); Assert.Equal(data, mirror);
PrintLinearData((Span<float>)mirror); //PrintLinearData((Span<float>)mirror);
} }
[Theory] [Fact]
[InlineData(1)] public unsafe void Load_Store_FloatArray_Ptr()
[InlineData(1000000)]
public void Load_Store_IntArray(int times)
{ {
float[] data = new float[Block8x8.ScalarCount];
float[] mirror = new float[Block8x8.ScalarCount];
for (int i = 0; i < Block8x8.ScalarCount; i++)
{
data[i] = i;
}
Measure(Times, () =>
{
Block8x8 b = new Block8x8();
Block8x8.LoadFrom(&b, data);
Block8x8.CopyTo(&b, mirror);
});
Assert.Equal(data, mirror);
//PrintLinearData((Span<float>)mirror);
}
[Fact]
public void Load_Store_IntArray()
{
int[] data = new int[Block8x8.ScalarCount]; int[] data = new int[Block8x8.ScalarCount];
int[] mirror = new int[Block8x8.ScalarCount]; int[] mirror = new int[Block8x8.ScalarCount];
@ -55,7 +143,7 @@ namespace ImageSharp.Tests.Formats.Jpg
{ {
data[i] = i; data[i] = i;
} }
Measure(times, () => Measure(Times, () =>
{ {
Block8x8 v = new Block8x8(); Block8x8 v = new Block8x8();
v.LoadFrom(data); v.LoadFrom(data);
@ -63,7 +151,7 @@ namespace ImageSharp.Tests.Formats.Jpg
}); });
Assert.Equal(data, mirror); Assert.Equal(data, mirror);
PrintLinearData((Span<int>)mirror); //PrintLinearData((Span<int>)mirror);
} }
[Fact] [Fact]
@ -172,40 +260,37 @@ namespace ImageSharp.Tests.Formats.Jpg
public Block8x8 Buffer; public Block8x8 Buffer;
} }
[Theory] [Fact]
[InlineData(1)] public void TranposeInto_Benchmark()
[InlineData(10000000)]
public void TranposeInto_Benchmark(int times)
{ {
BufferHolder source = new BufferHolder(); BufferHolder source = new BufferHolder();
source.Buffer.LoadFrom(Create8x8FloatData()); source.Buffer.LoadFrom(Create8x8FloatData());
BufferHolder dest = new BufferHolder(); BufferHolder dest = new BufferHolder();
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {times} ..."); Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {Times} ...");
Stopwatch sw = Stopwatch.StartNew(); Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++) for (int i = 0; i < Times; i++)
{ {
source.Buffer.TransposeInto(ref dest.Buffer); source.Buffer.TransposeInto(ref dest.Buffer);
} }
sw.Stop(); sw.Stop();
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms"); Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms");
} }
[Theory] [Fact]
[InlineData(1)] public void TranposeInto_PinningImpl_Benchmark()
[InlineData(10000000)]
public void TranposeInto_PinningImpl_Benchmark(int times)
{ {
BufferHolder source = new BufferHolder(); BufferHolder source = new BufferHolder();
source.Buffer.LoadFrom(Create8x8FloatData()); source.Buffer.LoadFrom(Create8x8FloatData());
BufferHolder dest = new BufferHolder(); BufferHolder dest = new BufferHolder();
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {times} ..."); Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {Times} ...");
Stopwatch sw = Stopwatch.StartNew(); Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++) for (int i = 0; i < Times; i++)
{ {
source.Buffer.TransposeInto_PinningImpl(ref dest.Buffer); source.Buffer.TransposeInto_PinningImpl(ref dest.Buffer);
} }
@ -214,10 +299,8 @@ namespace ImageSharp.Tests.Formats.Jpg
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms"); Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms");
} }
[Theory] [Fact]
[InlineData(1)] public unsafe void TransposeInto_WithPointers_Benchmark()
[InlineData(10000000)]
public unsafe void TransposeInto_WithPointers_Benchmark(int times)
{ {
BufferHolder source = new BufferHolder(); BufferHolder source = new BufferHolder();
source.Buffer.LoadFrom(Create8x8FloatData()); source.Buffer.LoadFrom(Create8x8FloatData());
@ -227,10 +310,10 @@ namespace ImageSharp.Tests.Formats.Jpg
{ {
fixed (Block8x8* dPtr = &dest.Buffer) fixed (Block8x8* dPtr = &dest.Buffer)
{ {
Output.WriteLine($"TransposeInto_WithPointers_Benchmark X {times} ..."); Output.WriteLine($"TransposeInto_WithPointers_Benchmark X {Times} ...");
Stopwatch sw = Stopwatch.StartNew(); Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++) for (int i = 0; i < Times; i++)
{ {
Block8x8.TransposeInto(sPtr, dPtr); Block8x8.TransposeInto(sPtr, dPtr);
} }
@ -318,110 +401,6 @@ namespace ImageSharp.Tests.Formats.Jpg
Print8x8Data(actualDestArray); Print8x8Data(actualDestArray);
Assert.Equal(expectedDestArray, actualDestArray); Assert.Equal(expectedDestArray, actualDestArray);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void TransposeMatrix(ref Matrix4x4 s, ref Matrix4x4 d)
{
d.M11 = s.M11;
d.M12 = s.M21;
d.M13 = s.M31;
d.M14 = s.M41;
d.M21 = s.M12;
d.M22 = s.M22;
d.M23 = s.M32;
d.M24 = s.M42;
d.M31 = s.M13;
d.M32 = s.M23;
d.M33 = s.M33;
d.M34 = s.M43;
d.M41 = s.M14;
d.M42 = s.M24;
d.M43 = s.M34;
d.M44 = s.M44;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void TransposeMatrixPtr(float* s, float* d)
{
for (int i = 0; i < 4; i++)
{
int i4 = i*4;
for (int j = 0; j < 4; j++)
{
d[j*4 + i] = s[i4 + j];
}
}
}
[Theory]
[InlineData(50000000)]
public void TransposeMatrix_Custom(int times)
{
Matrix4x4 s = new Matrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
Matrix4x4 d = new Matrix4x4();
Output.WriteLine($"TransposeMatrix_System X {times} ...");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++)
{
TransposeMatrix(ref s, ref d);
}
sw.Stop();
Output.WriteLine($"TransposeMatrix_System finished in {sw.ElapsedMilliseconds} ms");
Output.WriteLine(d.ToString());
}
[Theory]
[InlineData(50000000)]
public unsafe void TransposeMatrix_System(int times)
{
Matrix4x4 s = new Matrix4x4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
Matrix4x4 d = new Matrix4x4();
Output.WriteLine($"TransposeMatrix_System X {times} ...");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++)
{
d = Matrix4x4.Transpose(s);
}
sw.Stop();
Output.WriteLine($"TransposeMatrix_System finished in {sw.ElapsedMilliseconds} ms");
Output.WriteLine(d.ToString());
}
[Theory]
[InlineData(50000000)]
public unsafe void TransposeMatrix_Ptr(int times)
{
Matrix4x4 s = new Matrix4x4(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
Matrix4x4 d = new Matrix4x4();
float* sPtr = (float*) &s;
float* dPtr = (float*) &d;
Output.WriteLine($"TransposeMatrix_System X {times} ...");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < times; i++)
{
TransposeMatrixPtr(sPtr,dPtr);
}
sw.Stop();
Output.WriteLine($"TransposeMatrix_System finished in {sw.ElapsedMilliseconds} ms");
Output.WriteLine(d.ToString());
}
} }
} }
Loading…
Cancel
Save