mirror of https://github.com/SixLabors/ImageSharp
1 changed files with 154 additions and 0 deletions
@ -0,0 +1,154 @@ |
|||
namespace ImageSharp.Benchmarks.General |
|||
{ |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
using BenchmarkDotNet.Attributes; |
|||
|
|||
using ImageSharp.Formats.Jpg; |
|||
|
|||
/// <summary>
|
|||
/// The goal of this benchmark is to measure the following Jpeg-related scenario:
|
|||
/// - Take 2 blocks of float-s
|
|||
/// - Divide each float pair, round the result
|
|||
/// - Iterate through all rounded values as int-s
|
|||
/// </summary>
|
|||
public unsafe class RoundSinglePrecisionBlocks |
|||
{ |
|||
private const int ExecutionCount = 5; // Added this to reduce the effect of copying the blocks
|
|||
private static readonly Vector4 MinusOne = new Vector4(-1); |
|||
private static readonly Vector4 Half = new Vector4(0.5f); |
|||
|
|||
private Block8x8F inputDividend = default(Block8x8F); |
|||
private Block8x8F inputDivisior = default(Block8x8F); |
|||
|
|||
[Setup] |
|||
public void Setup() |
|||
{ |
|||
for (int i = 0; i < Block8x8F.ScalarCount; i++) |
|||
{ |
|||
this.inputDividend[i] = i*44.8f; |
|||
this.inputDivisior[i] = 100 - i; |
|||
} |
|||
} |
|||
|
|||
[Benchmark(Baseline = true)] |
|||
public int ByRationalIntegers() |
|||
{ |
|||
int sum = 0; |
|||
|
|||
Block8x8F b1 = this.inputDividend; |
|||
Block8x8F b2 = this.inputDivisior; |
|||
float* pDividend = (float*)&b1; |
|||
float* pDivisor = (float*)&b2; |
|||
|
|||
int* result = stackalloc int[Block8x8F.ScalarCount]; |
|||
|
|||
for (int cnt = 0; cnt < ExecutionCount; cnt++) |
|||
{ |
|||
sum = 0; |
|||
for (int i = 0; i < Block8x8F.ScalarCount; i++) |
|||
{ |
|||
int a = (int) pDividend[i]; |
|||
int b = (int) pDivisor; |
|||
result[i] = RationalRound(a, b); |
|||
} |
|||
for (int i = 0; i < Block8x8F.ScalarCount; i++) |
|||
{ |
|||
sum += result[i]; |
|||
} |
|||
} |
|||
|
|||
return sum; |
|||
} |
|||
|
|||
[Benchmark] |
|||
public int BySystemMathRound() |
|||
{ |
|||
int sum = 0; |
|||
|
|||
Block8x8F b1 = this.inputDividend; |
|||
Block8x8F b2 = this.inputDivisior; |
|||
float* pDividend = (float*)&b1; |
|||
float* pDivisor = (float*)&b2; |
|||
|
|||
for (int cnt = 0; cnt < ExecutionCount; cnt++) |
|||
{ |
|||
sum = 0; |
|||
for (int i = 0; i < Block8x8F.ScalarCount; i++) |
|||
{ |
|||
double value = pDividend[i] / pDivisor[i]; |
|||
pDividend[i] = (float) System.Math.Round(value); |
|||
} |
|||
for (int i = 0; i < Block8x8F.ScalarCount; i++) |
|||
{ |
|||
sum += (int) pDividend[i]; |
|||
} |
|||
} |
|||
return sum; |
|||
} |
|||
|
|||
[Benchmark] |
|||
public int BySimdMagic() |
|||
{ |
|||
int sum = 0; |
|||
|
|||
Block8x8F bDividend = this.inputDividend; |
|||
Block8x8F bDivisor = this.inputDivisior; |
|||
float* pDividend = (float*)&bDividend; |
|||
float* pDivisor = (float*)&bDivisor; |
|||
|
|||
for (int cnt = 0; cnt < ExecutionCount; cnt++) |
|||
{ |
|||
sum = 0; |
|||
DivideRoundAll(ref bDividend, ref bDivisor); |
|||
for (int i = 0; i < Block8x8F.ScalarCount; i++) |
|||
{ |
|||
sum += (int)pDividend[i]; |
|||
} |
|||
} |
|||
return sum; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static void DivideRoundAll(ref Block8x8F a, ref Block8x8F b) |
|||
{ |
|||
a.V0L = DivideRound(a.V0L, b.V0L); |
|||
a.V0R = DivideRound(a.V0R, b.V0R); |
|||
a.V1L = DivideRound(a.V1L, b.V1L); |
|||
a.V1R = DivideRound(a.V1R, b.V1R); |
|||
a.V2L = DivideRound(a.V2L, b.V2L); |
|||
a.V2R = DivideRound(a.V2R, b.V2R); |
|||
a.V3L = DivideRound(a.V3L, b.V3L); |
|||
a.V3R = DivideRound(a.V3R, b.V3R); |
|||
a.V4L = DivideRound(a.V4L, b.V4L); |
|||
a.V4R = DivideRound(a.V4R, b.V4R); |
|||
a.V5L = DivideRound(a.V5L, b.V5L); |
|||
a.V5R = DivideRound(a.V5R, b.V5R); |
|||
a.V6L = DivideRound(a.V6L, b.V6L); |
|||
a.V6R = DivideRound(a.V6R, b.V6R); |
|||
a.V7L = DivideRound(a.V7L, b.V7L); |
|||
a.V7R = DivideRound(a.V7R, b.V7R); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) |
|||
{ |
|||
Vector4 sign = Vector4.Min(dividend, Vector4.One); |
|||
sign = Vector4.Max(sign, MinusOne); |
|||
|
|||
return dividend / divisor + sign * Half; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static int RationalRound(int dividend, int divisor) |
|||
{ |
|||
if (dividend >= 0) |
|||
{ |
|||
return (dividend + (divisor >> 1)) / divisor; |
|||
} |
|||
|
|||
return -((-dividend + (divisor >> 1)) / divisor); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue