Optimizations and tiny cleanup
This commit is contained in:
1 parent
e14cb5df52
commit
513fc7acb0
6 files changed
+44
-41
No files matched your search
Vendored
+5
-1
@@ -2,6 +2,10 @@
|
|||||||
"dotnet.defaultSolution": "FlexiCoder.sln",
|
"dotnet.defaultSolution": "FlexiCoder.sln",
|
||||||
"chatgpt.openOnStartup": true,
|
"chatgpt.openOnStartup": true,
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"ILGPU"
|
"CCCCCCCDUL",
|
||||||
|
"ILGPU",
|
||||||
|
"mers",
|
||||||
|
"primality",
|
||||||
|
"suff"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using BenchmarkDotNet.Jobs;
|
using BenchmarkDotNet.Jobs;
|
||||||
@@ -29,17 +29,17 @@ public class GpuUInt128BinaryGcdBenchmarks
|
|||||||
[Benchmark(Baseline = true)]
|
[Benchmark(Baseline = true)]
|
||||||
public GpuUInt128 ReusedVariables()
|
public GpuUInt128 ReusedVariables()
|
||||||
{
|
{
|
||||||
return GpuUInt128.BinaryGcd(Input.Left, Input.Right);
|
return BinaryGcdWithReusedVariables(Input.Left, Input.Right);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public GpuUInt128 TemporaryStructPerIteration()
|
public GpuUInt128 TemporaryStructPerIteration()
|
||||||
{
|
{
|
||||||
return BinaryGcdWithTemporary(Input.Left, Input.Right);
|
return GpuUInt128.BinaryGcd(Input.Left, Input.Right);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static GpuUInt128 BinaryGcdWithTemporary(GpuUInt128 u, GpuUInt128 v)
|
private static GpuUInt128 BinaryGcdWithReusedVariables(GpuUInt128 u, GpuUInt128 v)
|
||||||
{
|
{
|
||||||
if (u.IsZero)
|
if (u.IsZero)
|
||||||
{
|
{
|
||||||
@@ -51,7 +51,12 @@ public class GpuUInt128BinaryGcdBenchmarks
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
int shift = GpuUInt128.TrailingZeroCount(new GpuUInt128(u.High | v.High, u.Low | v.Low));
|
ulong combinedLow = u.Low | v.Low;
|
||||||
|
ulong combinedHigh = u.High | v.High;
|
||||||
|
int shift = combinedLow != 0UL
|
||||||
|
? BitOperations.TrailingZeroCount(combinedLow)
|
||||||
|
: 64 + BitOperations.TrailingZeroCount(combinedHigh);
|
||||||
|
|
||||||
int zu = GpuUInt128.TrailingZeroCount(u);
|
int zu = GpuUInt128.TrailingZeroCount(u);
|
||||||
u >>= zu;
|
u >>= zu;
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class GpuUInt128Mul64Benchmarks
|
|||||||
public static IEnumerable<Mul64Input> GetInputs() => Inputs;
|
public static IEnumerable<Mul64Input> GetInputs() => Inputs;
|
||||||
|
|
||||||
[Benchmark(Baseline = true)]
|
[Benchmark(Baseline = true)]
|
||||||
public GpuUInt128 HighProductMaterialisedInLocal()
|
public GpuUInt128 HighProductMaterializedInLocal()
|
||||||
{
|
{
|
||||||
GpuUInt128 value = Input.Multiplicand;
|
GpuUInt128 value = Input.Multiplicand;
|
||||||
value.Mul64(Input.Multiplier);
|
value.Mul64(Input.Multiplier);
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ namespace EvenPerfectBitScanner.Benchmarks;
|
|||||||
[MemoryDiagnoser]
|
[MemoryDiagnoser]
|
||||||
public class GpuUInt128MulModBenchmarks
|
public class GpuUInt128MulModBenchmarks
|
||||||
{
|
{
|
||||||
private static readonly MulModInput[] Inputs = new MulModInput[]
|
private static readonly MulModInput[] Inputs =
|
||||||
{
|
[
|
||||||
new(
|
new(
|
||||||
new GpuUInt128(0UL, 5UL),
|
new GpuUInt128(0UL, 5UL),
|
||||||
new GpuUInt128(0UL, 7UL),
|
new GpuUInt128(0UL, 7UL),
|
||||||
@@ -32,7 +32,7 @@ public class GpuUInt128MulModBenchmarks
|
|||||||
new GpuUInt128(0x7FFF_FFFF_FFFF_FFFFUL, 0x8000_0000_0000_0000UL),
|
new GpuUInt128(0x7FFF_FFFF_FFFF_FFFFUL, 0x8000_0000_0000_0000UL),
|
||||||
new GpuUInt128(0x7FFF_FFFF_FFFF_FFFFUL, 0xFFFF_FFFF_FFFF_FFF1UL),
|
new GpuUInt128(0x7FFF_FFFF_FFFF_FFFFUL, 0xFFFF_FFFF_FFFF_FFF1UL),
|
||||||
"MixedMagnitude"),
|
"MixedMagnitude"),
|
||||||
};
|
];
|
||||||
|
|
||||||
[ParamsSource(nameof(GetInputs))]
|
[ParamsSource(nameof(GetInputs))]
|
||||||
public MulModInput Input { get; set; }
|
public MulModInput Input { get; set; }
|
||||||
@@ -42,6 +42,7 @@ public class GpuUInt128MulModBenchmarks
|
|||||||
[Benchmark(Baseline = true)]
|
[Benchmark(Baseline = true)]
|
||||||
public GpuUInt128 InPlaceMulMod()
|
public GpuUInt128 InPlaceMulMod()
|
||||||
{
|
{
|
||||||
|
// TODO: Switch the extension method to allocate per iteration, as it's faster. Keep the benchmarks.
|
||||||
GpuUInt128 value = Input.Left;
|
GpuUInt128 value = Input.Left;
|
||||||
value.MulMod(Input.Right, Input.Modulus);
|
value.MulMod(Input.Right, Input.Modulus);
|
||||||
return value;
|
return value;
|
||||||
@@ -56,6 +57,7 @@ public class GpuUInt128MulModBenchmarks
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static GpuUInt128 MulModInline(GpuUInt128 left, GpuUInt128 right, GpuUInt128 modulus)
|
private static GpuUInt128 MulModInline(GpuUInt128 left, GpuUInt128 right, GpuUInt128 modulus)
|
||||||
{
|
{
|
||||||
|
// Reuse the variables to new instances and lower registry pressure, if possible.
|
||||||
GpuUInt128 a = left;
|
GpuUInt128 a = left;
|
||||||
GpuUInt128 b = right;
|
GpuUInt128 b = right;
|
||||||
GpuUInt128 result = new();
|
GpuUInt128 result = new();
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public class GpuUInt128MulModByLimbBenchmarks
|
|||||||
[Benchmark]
|
[Benchmark]
|
||||||
public GpuUInt128 InPlaceReduction()
|
public GpuUInt128 InPlaceReduction()
|
||||||
{
|
{
|
||||||
|
// TODO: Switch the extension method back to legacy method, as it's faster. Keep the benchmarks.
|
||||||
GpuUInt128 value = Input.Left;
|
GpuUInt128 value = Input.Left;
|
||||||
value.MulModByLimb(Input.Right, Input.Modulus);
|
value.MulModByLimb(Input.Right, Input.Modulus);
|
||||||
return value;
|
return value;
|
||||||
|
|||||||
@@ -535,12 +535,7 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
|
|||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong combinedLow = u.Low | v.Low;
|
int shift = TrailingZeroCount(new GpuUInt128(u.High | v.High, u.Low | v.Low));
|
||||||
ulong combinedHigh = u.High | v.High;
|
|
||||||
int shift = combinedLow != 0UL
|
|
||||||
? BitOperations.TrailingZeroCount(combinedLow)
|
|
||||||
: 64 + BitOperations.TrailingZeroCount(combinedHigh);
|
|
||||||
|
|
||||||
int zu = TrailingZeroCount(u);
|
int zu = TrailingZeroCount(u);
|
||||||
u >>= zu;
|
u >>= zu;
|
||||||
|
|
||||||
@@ -762,7 +757,7 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ulong MulMod(GpuUInt128 other, ulong modulus)
|
public readonly ulong MulMod(GpuUInt128 other, ulong modulus)
|
||||||
{
|
{
|
||||||
ulong modulusLocal = modulus;
|
ulong modulusLocal = modulus;
|
||||||
ulong a = Low % modulusLocal;
|
ulong a = Low % modulusLocal;
|
||||||
@@ -779,24 +774,24 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ulong MulMod(ulong value, ulong modulus)
|
public readonly ulong MulMod(ulong value, ulong modulus)
|
||||||
{
|
{
|
||||||
ulong modulusLocal = modulus;
|
ulong a = Low % modulus;
|
||||||
ulong a = Low % modulusLocal;
|
ulong b = value % modulus;
|
||||||
ulong b = value % modulusLocal;
|
|
||||||
|
|
||||||
if (a == 0UL || b == 0UL)
|
if (a == 0UL || b == 0UL)
|
||||||
{
|
{
|
||||||
return 0UL;
|
return 0UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return b <= ulong.MaxValue / a
|
ulong ulongRange = ulong.MaxValue / a;
|
||||||
? (a * b) % modulusLocal
|
return b <= ulongRange
|
||||||
: MulMod64(a, b, modulusLocal);
|
? (a * b) % modulus
|
||||||
|
: MulMod64(a, b, modulus);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ulong MulModSimplified(ulong value, ulong modulus)
|
public readonly ulong MulModSimplified(ulong value, ulong modulus)
|
||||||
{
|
{
|
||||||
ulong modulusLocal = modulus;
|
ulong modulusLocal = modulus;
|
||||||
ulong a = Low % modulusLocal;
|
ulong a = Low % modulusLocal;
|
||||||
@@ -811,37 +806,33 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ulong MulModWithNativeModulo(ulong value, ulong modulus)
|
public readonly ulong MulModWithNativeModulo(ulong value, ulong modulus)
|
||||||
{
|
{
|
||||||
ulong modulusLocal = modulus;
|
ulong multiplicand = Low % modulus;
|
||||||
ulong multiplicand = Low % modulusLocal;
|
var remainder = value % modulus;
|
||||||
ulong multiplier = value % modulusLocal;
|
|
||||||
|
|
||||||
if (multiplicand == 0UL || multiplier == 0UL)
|
if (multiplicand == 0UL || remainder == 0UL)
|
||||||
{
|
{
|
||||||
return 0UL;
|
return 0UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong result = 0UL;
|
ulong result = 0UL;
|
||||||
ulong current = multiplicand;
|
|
||||||
ulong remaining = multiplier;
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ulong chunk = remaining & NativeModuloChunkMask;
|
ulong chunk = remainder & NativeModuloChunkMask;
|
||||||
if (chunk != 0UL)
|
if (chunk != 0UL)
|
||||||
{
|
{
|
||||||
ulong chunkContribution = MultiplyChunkModulo(current, chunk, modulusLocal);
|
chunk = MultiplyChunkModulo(multiplicand, chunk, modulus);
|
||||||
result = (result + chunkContribution) % modulusLocal;
|
result = (result + chunk) % modulus;
|
||||||
}
|
}
|
||||||
|
|
||||||
remaining >>= NativeModuloChunkBits;
|
remainder >>= NativeModuloChunkBits;
|
||||||
if (remaining == 0UL)
|
if (remainder == 0UL)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
current = ShiftLeftByNativeChunk(current, modulusLocal);
|
multiplicand = ShiftLeftByNativeChunk(multiplicand, modulus);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -936,7 +927,7 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ulong MulModMontgomery64(GpuUInt128 other, ulong modulus, ulong nPrime, ulong r2)
|
public readonly ulong MulModMontgomery64(GpuUInt128 other, ulong modulus, ulong nPrime, ulong r2)
|
||||||
{
|
{
|
||||||
ulong modulusLocal = modulus;
|
ulong modulusLocal = modulus;
|
||||||
ulong a = Low % modulusLocal;
|
ulong a = Low % modulusLocal;
|
||||||
@@ -954,7 +945,7 @@ public struct GpuUInt128 : IComparable<GpuUInt128>, IEquatable<GpuUInt128>
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ulong MulModMontgomery64(ulong other, ulong modulus, ulong nPrime, ulong r2)
|
public readonly ulong MulModMontgomery64(ulong other, ulong modulus, ulong nPrime, ulong r2)
|
||||||
{
|
{
|
||||||
ulong modulusLocal = modulus;
|
ulong modulusLocal = modulus;
|
||||||
ulong a = Low % modulusLocal;
|
ulong a = Low % modulusLocal;
|
||||||
|
|||||||
Reference in new issue
Block a user