|
|
|
@ -1,7 +1,11 @@ |
|
|
|
using System; |
|
|
|
// Uncomment this to turn unit tests into benchmarks:
|
|
|
|
#define BENCHMARKING
|
|
|
|
|
|
|
|
using System; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Numerics; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
|
using System.Runtime.InteropServices; |
|
|
|
using System.Text; |
|
|
|
using ImageSharp.Formats; |
|
|
|
using Xunit; |
|
|
|
@ -12,17 +16,84 @@ namespace ImageSharp.Tests.Formats.Jpg |
|
|
|
// ReSharper disable once InconsistentNaming
|
|
|
|
public class Block8x8Tests : UtilityTestClassBase |
|
|
|
{ |
|
|
|
#if BENCHMARKING
|
|
|
|
public const int Times = 1000000; |
|
|
|
#else
|
|
|
|
public const int Times = 1; |
|
|
|
#endif
|
|
|
|
|
|
|
|
public Block8x8Tests(ITestOutputHelper output) : base(output) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(1)] |
|
|
|
[InlineData(1000000)] |
|
|
|
public void Load_Store_FloatArray(int times) |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void Indexer() |
|
|
|
{ |
|
|
|
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[] mirror = new float[Block8x8.ScalarCount]; |
|
|
|
|
|
|
|
@ -30,24 +101,41 @@ namespace ImageSharp.Tests.Formats.Jpg |
|
|
|
{ |
|
|
|
data[i] = i; |
|
|
|
} |
|
|
|
Measure(times, () => |
|
|
|
Measure(Times, () => |
|
|
|
{ |
|
|
|
Block8x8 v = new Block8x8(); |
|
|
|
v.LoadFrom(data); |
|
|
|
v.CopyTo(mirror); |
|
|
|
Block8x8 b = new Block8x8(); |
|
|
|
b.LoadFrom(data); |
|
|
|
b.CopyTo(mirror); |
|
|
|
}); |
|
|
|
|
|
|
|
Assert.Equal(data, mirror); |
|
|
|
PrintLinearData((Span<float>)mirror); |
|
|
|
//PrintLinearData((Span<float>)mirror);
|
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(1)] |
|
|
|
[InlineData(1000000)] |
|
|
|
public void Load_Store_IntArray(int times) |
|
|
|
[Fact] |
|
|
|
public unsafe void Load_Store_FloatArray_Ptr() |
|
|
|
{ |
|
|
|
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[] mirror = new int[Block8x8.ScalarCount]; |
|
|
|
|
|
|
|
@ -55,7 +143,7 @@ namespace ImageSharp.Tests.Formats.Jpg |
|
|
|
{ |
|
|
|
data[i] = i; |
|
|
|
} |
|
|
|
Measure(times, () => |
|
|
|
Measure(Times, () => |
|
|
|
{ |
|
|
|
Block8x8 v = new Block8x8(); |
|
|
|
v.LoadFrom(data); |
|
|
|
@ -63,7 +151,7 @@ namespace ImageSharp.Tests.Formats.Jpg |
|
|
|
}); |
|
|
|
|
|
|
|
Assert.Equal(data, mirror); |
|
|
|
PrintLinearData((Span<int>)mirror); |
|
|
|
//PrintLinearData((Span<int>)mirror);
|
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
@ -172,40 +260,37 @@ namespace ImageSharp.Tests.Formats.Jpg |
|
|
|
public Block8x8 Buffer; |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(1)] |
|
|
|
[InlineData(10000000)] |
|
|
|
public void TranposeInto_Benchmark(int times) |
|
|
|
[Fact] |
|
|
|
public void TranposeInto_Benchmark() |
|
|
|
{ |
|
|
|
BufferHolder source = new BufferHolder(); |
|
|
|
source.Buffer.LoadFrom(Create8x8FloatData()); |
|
|
|
BufferHolder dest = new BufferHolder(); |
|
|
|
|
|
|
|
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {times} ..."); |
|
|
|
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {Times} ..."); |
|
|
|
Stopwatch sw = Stopwatch.StartNew(); |
|
|
|
|
|
|
|
for (int i = 0; i < times; i++) |
|
|
|
for (int i = 0; i < Times; i++) |
|
|
|
{ |
|
|
|
source.Buffer.TransposeInto(ref dest.Buffer); |
|
|
|
} |
|
|
|
|
|
|
|
sw.Stop(); |
|
|
|
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(1)] |
|
|
|
[InlineData(10000000)] |
|
|
|
public void TranposeInto_PinningImpl_Benchmark(int times) |
|
|
|
[Fact] |
|
|
|
public void TranposeInto_PinningImpl_Benchmark() |
|
|
|
{ |
|
|
|
BufferHolder source = new BufferHolder(); |
|
|
|
source.Buffer.LoadFrom(Create8x8FloatData()); |
|
|
|
BufferHolder dest = new BufferHolder(); |
|
|
|
|
|
|
|
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {times} ..."); |
|
|
|
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark X {Times} ..."); |
|
|
|
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); |
|
|
|
} |
|
|
|
@ -214,10 +299,8 @@ namespace ImageSharp.Tests.Formats.Jpg |
|
|
|
Output.WriteLine($"TranposeInto_PinningImpl_Benchmark finished in {sw.ElapsedMilliseconds} ms"); |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(1)] |
|
|
|
[InlineData(10000000)] |
|
|
|
public unsafe void TransposeInto_WithPointers_Benchmark(int times) |
|
|
|
[Fact] |
|
|
|
public unsafe void TransposeInto_WithPointers_Benchmark() |
|
|
|
{ |
|
|
|
BufferHolder source = new BufferHolder(); |
|
|
|
source.Buffer.LoadFrom(Create8x8FloatData()); |
|
|
|
@ -227,10 +310,10 @@ namespace ImageSharp.Tests.Formats.Jpg |
|
|
|
{ |
|
|
|
fixed (Block8x8* dPtr = &dest.Buffer) |
|
|
|
{ |
|
|
|
Output.WriteLine($"TransposeInto_WithPointers_Benchmark X {times} ..."); |
|
|
|
Output.WriteLine($"TransposeInto_WithPointers_Benchmark X {Times} ..."); |
|
|
|
Stopwatch sw = Stopwatch.StartNew(); |
|
|
|
|
|
|
|
for (int i = 0; i < times; i++) |
|
|
|
for (int i = 0; i < Times; i++) |
|
|
|
{ |
|
|
|
Block8x8.TransposeInto(sPtr, dPtr); |
|
|
|
} |
|
|
|
@ -318,110 +401,6 @@ namespace ImageSharp.Tests.Formats.Jpg |
|
|
|
Print8x8Data(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()); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |