Browse Source

improved Block8x8F.Copy2x2Scale

af/merge-core
Anton Firszov 7 years ago
parent
commit
f57e1f062b
  1. 42
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
  2. 82
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs
  3. 104
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs

42
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs

@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return; return;
} }
// TODO: Optimize: implement all the cases with scale-specific, loopless code! // TODO: Optimize: implement all cases with scale-specific, loopless code!
this.CopyArbitraryScale(area, horizontalScale, verticalScale); this.CopyArbitraryScale(area, horizontalScale, verticalScale);
} }
@ -79,9 +79,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1);
ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride);
ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4);
ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride);
ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4);
var xLeft = new Vector4(sLeft.X); var xLeft = new Vector4(sLeft.X);
var yLeft = new Vector4(sLeft.Y); var yLeft = new Vector4(sLeft.Y);
@ -91,27 +89,33 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
var xRight = new Vector4(sRight.X); var xRight = new Vector4(sRight.X);
var yRight = new Vector4(sRight.Y); var yRight = new Vector4(sRight.Y);
var zRight = new Vector4(sRight.Z); var zRight = new Vector4(sRight.Z);
var wRight = new Vector4(sRight.W); var wRight = new Vector2(sRight.W);
Unsafe.As<Vector2, Vector4>(ref dTopLeft) = xLeft; Unsafe.As<Vector2, Vector4>(ref dTopLeft) = xLeft;
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; AssignVector4Value(ref dTopLeft, 1, ref yLeft);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; AssignVector4Value(ref dTopLeft, 2, ref zLeft);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; AssignVector4Value(ref dTopLeft, 3, ref wLeft);
Unsafe.As<Vector2, Vector4>(ref dTopRight) = xRight; AssignVector4Value(ref dTopLeft, 4, ref xRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopRight, 1)) = yRight; AssignVector4Value(ref dTopLeft, 5, ref yRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopRight, 2)) = zRight; AssignVector4Value(ref dTopLeft, 6, ref zRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopRight, 3)) = wRight; Unsafe.Add(ref dTopLeft, 7) = wRight;
Unsafe.As<Vector2, Vector4>(ref dBottomLeft) = xLeft; Unsafe.As<Vector2, Vector4>(ref dBottomLeft) = xLeft;
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; AssignVector4Value(ref dBottomLeft, 1, ref yLeft);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; AssignVector4Value(ref dBottomLeft, 2, ref zLeft);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; AssignVector4Value(ref dBottomLeft, 3, ref wLeft);
Unsafe.As<Vector2, Vector4>(ref dBottomRight) = xRight; AssignVector4Value(ref dBottomLeft, 4, ref xRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; AssignVector4Value(ref dBottomLeft, 5, ref yRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; AssignVector4Value(ref dBottomLeft, 6, ref zRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; Unsafe.Add(ref dBottomLeft, 7) = wRight;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value)
{
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset)) = value;
} }
[MethodImpl(InliningOptions.ColdPath)] [MethodImpl(InliningOptions.ColdPath)]

82
tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs

@ -0,0 +1,82 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
{
public class Block8x8F_CopyTo1x1
{
private Block8x8F block;
private Buffer2D<float> buffer;
private BufferArea<float> destArea;
[GlobalSetup]
public void Setup()
{
if (!SimdUtils.IsAvx2CompatibleArchitecture)
{
throw new InvalidOperationException("Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support.");
}
this.buffer = Configuration.Default.MemoryAllocator.Allocate2D<float>(1000, 500);
this.destArea = this.buffer.GetArea(200, 100, 64, 64);
}
[Benchmark(Baseline = true)]
public void Original()
{
ref byte selfBase = ref Unsafe.As<Block8x8F, byte>(ref this.block);
ref byte destBase = ref Unsafe.As<float, byte>(ref this.destArea.GetReferenceToOrigin());
int destStride = this.destArea.Stride * sizeof(float);
CopyRowImpl(ref selfBase, ref destBase, destStride, 0);
CopyRowImpl(ref selfBase, ref destBase, destStride, 1);
CopyRowImpl(ref selfBase, ref destBase, destStride, 2);
CopyRowImpl(ref selfBase, ref destBase, destStride, 3);
CopyRowImpl(ref selfBase, ref destBase, destStride, 4);
CopyRowImpl(ref selfBase, ref destBase, destStride, 5);
CopyRowImpl(ref selfBase, ref destBase, destStride, 6);
CopyRowImpl(ref selfBase, ref destBase, destStride, 7);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void CopyRowImpl(ref byte selfBase, ref byte destBase, int destStride, int row)
{
ref byte s = ref Unsafe.Add(ref selfBase, row * 8 * sizeof(float));
ref byte d = ref Unsafe.Add(ref destBase, row * destStride);
Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float));
}
[Benchmark]
public void UseVector8()
{
ref Block8x8F s = ref this.block;
ref Vector<float> d = ref Unsafe.As<float, Vector<float>>(ref this.destArea.GetReferenceToOrigin());
Vector<float> row0 = Unsafe.As<Vector4, Vector<float>>(ref s.V0L);
Vector<float> row1 = Unsafe.As<Vector4, Vector<float>>(ref s.V1L);
Vector<float> row2 = Unsafe.As<Vector4, Vector<float>>(ref s.V2L);
Vector<float> row3 = Unsafe.As<Vector4, Vector<float>>(ref s.V3L);
Vector<float> row4 = Unsafe.As<Vector4, Vector<float>>(ref s.V4L);
Vector<float> row5 = Unsafe.As<Vector4, Vector<float>>(ref s.V5L);
Vector<float> row6 = Unsafe.As<Vector4, Vector<float>>(ref s.V6L);
Vector<float> row7 = Unsafe.As<Vector4, Vector<float>>(ref s.V7L);
d = row0;
Unsafe.Add(ref d, 1) = row1;
Unsafe.Add(ref d, 2) = row2;
Unsafe.Add(ref d, 3) = row3;
Unsafe.Add(ref d, 4) = row4;
Unsafe.Add(ref d, 5) = row5;
Unsafe.Add(ref d, 6) = row6;
Unsafe.Add(ref d, 7) = row7;
}
}
}

104
tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs

@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WidenCopyImpl2x2(ref Block8x8F src, ref float destBase, int row, int destStride) private static void WidenCopyImpl2x2(ref Block8x8F src, ref float destBase, int row, int destStride)
{ {
ref Vector4 selfRight = ref Unsafe.Add(ref src.V0L, 2 * row); ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row);
ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1);
ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride);
@ -257,31 +257,97 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
var wRight = new Vector4(sRight.W); var wRight = new Vector4(sRight.W);
Unsafe.As<Vector2, Vector4>(ref dTopLeft) = xLeft; Unsafe.As<Vector2, Vector4>(ref dTopLeft) = xLeft;
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; AssignVector4Value(ref dTopLeft, 1, ref yLeft);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; AssignVector4Value(ref dTopLeft, 2, ref zLeft);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; AssignVector4Value(ref dTopLeft, 3, ref wLeft);
Unsafe.As<Vector2, Vector4>(ref dTopRight) = xRight; Unsafe.As<Vector2, Vector4>(ref dTopRight) = xRight;
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopRight, 1)) = yRight; AssignVector4Value(ref dTopRight, 1, ref yRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopRight, 2)) = zRight; AssignVector4Value(ref dTopRight, 2, ref zRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dTopRight, 3)) = wRight; AssignVector4Value(ref dTopRight, 3, ref wRight);
Unsafe.As<Vector2, Vector4>(ref dBottomLeft) = xLeft; Unsafe.As<Vector2, Vector4>(ref dBottomLeft) = xLeft;
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; AssignVector4Value(ref dBottomLeft, 1, ref yLeft);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; AssignVector4Value(ref dBottomLeft, 2, ref zLeft);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; AssignVector4Value(ref dBottomLeft, 3, ref wLeft);
Unsafe.As<Vector2, Vector4>(ref dBottomRight) = xRight; Unsafe.As<Vector2, Vector4>(ref dBottomRight) = xRight;
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; AssignVector4Value(ref dBottomRight, 1, ref yRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; AssignVector4Value(ref dBottomRight, 2, ref zRight);
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; AssignVector4Value(ref dBottomRight, 3, ref wRight);
}
[Benchmark]
public void UseVector4_SafeRightCorner()
{
ref Vector2 destBase = ref Unsafe.As<float, Vector2>(ref this.destArea.GetReferenceToOrigin());
int destStride = this.destArea.Stride / 2;
ref Block8x8F src = ref this.block;
WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 0, destStride);
WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 1, destStride);
WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 2, destStride);
WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 3, destStride);
WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 4, destStride);
WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 5, destStride);
WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 6, destStride);
WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 7, destStride);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void WidenCopyImpl2x2_Vector4_SafeRightCorner(ref Block8x8F src, ref Vector2 destBase, int row, int destStride)
{
ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row);
ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1);
ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride);
ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride);
var xLeft = new Vector4(sLeft.X);
var yLeft = new Vector4(sLeft.Y);
var zLeft = new Vector4(sLeft.Z);
var wLeft = new Vector4(sLeft.W);
var xRight = new Vector4(sRight.X);
var yRight = new Vector4(sRight.Y);
var zRight = new Vector4(sRight.Z);
var wRight = new Vector2(sRight.W);
Unsafe.As<Vector2, Vector4>(ref dTopLeft) = xLeft;
AssignVector4Value(ref dTopLeft, 1, ref yLeft);
AssignVector4Value(ref dTopLeft, 2, ref zLeft);
AssignVector4Value(ref dTopLeft, 3, ref wLeft);
AssignVector4Value(ref dTopLeft, 4, ref xRight);
AssignVector4Value(ref dTopLeft, 5, ref yRight);
AssignVector4Value(ref dTopLeft, 6, ref zRight);
Unsafe.Add(ref dTopLeft, 7) = wRight;
Unsafe.As<Vector2, Vector4>(ref dBottomLeft) = xLeft;
AssignVector4Value(ref dBottomLeft, 1, ref yLeft);
AssignVector4Value(ref dBottomLeft, 2, ref zLeft);
AssignVector4Value(ref dBottomLeft, 3, ref wLeft);
AssignVector4Value(ref dBottomLeft, 4, ref xRight);
AssignVector4Value(ref dBottomLeft, 5, ref yRight);
AssignVector4Value(ref dBottomLeft, 6, ref zRight);
Unsafe.Add(ref dBottomLeft, 7) = wRight;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AssignVector4Value(ref Vector2 destBase, int offset, ref Vector4 value)
{
Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset)) = value;
} }
// RESULTS: // RESULTS:
// Method | Mean | Error | StdDev | Scaled | // Method | Mean | Error | StdDev | Scaled | ScaledSD |
// ------------ |---------:|----------:|----------:|-------:| // --------------------------- |---------:|----------:|----------:|-------:|---------:|
// Original | 88.93 ns | 0.7783 ns | 0.6899 ns | 1.00 | // Original | 93.78 ns | 1.8419 ns | 1.9708 ns | 1.00 | 0.00 |
// Original_V2 | 88.39 ns | 0.9426 ns | 0.8356 ns | 0.99 | // Original_V2 | 89.85 ns | 0.8809 ns | 0.7356 ns | 0.96 | 0.02 |
// UseVector2 | 45.63 ns | 0.4248 ns | 0.3548 ns | 0.51 | // UseVector2 | 81.81 ns | 0.4441 ns | 0.3937 ns | 0.87 | 0.02 |
// UseVector4 | 55.74 ns | 0.3674 ns | 0.3068 ns | 0.59 | 0.01 |
// UseVector4_SafeRightCorner | 55.70 ns | 0.3239 ns | 0.2705 ns | 0.59 | 0.01 |
} }
} }
Loading…
Cancel
Save