MethodImplOptions.AggressiveOptimization & MethodImplOptions.AggressiveInlining optimized. Small optimizations.

This commit is contained in:
mlemanczyk committed 2025-12-10 19:59:51 +01:00
1 parent 7a242b3bfa
commit 05d3061c47
23 files changed
+284 -215

No files matched your search

@@ -12,10 +12,7 @@ public class HeuristicCombinedPrimeTesterTests
[InlineData((byte)9)] [InlineData((byte)9)]
public void Enumerator_uses_one_a_one_b_schedule_by_default(byte lastDigit) public void Enumerator_uses_one_a_one_b_schedule_by_default(byte lastDigit)
{ {
Span<HeuristicCombinedPrimeTester.HeuristicGroupBSequenceState> groupBState = var enumerator = HeuristicCombinedPrimeTester.CreateHeuristicDivisorEnumerator(500UL * 500UL, lastDigit);
stackalloc HeuristicCombinedPrimeTester.HeuristicGroupBSequenceState[4];
var enumerator = HeuristicCombinedPrimeTester.CreateHeuristicDivisorEnumerator(500UL * 500UL, lastDigit, groupBState);
var results = new List<HeuristicCombinedPrimeTester.HeuristicDivisorCandidate>(32); var results = new List<HeuristicCombinedPrimeTester.HeuristicDivisorCandidate>(32);
while (results.Count < 20 && enumerator.TryGetNext(out var candidate)) while (results.Count < 20 && enumerator.TryGetNext(out var candidate))
@@ -7,7 +7,7 @@ public struct AscendingDivisorRemainderStepper
private readonly ulong _dividend; private readonly ulong _dividend;
private ulong _maxDivisor; private ulong _maxDivisor;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
public AscendingDivisorRemainderStepper(ulong value) public AscendingDivisorRemainderStepper(ulong value)
{ {
_dividend = value; _dividend = value;
@@ -20,10 +20,10 @@ public struct AscendingDivisorRemainderStepper
_maxDivisor = root; _maxDivisor = root;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public readonly bool ShouldContinue(ulong divisor) => divisor <= _maxDivisor; public readonly bool ShouldContinue(ulong divisor) => divisor <= _maxDivisor;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public bool Divides(ulong divisor) public bool Divides(ulong divisor)
{ {
ulong remainder = _dividend; ulong remainder = _dividend;
@@ -10,21 +10,21 @@ public struct BidirectionalCycleRemainderStepper(ulong modulus)
public readonly ulong Modulus public readonly ulong Modulus
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
get get
{ {
return _modulus; return _modulus;
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public void Initialize(ulong value) public void Initialize(ulong value)
{ {
_remainder = value.ReduceCycleRemainder(_modulus); _remainder = value.ReduceCycleRemainder(_modulus);
_previous = value; _previous = value;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public ulong Step(ulong value) public ulong Step(ulong value)
{ {
long delta = unchecked((long)value - (long)_previous); long delta = unchecked((long)value - (long)_previous);
@@ -1,3 +1,5 @@
using System.Runtime.CompilerServices;
namespace PerfectNumbers.Core.Cpu; namespace PerfectNumbers.Core.Cpu;
internal static class DeterministicRandomCpu internal static class DeterministicRandomCpu
@@ -7,6 +9,7 @@ internal static class DeterministicRandomCpu
private static long s_seedCounter; private static long s_seedCounter;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong NextUInt64() public static ulong NextUInt64()
{ {
ulong state = s_threadState; ulong state = s_threadState;
@@ -22,6 +25,7 @@ internal static class DeterministicRandomCpu
return state * 2685821657736338717UL; return state * 2685821657736338717UL;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static UInt128 NextUInt128() public static UInt128 NextUInt128()
{ {
UInt128 high = (UInt128)NextUInt64(); UInt128 high = (UInt128)NextUInt64();
@@ -29,6 +33,7 @@ internal static class DeterministicRandomCpu
return (high << 64) | low; return (high << 64) | low;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong InitializeThreadState() private static ulong InitializeThreadState()
{ {
ulong seed = (ulong)Interlocked.Increment(ref s_seedCounter); ulong seed = (ulong)Interlocked.Increment(ref s_seedCounter);
@@ -18,7 +18,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
private ulong _currentMontgomery = divisor.MontgomeryOne; private ulong _currentMontgomery = divisor.MontgomeryOne;
private static readonly ConcurrentDictionary<(ulong Cycle, ulong Delta), ulong> _cycleDeltaCache = new(); private static readonly ConcurrentDictionary<(ulong Cycle, ulong Delta), ulong> _cycleDeltaCache = new();
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public readonly bool MatchesDivisor(in MontgomeryDivisorData divisor, ulong cycleLength) public readonly bool MatchesDivisor(in MontgomeryDivisorData divisor, ulong cycleLength)
=> _modulus == divisor.Modulus && _nPrime == divisor.NPrime && _montgomeryOne == divisor.MontgomeryOne && _cycleLength == cycleLength; => _modulus == divisor.Modulus && _nPrime == divisor.NPrime && _montgomeryOne == divisor.MontgomeryOne && _cycleLength == cycleLength;
@@ -26,7 +26,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
/// Clears the cached Montgomery residue so the stepper can be reused for another divisor. /// Clears the cached Montgomery residue so the stepper can be reused for another divisor.
/// Callers must reinitialize the stepper before consuming any residues after a reset. /// Callers must reinitialize the stepper before consuming any residues after a reset.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public void Reset() public void Reset()
{ {
PreviousExponent = 0UL; PreviousExponent = 0UL;
@@ -39,7 +39,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
/// </summary> /// </summary>
/// <param name="exponent">First exponent evaluated for the current divisor. The caller must reuse the same divisor metadata.</param> /// <param name="exponent">First exponent evaluated for the current divisor. The caller must reuse the same divisor metadata.</param>
/// <returns>The canonical residue produced by <c>2^exponent mod divisor</c>.</returns> /// <returns>The canonical residue produced by <c>2^exponent mod divisor</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public ulong InitializeCpu(ulong exponent) public ulong InitializeCpu(ulong exponent)
{ {
InitializeCpuState(exponent); InitializeCpuState(exponent);
@@ -51,7 +51,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
/// </summary> /// </summary>
/// <param name="exponent">First exponent evaluated for the current divisor. Must match the divisor passed to the constructor.</param> /// <param name="exponent">First exponent evaluated for the current divisor. Must match the divisor passed to the constructor.</param>
/// <returns><see langword="true"/> when the seed exponent produces a Montgomery residue equal to one.</returns> /// <returns><see langword="true"/> when the seed exponent produces a Montgomery residue equal to one.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public bool InitializeCpuIsUnity(ulong exponent) public bool InitializeCpuIsUnity(ulong exponent)
{ {
InitializeCpuState(exponent); InitializeCpuState(exponent);
@@ -64,7 +64,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
/// </summary> /// </summary>
/// <param name="exponent">Next exponent in the ascending sequence. Callers must never move backwards or reuse an older exponent.</param> /// <param name="exponent">Next exponent in the ascending sequence. Callers must never move backwards or reuse an older exponent.</param>
/// <returns>The canonical residue produced by <c>2^exponent mod divisor</c>.</returns> /// <returns>The canonical residue produced by <c>2^exponent mod divisor</c>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public ulong ComputeNextCpu(ulong exponent) public ulong ComputeNextCpu(ulong exponent)
{ {
ulong delta = exponent - PreviousExponent; ulong delta = exponent - PreviousExponent;
@@ -84,7 +84,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
/// </summary> /// </summary>
/// <param name="exponent">Next exponent in the ascending sequence.</param> /// <param name="exponent">Next exponent in the ascending sequence.</param>
/// <returns><see langword="true"/> when the canonical residue equals one.</returns> /// <returns><see langword="true"/> when the canonical residue equals one.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public bool ComputeNextIsUnity(ulong exponent) public bool ComputeNextIsUnity(ulong exponent)
{ {
ulong delta = exponent - PreviousExponent; ulong delta = exponent - PreviousExponent;
@@ -105,7 +105,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
/// <param name="montgomeryResult">Residue in Montgomery form produced externally for the configured divisor.</param> /// <param name="montgomeryResult">Residue in Montgomery form produced externally for the configured divisor.</param>
/// <param name="isUnity">Outputs whether the supplied residue equals Montgomery one.</param> /// <param name="isUnity">Outputs whether the supplied residue equals Montgomery one.</param>
/// <returns><see langword="true"/> when the residue is accepted and cached.</returns> /// <returns><see langword="true"/> when the residue is accepted and cached.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public bool TryInitializeFromMontgomeryResult(ulong exponent, ulong montgomeryResult, out bool isUnity) public bool TryInitializeFromMontgomeryResult(ulong exponent, ulong montgomeryResult, out bool isUnity)
{ {
_currentMontgomery = montgomeryResult; _currentMontgomery = montgomeryResult;
@@ -122,7 +122,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
/// <param name="montgomeryDelta">Montgomery residue delta corresponding to the exponent gap.</param> /// <param name="montgomeryDelta">Montgomery residue delta corresponding to the exponent gap.</param>
/// <param name="isUnity">Outputs whether the resulting residue equals Montgomery one.</param> /// <param name="isUnity">Outputs whether the resulting residue equals Montgomery one.</param>
/// <returns><see langword="true"/> when the advance succeeds.</returns> /// <returns><see langword="true"/> when the advance succeeds.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public bool TryAdvanceWithMontgomeryDelta(ulong exponent, ulong montgomeryDelta, out bool isUnity) public bool TryAdvanceWithMontgomeryDelta(ulong exponent, ulong montgomeryDelta, out bool isUnity)
{ {
ulong delta = exponent - PreviousExponent; ulong delta = exponent - PreviousExponent;
@@ -149,7 +149,7 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private void InitializeCpuState(ulong exponent) private void InitializeCpuState(ulong exponent)
{ {
ulong rotation = ReduceDelta(exponent); ulong rotation = ReduceDelta(exponent);
@@ -159,10 +159,10 @@ internal struct ExponentRemainderStepperCpu(in MontgomeryDivisorData divisor, ul
PreviousExponent = exponent; PreviousExponent = exponent;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private readonly ulong ReduceCurrent() => _currentMontgomery.MontgomeryMultiplyCpu(1UL, _modulus, _nPrime); private readonly ulong ReduceCurrent() => _currentMontgomery.MontgomeryMultiplyCpu(1UL, _modulus, _nPrime);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private readonly ulong ReduceDelta(ulong delta) private readonly ulong ReduceDelta(ulong delta)
{ {
ulong cycleLength = _cycleLength; ulong cycleLength = _cycleLength;
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using ILGPU; using ILGPU;
using ILGPU.Runtime; using ILGPU.Runtime;
@@ -9,10 +10,13 @@ internal readonly struct HeuristicCombinedGpuTables
private static readonly HeuristicCombinedGpuTables[] _sharedTables = new HeuristicCombinedGpuTables[PerfectNumberConstants.RollingAccelerators]; private static readonly HeuristicCombinedGpuTables[] _sharedTables = new HeuristicCombinedGpuTables[PerfectNumberConstants.RollingAccelerators];
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal static void WarmUp(int acceleratorIndex, AcceleratorStream stream) => _sharedTables[acceleratorIndex] = new(_accelerators[acceleratorIndex], stream); internal static void WarmUp(int acceleratorIndex, AcceleratorStream stream) => _sharedTables[acceleratorIndex] = new(_accelerators[acceleratorIndex], stream);
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static HeuristicCombinedGpuTables GetStaticTables(int acceleratorIndex) => _sharedTables[acceleratorIndex]; internal static HeuristicCombinedGpuTables GetStaticTables(int acceleratorIndex) => _sharedTables[acceleratorIndex];
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal HeuristicCombinedGpuTables(Accelerator accelerator, AcceleratorStream stream) internal HeuristicCombinedGpuTables(Accelerator accelerator, AcceleratorStream stream)
{ {
var combinedEnding1 = HeuristicCombinedPrimeTester.CombinedDivisorsEnding1; var combinedEnding1 = HeuristicCombinedPrimeTester.CombinedDivisorsEnding1;
@@ -45,6 +49,7 @@ internal readonly struct HeuristicCombinedGpuTables
internal readonly MemoryBuffer1D<ulong, Stride1D.Dense> HeuristicCombinedDivisorsEnding9; internal readonly MemoryBuffer1D<ulong, Stride1D.Dense> HeuristicCombinedDivisorsEnding9;
internal readonly MemoryBuffer1D<ulong, Stride1D.Dense> HeuristicCombinedDivisorSquaresEnding9; internal readonly MemoryBuffer1D<ulong, Stride1D.Dense> HeuristicCombinedDivisorSquaresEnding9;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal HeuristicCombinedGpuViews CreateViews() => new( internal HeuristicCombinedGpuViews CreateViews() => new(
HeuristicCombinedDivisorsEnding1.View, HeuristicCombinedDivisorsEnding1.View,
HeuristicCombinedDivisorsEnding3.View, HeuristicCombinedDivisorsEnding3.View,
@@ -55,6 +60,7 @@ internal readonly struct HeuristicCombinedGpuTables
HeuristicCombinedDivisorSquaresEnding7.View, HeuristicCombinedDivisorSquaresEnding7.View,
HeuristicCombinedDivisorSquaresEnding9.View); HeuristicCombinedDivisorSquaresEnding9.View);
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal void Dispose() internal void Dispose()
{ {
HeuristicCombinedDivisorsEnding1.Dispose(); HeuristicCombinedDivisorsEnding1.Dispose();
@@ -195,6 +195,7 @@ public sealed class PrimeOrderCalculatorAccelerator
public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> SmallPrimeSieveKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> SmallPrimeSieveKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ulong, ArrayView<ulong>, int, ulong, ArrayView<ulong>> SpecialMaxKernelLauncher; public readonly Action<AcceleratorStream, Index1D, ulong, ArrayView<ulong>, int, ulong, ArrayView<ulong>> SpecialMaxKernelLauncher;
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public void EnsureCalculateOrderWideCapacity(int newSize) public void EnsureCalculateOrderWideCapacity(int newSize)
{ {
if (newSize > Input.Length) if (newSize > Input.Length)
@@ -213,6 +214,7 @@ public sealed class PrimeOrderCalculatorAccelerator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public void EnsureCapacity(int factorsCount, int primeTesterCapacity) public void EnsureCapacity(int factorsCount, int primeTesterCapacity)
{ {
Accelerator accelerator = Accelerator; Accelerator accelerator = Accelerator;
@@ -325,6 +327,7 @@ public sealed class PrimeOrderCalculatorAccelerator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public void EnsureUlongInputOutputCapacity(int newSize) public void EnsureUlongInputOutputCapacity(int newSize)
{ {
var accelerator = Accelerator; var accelerator = Accelerator;
+2
View File
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using ILGPU; using ILGPU;
using ILGPU.Runtime; using ILGPU.Runtime;
using PerfectNumbers.Core.Gpu.Accelerators; using PerfectNumbers.Core.Gpu.Accelerators;
@@ -74,6 +75,7 @@ public class GpuKernelPool
}); });
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
static void InitPow2ModKernelScan(Accelerator accelerator, KernelContainer kernels) static void InitPow2ModKernelScan(Accelerator accelerator, KernelContainer kernels)
{ {
InitOnce(ref kernels.Pow2Mod, () => InitOnce(ref kernels.Pow2Mod, () =>
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using ILGPU; using ILGPU;
using ILGPU.Runtime; using ILGPU.Runtime;
@@ -6,6 +7,7 @@ namespace PerfectNumbers.Core.Gpu;
internal static class Pow2ModKernels internal static class Pow2ModKernels
{ {
/// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers. /// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers.
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void Pow2ModKernelScan( public static void Pow2ModKernelScan(
Index1D index, Index1D index,
ulong exponent, ulong exponent,
@@ -107,6 +109,7 @@ internal static class Pow2ModKernels
/// This kernel doesn't always set the result of the found array. It sets the value only when it needs to. The callers /// This kernel doesn't always set the result of the found array. It sets the value only when it needs to. The callers
/// must clean the output buffer before the call to get a deterministic result. /// must clean the output buffer before the call to get a deterministic result.
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void Pow2ModOrderKernelScan( public static void Pow2ModOrderKernelScan(
Index1D index, Index1D index,
ulong exponent, ulong exponent,
@@ -117,7 +117,7 @@ public static class Pow2MontgomeryKernels
return sumHigh; return sumHigh;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
private static void MultiplyPartsGpu(ulong left, ulong right, out ulong high, out ulong low) private static void MultiplyPartsGpu(ulong left, ulong right, out ulong high, out ulong low)
{ {
ulong leftLow = (uint)left; ulong leftLow = (uint)left;
@@ -135,13 +135,13 @@ public static class Pow2MontgomeryKernels
high = unchecked(highProduct + (cross1 >> 32) + (cross2 >> 32) + (carry >> 32)); high = unchecked(highProduct + (cross1 >> 32) + (cross2 >> 32) + (carry >> 32));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static ulong Pow2MontgomeryModWindowedGpuKeepMontgomery(in MontgomeryDivisorDataGpu divisor, ulong exponent) internal static ulong Pow2MontgomeryModWindowedGpuKeepMontgomery(in MontgomeryDivisorDataGpu divisor, ulong exponent)
{ {
return Pow2MontgomeryModWindowedGpuMontgomeryResult(divisor, exponent); return Pow2MontgomeryModWindowedGpuMontgomeryResult(divisor, exponent);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModWindowedGpuConvertToStandard(this MontgomeryDivisorDataGpu divisor, ulong exponent) public static ulong Pow2MontgomeryModWindowedGpuConvertToStandard(this MontgomeryDivisorDataGpu divisor, ulong exponent)
{ {
ulong modulus = divisor.Modulus; ulong modulus = divisor.Modulus;
@@ -150,7 +150,7 @@ public static class Pow2MontgomeryKernels
return MontgomeryMultiplyGpu(montgomeryResult, 1UL, modulus, nPrime); return MontgomeryMultiplyGpu(montgomeryResult, 1UL, modulus, nPrime);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong Pow2MontgomeryModWindowedGpuMontgomeryResult(in MontgomeryDivisorDataGpu divisor, ulong exponent) private static ulong Pow2MontgomeryModWindowedGpuMontgomeryResult(in MontgomeryDivisorDataGpu divisor, ulong exponent)
{ {
ulong modulus = divisor.Modulus; ulong modulus = divisor.Modulus;
@@ -1182,6 +1182,7 @@ internal static partial class PrimeOrderKernels
return divisor.Pow2MontgomeryModWindowedGpuConvertToStandard(exponent) == 1UL; return divisor.Pow2MontgomeryModWindowedGpuConvertToStandard(exponent) == 1UL;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong CalculateByDoublingKernel(ulong prime) private static ulong CalculateByDoublingKernel(ulong prime)
{ {
ulong order = 1UL; ulong order = 1UL;
@@ -1203,6 +1204,7 @@ internal static partial class PrimeOrderKernels
/// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers. /// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers.
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal static void Pow2ModKernel(Index1D index, ArrayView1D<ulong, Stride1D.Dense> exponents, ulong divisorModulus, ulong divisorNPrime, ulong divisorMontgomeryOne, ulong divisorMontgomeryTwo, ulong divisorMontgomeryTwoSquared, ArrayView1D<ulong, Stride1D.Dense> remainders) internal static void Pow2ModKernel(Index1D index, ArrayView1D<ulong, Stride1D.Dense> exponents, ulong divisorModulus, ulong divisorNPrime, ulong divisorMontgomeryOne, ulong divisorMontgomeryTwo, ulong divisorMontgomeryTwoSquared, ArrayView1D<ulong, Stride1D.Dense> remainders)
{ {
ulong exponent = exponents[index]; ulong exponent = exponents[index];
@@ -1211,12 +1213,14 @@ internal static partial class PrimeOrderKernels
} }
/// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers. /// This kernel always sets the result of the corresponding element. Callers don't need to clear the output buffers.
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal static void Pow2ModKernelWide(Index1D index, ArrayView1D<GpuUInt128, Stride1D.Dense> exponents, GpuUInt128 modulus, ArrayView1D<GpuUInt128, Stride1D.Dense> remainders) internal static void Pow2ModKernelWide(Index1D index, ArrayView1D<GpuUInt128, Stride1D.Dense> exponents, GpuUInt128 modulus, ArrayView1D<GpuUInt128, Stride1D.Dense> remainders)
{ {
GpuUInt128 exponent = exponents[index]; GpuUInt128 exponent = exponents[index];
remainders[index] = Pow2ModKernelCore(exponent, modulus); remainders[index] = Pow2ModKernelCore(exponent, modulus);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static GpuUInt128[] InitializeOddPowersTable(GpuUInt128 baseValue, GpuUInt128 modulus, int oddPowerCount) private static GpuUInt128[] InitializeOddPowersTable(GpuUInt128 baseValue, GpuUInt128 modulus, int oddPowerCount)
{ {
GpuUInt128[] result = new GpuUInt128[PerfectNumberConstants.MaxOddPowersCount]; GpuUInt128[] result = new GpuUInt128[PerfectNumberConstants.MaxOddPowersCount];
@@ -1242,6 +1246,7 @@ internal static partial class PrimeOrderKernels
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal static GpuUInt128 Pow2ModKernelCore(GpuUInt128 exponent, GpuUInt128 modulus) internal static GpuUInt128 Pow2ModKernelCore(GpuUInt128 exponent, GpuUInt128 modulus)
{ {
// This should never happen in production code. // This should never happen in production code.
@@ -23,6 +23,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
// requested by the caller, skip queuing additional block generation, and keep the snapshot cache untouched. // requested by the caller, skip queuing additional block generation, and keep the snapshot cache untouched.
// GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1. // GPU residue variant: check 2^p % q == 1 for q = 2*p*k + 1.
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public void Scan(PrimeOrderCalculatorAccelerator gpu, ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime) public void Scan(PrimeOrderCalculatorAccelerator gpu, ulong exponent, UInt128 twoP, LastDigit lastDigit, UInt128 maxK, ref bool isPrime)
{ {
// GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
@@ -114,6 +115,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
// GpuPrimeWorkLimiter.Release(); // GpuPrimeWorkLimiter.Release();
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> GetPow2ModKernel(Accelerator accelerator) private static Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> GetPow2ModKernel(Accelerator accelerator)
{ {
@@ -128,6 +130,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
return cached; return cached;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> CreatePow2ModKernel(Accelerator accelerator) private static Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> CreatePow2ModKernel(Accelerator accelerator)
{ {
var loaded = accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2ModKernels.Pow2ModKernelScan); var loaded = accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<ulong>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2ModKernels.Pow2ModKernelScan);
@@ -140,6 +143,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ResidueResources RentResources(Accelerator accelerator, int capacity) private static ResidueResources RentResources(Accelerator accelerator, int capacity)
{ {
var resourcePools = _resourcePools ??= new(); var resourcePools = _resourcePools ??= new();
@@ -152,6 +156,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
return new ResidueResources(accelerator, capacity); return new ResidueResources(accelerator, capacity);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void ReturnResources(ResidueResources resources) private static void ReturnResources(ResidueResources resources)
{ {
var resourcePools = _resourcePools ??= new(); var resourcePools = _resourcePools ??= new();
@@ -160,6 +165,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
private sealed class ResidueResources private sealed class ResidueResources
{ {
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal ResidueResources(Accelerator accelerator, int capacity) internal ResidueResources(Accelerator accelerator, int capacity)
{ {
Capacity = Math.Max(1, capacity); Capacity = Math.Max(1, capacity);
@@ -171,6 +177,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
OrderArray = ThreadStaticPools.UlongPool.Rent(Capacity); OrderArray = ThreadStaticPools.UlongPool.Rent(Capacity);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal void EnsureCapacity(Accelerator accelerator, int capacity) internal void EnsureCapacity(Accelerator accelerator, int capacity)
{ {
if (OrderBuffer.Length >= capacity) if (OrderBuffer.Length >= capacity)
@@ -7,7 +7,7 @@ namespace PerfectNumbers.Core.Gpu;
public static class Pow2MontgomeryGpuCalculator public static class Pow2MontgomeryGpuCalculator
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong CalculateKeep(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor) public static ulong CalculateKeep(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor)
{ {
// GpuPrimeWorkLimiter.Acquire(); // GpuPrimeWorkLimiter.Acquire();
@@ -34,7 +34,7 @@ public static class Pow2MontgomeryGpuCalculator
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong CalculateConvert(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor) public static ulong CalculateConvert(PrimeOrderCalculatorAccelerator gpu, ulong exponent, in MontgomeryDivisorData divisor)
{ {
ulong result = 0UL; ulong result = 0UL;
@@ -1,5 +1,6 @@
using System.Buffers; using System.Buffers;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using ILGPU.Runtime; using ILGPU.Runtime;
using PerfectNumbers.Core.Gpu.Accelerators; using PerfectNumbers.Core.Gpu.Accelerators;
@@ -16,6 +17,7 @@ internal enum GpuPow2ModStatus
internal static partial class PrimeOrderGpuHeuristics internal static partial class PrimeOrderGpuHeuristics
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static void PreloadStaticTables(AcceleratorStream stream) internal static void PreloadStaticTables(AcceleratorStream stream)
{ {
// _ = GetSmallPrimeDeviceCache(stream); // _ = GetSmallPrimeDeviceCache(stream);
@@ -31,16 +33,19 @@ internal static partial class PrimeOrderGpuHeuristics
internal static ConcurrentDictionary<ulong, byte> OverflowRegistry => OverflowedPrimes; internal static ConcurrentDictionary<ulong, byte> OverflowRegistry => OverflowedPrimes;
internal static ConcurrentDictionary<UInt128, byte> OverflowRegistryWide => OverflowedPrimesWide; internal static ConcurrentDictionary<UInt128, byte> OverflowRegistryWide => OverflowedPrimesWide;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static void OverrideCapabilitiesForTesting(PrimeOrderGpuCapability capability) internal static void OverrideCapabilitiesForTesting(PrimeOrderGpuCapability capability)
{ {
s_capability = capability; s_capability = capability;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static void ResetCapabilitiesForTesting() internal static void ResetCapabilitiesForTesting()
{ {
s_capability = PrimeOrderGpuCapability.Default; s_capability = PrimeOrderGpuCapability.Default;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static bool TryPartialFactor( public static bool TryPartialFactor(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong value, ulong value,
@@ -88,6 +93,7 @@ internal static partial class PrimeOrderGpuHeuristics
private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators; private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators;
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryLaunchPartialFactorKernel( private static bool TryLaunchPartialFactorKernel(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong value, ulong value,
@@ -156,6 +162,7 @@ internal static partial class PrimeOrderGpuHeuristics
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static GpuPow2ModStatus TryPow2Mod(PrimeOrderCalculatorAccelerator gpu, ulong exponent, ulong prime, out ulong remainder, in MontgomeryDivisorData? divisorData) public static GpuPow2ModStatus TryPow2Mod(PrimeOrderCalculatorAccelerator gpu, ulong exponent, ulong prime, out ulong remainder, in MontgomeryDivisorData? divisorData)
{ {
Span<ulong> exponents = stackalloc ulong[1]; Span<ulong> exponents = stackalloc ulong[1];
@@ -167,6 +174,7 @@ internal static partial class PrimeOrderGpuHeuristics
return status; return status;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static GpuPow2ModStatus TryPow2ModBatch(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<ulong> exponents, ulong prime, Span<ulong> remainders, in MontgomeryDivisorData? divisorData) public static GpuPow2ModStatus TryPow2ModBatch(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<ulong> exponents, ulong prime, Span<ulong> remainders, in MontgomeryDivisorData? divisorData)
{ {
// This will never occur in production code // This will never occur in production code
@@ -222,6 +230,7 @@ internal static partial class PrimeOrderGpuHeuristics
return computed ? GpuPow2ModStatus.Success : GpuPow2ModStatus.Unavailable; return computed ? GpuPow2ModStatus.Success : GpuPow2ModStatus.Unavailable;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static GpuPow2ModStatus TryPow2Mod(PrimeOrderCalculatorAccelerator gpu, in UInt128 exponent, in UInt128 prime, out UInt128 remainder) public static GpuPow2ModStatus TryPow2Mod(PrimeOrderCalculatorAccelerator gpu, in UInt128 exponent, in UInt128 prime, out UInt128 remainder)
{ {
Span<UInt128> exponents = stackalloc UInt128[1]; Span<UInt128> exponents = stackalloc UInt128[1];
@@ -233,11 +242,13 @@ internal static partial class PrimeOrderGpuHeuristics
return status; return status;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static GpuPow2ModStatus TryPow2ModBatch(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<UInt128> exponents, UInt128 prime, Span<UInt128> remainders) public static GpuPow2ModStatus TryPow2ModBatch(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<UInt128> exponents, UInt128 prime, Span<UInt128> remainders)
{ {
return TryPow2ModBatchInternal(gpu, exponents, prime, remainders); return TryPow2ModBatchInternal(gpu, exponents, prime, remainders);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
internal static bool TryCalculateOrder( internal static bool TryCalculateOrder(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong prime, ulong prime,
@@ -310,6 +321,7 @@ internal static partial class PrimeOrderGpuHeuristics
return order != 0UL; return order != 0UL;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static GpuPow2ModStatus TryPow2ModBatchInternal(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<UInt128> exponents, UInt128 prime, Span<UInt128> remainders) private static GpuPow2ModStatus TryPow2ModBatchInternal(PrimeOrderCalculatorAccelerator gpu, ReadOnlySpan<UInt128> exponents, UInt128 prime, Span<UInt128> remainders)
{ {
if (exponents.Length == 0) if (exponents.Length == 0)
@@ -41,6 +41,7 @@ public sealed class HeuristicCombinedPrimeTester
CombinedDivisorsEnding9Squares = CombinedDivisorsEnding9OneAOneBSquares; CombinedDivisorsEnding9Squares = CombinedDivisorsEnding9OneAOneBSquares;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void EnsureInitialized() public static void EnsureInitialized()
{ {
// Intentionally left blank. Accessing this method forces the static constructor to run. // Intentionally left blank. Accessing this method forces the static constructor to run.
@@ -155,9 +156,10 @@ public sealed class HeuristicCombinedPrimeTester
public static HeuristicCombinedPrimeTester Exclusive => _tester ??= new(); public static HeuristicCombinedPrimeTester Exclusive => _tester ??= new();
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static bool IsPrimeCpu(ulong n) public static bool IsPrimeCpu(ulong n)
{ {
byte nMod10 = (byte)n.Mod10(); byte nMod10 = n.Mod10();
ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n); ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n);
if (maxDivisorSquare < 9UL) if (maxDivisorSquare < 9UL)
@@ -168,13 +170,15 @@ public sealed class HeuristicCombinedPrimeTester
return HeuristicTrialDivisionCpu(n, maxDivisorSquare, nMod10); return HeuristicTrialDivisionCpu(n, maxDivisorSquare, nMod10);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n) public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n)
{ {
byte nMod10 = (byte)n.Mod10(); byte nMod10 = n.Mod10();
ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n); ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n);
return IsPrimeGpu(gpu, n, maxDivisorSquare, nMod10); return IsPrimeGpu(gpu, n, maxDivisorSquare, nMod10);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n, ulong maxDivisorSquare, byte nMod10) public static bool IsPrimeGpu(PrimeOrderCalculatorAccelerator gpu, ulong n, ulong maxDivisorSquare, byte nMod10)
{ {
// TODO: Is this condition ever met on the execution path in EvenPerfectBitScanner? // TODO: Is this condition ever met on the execution path in EvenPerfectBitScanner?
@@ -187,6 +191,7 @@ public sealed class HeuristicCombinedPrimeTester
return !compositeDetected; return !compositeDetected;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool HeuristicTrialDivisionCpu(ulong n, ulong maxDivisorSquare, byte nMod10) private static bool HeuristicTrialDivisionCpu(ulong n, ulong maxDivisorSquare, byte nMod10)
{ {
ReadOnlySpan<ulong> combinedDivisors = GetCombinedDivisors(nMod10); ReadOnlySpan<ulong> combinedDivisors = GetCombinedDivisors(nMod10);
@@ -211,7 +216,7 @@ public sealed class HeuristicCombinedPrimeTester
return EvaluateWithOpenNumericFallback(n); return EvaluateWithOpenNumericFallback(n);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static int GetBatchSize(ulong n) => n switch internal static int GetBatchSize(ulong n) => n switch
{ {
< 1_000 => 8, < 1_000 => 8,
@@ -222,6 +227,7 @@ public sealed class HeuristicCombinedPrimeTester
}; };
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool HeuristicTrialDivisionGpuDetectsDivisor(PrimeOrderCalculatorAccelerator gpu, ulong n, ulong maxDivisorSquare, byte nMod10) private static bool HeuristicTrialDivisionGpuDetectsDivisor(PrimeOrderCalculatorAccelerator gpu, ulong n, ulong maxDivisorSquare, byte nMod10)
{ {
var acceleratorIndex = gpu.AcceleratorIndex; var acceleratorIndex = gpu.AcceleratorIndex;
@@ -254,13 +260,13 @@ public sealed class HeuristicCombinedPrimeTester
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static bool EvaluateWithOpenNumericFallback(ulong n) => Prime.Numbers.IsPrime(n); private static bool EvaluateWithOpenNumericFallback(ulong n) => Prime.Numbers.IsPrime(n);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n) => n; internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n) => n;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10) => nMod10 switch private static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10) => nMod10 switch
{ {
1 => CombinedDivisorsEnding1, 1 => CombinedDivisorsEnding1,
@@ -270,7 +276,7 @@ public sealed class HeuristicCombinedPrimeTester
_ => throw new InvalidOperationException($"Unsupported combined divisor selector for digit {nMod10}."), _ => throw new InvalidOperationException($"Unsupported combined divisor selector for digit {nMod10}."),
}; };
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ReadOnlySpan<ulong> GetCombinedDivisorSquares(byte nMod10) => nMod10 switch private static ReadOnlySpan<ulong> GetCombinedDivisorSquares(byte nMod10) => nMod10 switch
{ {
1 => CombinedDivisorsEnding1Squares, 1 => CombinedDivisorsEnding1Squares,
@@ -280,7 +286,7 @@ public sealed class HeuristicCombinedPrimeTester
_ => throw new InvalidOperationException($"Unsupported combined divisor square selector for digit {nMod10}."), _ => throw new InvalidOperationException($"Unsupported combined divisor square selector for digit {nMod10}."),
}; };
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern) => pattern switch internal static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern) => pattern switch
{ {
CombinedDivisorPattern.TwoAOneB => nMod10 switch CombinedDivisorPattern.TwoAOneB => nMod10 switch
@@ -318,7 +324,7 @@ public sealed class HeuristicCombinedPrimeTester
_ => throw new InvalidOperationException($"Unsupported combined divisor pattern: {pattern}."), _ => throw new InvalidOperationException($"Unsupported combined divisor pattern: {pattern}."),
}; };
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static ReadOnlySpan<ulong> GetCombinedDivisorSquares(byte nMod10, CombinedDivisorPattern pattern) => pattern switch internal static ReadOnlySpan<ulong> GetCombinedDivisorSquares(byte nMod10, CombinedDivisorPattern pattern) => pattern switch
{ {
CombinedDivisorPattern.TwoAOneB => nMod10 switch CombinedDivisorPattern.TwoAOneB => nMod10 switch
@@ -428,6 +434,7 @@ public sealed class HeuristicCombinedPrimeTester
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static int GetGroupBStartIndex(ReadOnlySpan<uint> divisors) private static int GetGroupBStartIndex(ReadOnlySpan<uint> divisors)
{ {
int index = 0; int index = 0;
@@ -439,8 +446,10 @@ public sealed class HeuristicCombinedPrimeTester
return index; return index;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static bool IsGroupAPrefixValue(ulong value) => value is 3UL or 7UL or 11UL or 13UL; private static bool IsGroupAPrefixValue(ulong value) => value is 3UL or 7UL or 11UL or 13UL;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static HeuristicDivisorGroup ResolveGroup(ulong value) => value switch private static HeuristicDivisorGroup ResolveGroup(ulong value) => value switch
{ {
3UL or 7UL or 11UL or 13UL => HeuristicDivisorGroup.GroupAConstant, 3UL or 7UL or 11UL or 13UL => HeuristicDivisorGroup.GroupAConstant,
@@ -448,6 +457,7 @@ public sealed class HeuristicCombinedPrimeTester
_ => HeuristicDivisorGroup.GroupB, _ => HeuristicDivisorGroup.GroupB,
}; };
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ReadOnlySpan<uint> GetGroupBDivisors(byte ending) => ending switch private static ReadOnlySpan<uint> GetGroupBDivisors(byte ending) => ending switch
{ {
1 => DivisorGenerator.SmallPrimesLastOneWithoutLastThree, 1 => DivisorGenerator.SmallPrimesLastOneWithoutLastThree,
@@ -457,19 +467,19 @@ public sealed class HeuristicCombinedPrimeTester
_ => [], _ => [],
}; };
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer) internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10)
=> new(maxDivisorSquare, nMod10, groupBBuffer); => new(maxDivisorSquare, nMod10);
internal struct HeuristicGroupBSequenceState internal struct HeuristicGroupBSequenceState
{ {
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static MersenneHeuristicDivisorEnumerator CreateMersenneDivisorEnumerator(ulong exponent, ulong maxDivisor) internal static MersenneHeuristicDivisorEnumerator CreateMersenneDivisorEnumerator(ulong exponent, ulong maxDivisor)
=> new(exponent, maxDivisor); => new(exponent, maxDivisor);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate) internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
{ {
ulong divisor = candidate.Value; ulong divisor = candidate.Value;
@@ -478,7 +488,7 @@ public sealed class HeuristicCombinedPrimeTester
return new(candidate, divisorData, cycleLength, hasCycleHint); return new(candidate, divisorData, cycleLength, hasCycleHint);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static ulong ResolveHeuristicCycleLengthCpu( internal static ulong ResolveHeuristicCycleLengthCpu(
ulong exponent, ulong exponent,
in HeuristicDivisorPreparation preparation, in HeuristicDivisorPreparation preparation,
@@ -519,7 +529,7 @@ public sealed class HeuristicCombinedPrimeTester
return resolvedCycle; return resolvedCycle;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static ulong ResolveHeuristicCycleLengthGpu( internal static ulong ResolveHeuristicCycleLengthGpu(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong exponent, ulong exponent,
@@ -561,7 +571,7 @@ public sealed class HeuristicCombinedPrimeTester
return resolvedCycle; return resolvedCycle;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
internal static bool TryGetCycleLengthHint(ulong divisor, out ulong cycleLength) internal static bool TryGetCycleLengthHint(ulong divisor, out ulong cycleLength)
{ {
ulong[] snapshot = HeuristicSmallCycleSnapshot; ulong[] snapshot = HeuristicSmallCycleSnapshot;
@@ -578,35 +588,26 @@ public sealed class HeuristicCombinedPrimeTester
return false; return false;
} }
internal ref struct HeuristicDivisorEnumerator internal ref struct HeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10)
{ {
private readonly ulong maxDivisorSquare; private readonly ulong _maxDivisorSquare = maxDivisorSquare;
private readonly ReadOnlySpan<ulong> combinedDivisors; private readonly ReadOnlySpan<ulong> _combinedDivisors = GetCombinedDivisors(nMod10);
private readonly ReadOnlySpan<ulong> combinedDivisorSquares; private readonly ReadOnlySpan<ulong> _combinedDivisorSquares = GetCombinedDivisorSquares(nMod10);
private int index; private int index = 0;
public HeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer)
{
this.maxDivisorSquare = maxDivisorSquare;
_ = groupBBuffer;
combinedDivisors = GetCombinedDivisors(nMod10);
combinedDivisorSquares = GetCombinedDivisorSquares(nMod10);
index = 0;
}
public bool TryGetNext(out HeuristicDivisorCandidate candidate) public bool TryGetNext(out HeuristicDivisorCandidate candidate)
{ {
while (index < combinedDivisors.Length) while (index < _combinedDivisors.Length)
{ {
int currentIndex = index; int currentIndex = index;
ulong divisorSquare = combinedDivisorSquares[currentIndex]; ulong divisorSquare = _combinedDivisorSquares[currentIndex];
if (divisorSquare > maxDivisorSquare) if (divisorSquare > _maxDivisorSquare)
{ {
index = combinedDivisors.Length; index = _combinedDivisors.Length;
break; break;
} }
ulong entry = combinedDivisors[currentIndex]; ulong entry = _combinedDivisors[currentIndex];
index = currentIndex + 1; index = currentIndex + 1;
HeuristicDivisorGroup group = ResolveGroup(entry); HeuristicDivisorGroup group = ResolveGroup(entry);
@@ -629,8 +630,6 @@ public sealed class HeuristicCombinedPrimeTester
private GpuUInt128 current; private GpuUInt128 current;
private MersenneDivisorResidueStepper residueStepper; private MersenneDivisorResidueStepper residueStepper;
private bool active; private bool active;
private ulong processedCount;
private ulong lastDivisor;
public MersenneHeuristicDivisorEnumerator(ulong exponent, ulong maxDivisor) public MersenneHeuristicDivisorEnumerator(ulong exponent, ulong maxDivisor)
{ {
@@ -649,8 +648,6 @@ public sealed class HeuristicCombinedPrimeTester
current = hasCandidates ? firstDivisor : GpuUInt128.Zero; current = hasCandidates ? firstDivisor : GpuUInt128.Zero;
residueStepper = hasCandidates ? new MersenneDivisorResidueStepper(exponent, stepLocal, firstDivisor) : default; residueStepper = hasCandidates ? new MersenneDivisorResidueStepper(exponent, stepLocal, firstDivisor) : default;
active = hasCandidates; active = hasCandidates;
processedCount = 0UL;
lastDivisor = 0UL;
} }
public bool TryGetNext(out HeuristicDivisorCandidate candidate) public bool TryGetNext(out HeuristicDivisorCandidate candidate)
@@ -658,9 +655,6 @@ public sealed class HeuristicCombinedPrimeTester
while (active) while (active)
{ {
ulong value = current.Low; ulong value = current.Low;
processedCount++;
lastDivisor = value;
bool admissible = residueStepper.IsAdmissible(); bool admissible = residueStepper.IsAdmissible();
Advance(); Advance();
@@ -691,12 +685,6 @@ public sealed class HeuristicCombinedPrimeTester
residueStepper.Advance(); residueStepper.Advance();
} }
public readonly ulong ProcessedCount => processedCount;
public readonly ulong LastDivisor => lastDivisor;
public readonly bool Exhausted => !active;
private static HeuristicDivisorCandidate CreateCandidate(ulong value) private static HeuristicDivisorCandidate CreateCandidate(ulong value)
{ {
byte ending = (byte)(value % 10UL); byte ending = (byte)(value % 10UL);
@@ -60,6 +60,7 @@ public static class MontgomeryDivisorDataPool
montgomeryTwoSquared); montgomeryTwoSquared);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MontgomeryDivisorData Rent(this Queue<MontgomeryDivisorData> queue, ulong modulus, ulong nPrime, ulong montgomeryOne, ulong montgomeryTwo, ulong montgomeryTwoSquared) public static MontgomeryDivisorData Rent(this Queue<MontgomeryDivisorData> queue, ulong modulus, ulong nPrime, ulong montgomeryOne, ulong montgomeryTwo, ulong montgomeryTwoSquared)
{ {
if (queue.TryDequeue(out var pooled)) if (queue.TryDequeue(out var pooled))
+153 -121
View File
@@ -18,7 +18,7 @@ internal static partial class PrimeOrderCalculator
private static PendingEntry? _poolHead; private static PendingEntry? _poolHead;
private PendingEntry? _next; private PendingEntry? _next;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static PendingEntry Rent(ulong value, bool knownComposite) public static PendingEntry Rent(ulong value, bool knownComposite)
{ {
var poolHead = _poolHead; var poolHead = _poolHead;
@@ -35,7 +35,7 @@ internal static partial class PrimeOrderCalculator
return poolHead; return poolHead;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static void Return(PendingEntry entry) public static void Return(PendingEntry entry)
{ {
entry._next = _poolHead; entry._next = _poolHead;
@@ -47,7 +47,7 @@ internal static partial class PrimeOrderCalculator
public bool HasKnownPrimality = knownComposite; public bool HasKnownPrimality = knownComposite;
public bool IsPrime = false; public bool IsPrime = false;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public void WithPrimality(bool isPrime) public void WithPrimality(bool isPrime)
{ {
KnownComposite = KnownComposite || !isPrime; KnownComposite = KnownComposite || !isPrime;
@@ -125,6 +125,7 @@ internal static partial class PrimeOrderCalculator
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static UInt128 CalculateWideInternalCpu(in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config) private static UInt128 CalculateWideInternalCpu(in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config)
{ {
if (prime <= UInt128.One) if (prime <= UInt128.One)
@@ -152,6 +153,7 @@ internal static partial class PrimeOrderCalculator
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong RunHeuristicPipelineCpu( private static ulong RunHeuristicPipelineCpu(
ulong prime, ulong prime,
ulong? previousOrder, ulong? previousOrder,
@@ -179,7 +181,7 @@ internal static partial class PrimeOrderCalculator
return CalculateByFactorizationCpu(prime, divisorData); return CalculateByFactorizationCpu(prime, divisorData);
} }
if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order)) if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, orderFactors, out ulong order))
{ {
return order; return order;
} }
@@ -187,6 +189,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder; return candidateOrder;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong RunHeuristicPipelineHybrid( private static ulong RunHeuristicPipelineHybrid(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong prime, ulong prime,
@@ -223,6 +226,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder; return candidateOrder;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static UInt128 RunHeuristicPipelineWideCpu( private static UInt128 RunHeuristicPipelineWideCpu(
in UInt128 prime, in UInt128 prime,
in UInt128? previousOrder, in UInt128? previousOrder,
@@ -257,6 +261,7 @@ internal static partial class PrimeOrderCalculator
return candidateOrder; return candidateOrder;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static UInt128 FinishStrictlyWideCpu(in UInt128 prime, in MontgomeryDivisorData? divisorData) private static UInt128 FinishStrictlyWideCpu(in UInt128 prime, in MontgomeryDivisorData? divisorData)
{ {
UInt128 phi = prime - UInt128.One; UInt128 phi = prime - UInt128.One;
@@ -303,6 +308,7 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TrySpecialMaxWideCpu(in UInt128 phi, in UInt128 prime, in MontgomeryDivisorData? divisorData, in PartialFactorResult128 factors) private static bool TrySpecialMaxWideCpu(in UInt128 phi, in UInt128 prime, in MontgomeryDivisorData? divisorData, in PartialFactorResult128 factors)
{ {
ReadOnlySpan<FactorEntry128> factorSpan = factors.Factors; ReadOnlySpan<FactorEntry128> factorSpan = factors.Factors;
@@ -320,6 +326,7 @@ internal static partial class PrimeOrderCalculator
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static UInt128 InitializeStartingOrderWideCpu(in UInt128 prime, in UInt128 phi, in MontgomeryDivisorData? divisorData) private static UInt128 InitializeStartingOrderWideCpu(in UInt128 prime, in UInt128 phi, in MontgomeryDivisorData? divisorData)
{ {
UInt128 order = phi; UInt128 order = phi;
@@ -336,6 +343,7 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static UInt128 ExponentLoweringWideCpu(UInt128 order, in UInt128 prime, in MontgomeryDivisorData? divisorData, in PartialFactorResult128 factors) private static UInt128 ExponentLoweringWideCpu(UInt128 order, in UInt128 prime, in MontgomeryDivisorData? divisorData, in PartialFactorResult128 factors)
{ {
ArrayPool<FactorEntry128> pool = ThreadStaticPools.FactorEntry128Pool; ArrayPool<FactorEntry128> pool = ThreadStaticPools.FactorEntry128Pool;
@@ -382,6 +390,7 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryConfirmOrderWideCpu(in UInt128 prime, in UInt128 order, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config) private static bool TryConfirmOrderWideCpu(in UInt128 prime, in UInt128 order, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config)
{ {
if (order == UInt128.Zero) if (order == UInt128.Zero)
@@ -439,6 +448,7 @@ internal static partial class PrimeOrderCalculator
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryHeuristicFinishWideCpu( private static bool TryHeuristicFinishWideCpu(
in UInt128 prime, in UInt128 prime,
in UInt128 order, in UInt128 order,
@@ -474,7 +484,7 @@ internal static partial class PrimeOrderCalculator
orderFactors = orderFactors.WithAdditionalPrime(orderFactors.Cofactor); orderFactors = orderFactors.WithAdditionalPrime(orderFactors.Cofactor);
} }
int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecks * 4; int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecksCapacity;
Queue<List<UInt128>> uInt128ListPool = ThreadStaticPools.UInt128ListPool; Queue<List<UInt128>> uInt128ListPool = ThreadStaticPools.UInt128ListPool;
List<UInt128> candidates = uInt128ListPool.Rent(capacity); List<UInt128> candidates = uInt128ListPool.Rent(capacity);
FactorEntry128[] factorArray = orderFactors.Factors!; FactorEntry128[] factorArray = orderFactors.Factors!;
@@ -523,6 +533,7 @@ internal static partial class PrimeOrderCalculator
} }
// private static ulong specialMaxHits; // private static ulong specialMaxHits;
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TrySpecialMaxCpu(ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData) private static bool TrySpecialMaxCpu(ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
{ {
int length = factors.Count; int length = factors.Count;
@@ -539,6 +550,7 @@ internal static partial class PrimeOrderCalculator
return EvaluateSpecialMaxCandidatesCpu(stackBuffer, factorSpan, phi, prime, divisorData); return EvaluateSpecialMaxCandidatesCpu(stackBuffer, factorSpan, phi, prime, divisorData);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TrySpecialMaxHybrid(PrimeOrderCalculatorAccelerator gpu, ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData) private static bool TrySpecialMaxHybrid(PrimeOrderCalculatorAccelerator gpu, ulong phi, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
{ {
int length = factors.Count; int length = factors.Count;
@@ -560,6 +572,7 @@ internal static partial class PrimeOrderCalculator
return EvaluateSpecialMaxCandidatesGpu(gpu, factorSpan, phi, prime, divisorData); return EvaluateSpecialMaxCandidatesGpu(gpu, factorSpan, phi, prime, divisorData);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool EvaluateSpecialMaxCandidatesCpu(Span<ulong> buffer, ReadOnlySpan<ulong> factors, ulong phi, ulong prime, in MontgomeryDivisorData divisorData) private static bool EvaluateSpecialMaxCandidatesCpu(Span<ulong> buffer, ReadOnlySpan<ulong> factors, ulong phi, ulong prime, in MontgomeryDivisorData divisorData)
{ {
int factorCount = factors.Length; int factorCount = factors.Length;
@@ -604,13 +617,14 @@ internal static partial class PrimeOrderCalculator
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong InitializeStartingOrderCpu(ulong prime, ulong phi, in MontgomeryDivisorData divisorData) private static ulong InitializeStartingOrderCpu(ulong prime, ulong phi, in MontgomeryDivisorData divisorData)
{ {
ulong order = phi; ulong order = phi;
if ((prime & 7UL) == 1UL || (prime & 7UL) == 7UL) if ((prime & 7UL) == 1UL || (prime & 7UL) == 7UL)
{ {
ulong half = phi >> 1; ulong half = phi >> 1;
if (Pow2EqualsOneCpu(half, prime, divisorData)) if (Pow2EqualsOneCpu(half, divisorData))
{ {
order = half; order = half;
} }
@@ -619,6 +633,7 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong InitializeStartingOrderHybrid(PrimeOrderCalculatorAccelerator gpu, ulong prime, ulong phi, in MontgomeryDivisorData divisorData) private static ulong InitializeStartingOrderHybrid(PrimeOrderCalculatorAccelerator gpu, ulong prime, ulong phi, in MontgomeryDivisorData divisorData)
{ {
ulong order = phi; ulong order = phi;
@@ -634,14 +649,16 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong ExponentLoweringCpu(ulong order, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData) private static ulong ExponentLoweringCpu(ulong order, ulong prime, PartialFactorResult factors, in MontgomeryDivisorData divisorData)
{ {
ReadOnlySpan<ulong> factorSpan = factors.Factors; ReadOnlySpan<ulong> factorSpan = factors.Factors;
ReadOnlySpan<int> exponentsSpan = factors.Exponents; ReadOnlySpan<int> exponentsSpan = factors.Exponents;
int length = factors.Count; int length = factors.Count;
ulong[] tempFactorsArray = Pools.ExclusiveUlongArray.Rent(length + 1); int newLength = length + 1;
int[] tempExponentsArray = Pools.ExclusiveIntArray.Rent(length + 1); ulong[] tempFactorsArray = Pools.ExclusiveUlongArray.Rent(newLength);
int[] tempExponentsArray = Pools.ExclusiveIntArray.Rent(newLength);
Span<ulong> ulongBuffer = tempFactorsArray; Span<ulong> ulongBuffer = tempFactorsArray;
factorSpan.CopyTo(ulongBuffer); factorSpan.CopyTo(ulongBuffer);
@@ -652,7 +669,7 @@ internal static partial class PrimeOrderCalculator
{ {
ulongBuffer[length] = factors.Cofactor; ulongBuffer[length] = factors.Cofactor;
intBuffer[length] = 1; intBuffer[length] = 1;
length++; length = newLength;
} }
Array.Sort(tempFactorsArray, tempExponentsArray, 0, length); Array.Sort(tempFactorsArray, tempExponentsArray, 0, length);
@@ -706,6 +723,7 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void ProcessExponentLoweringPrime(Span<ulong> candidateBuffer, Span<bool> evaluationBuffer, ref ulong order, ulong primeFactor, int exponent, ref ExponentRemainderStepperCpu stepper) private static void ProcessExponentLoweringPrime(Span<ulong> candidateBuffer, Span<bool> evaluationBuffer, ref ulong order, ulong primeFactor, int exponent, ref ExponentRemainderStepperCpu stepper)
{ {
ulong working = order; ulong working = order;
@@ -756,6 +774,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static bool TryConfirmOrderCpu( private static bool TryConfirmOrderCpu(
ulong prime, ulong prime,
ulong order, ulong order,
@@ -765,12 +784,8 @@ internal static partial class PrimeOrderCalculator
{ {
reusableFactorization = null; reusableFactorization = null;
if (order == 0UL) ArgumentOutOfRangeException.ThrowIfEqual(order, 0UL);
{ if (!Pow2EqualsOneCpu(order, divisorData))
return false;
}
if (!Pow2EqualsOneCpu(order, prime, divisorData))
{ {
return false; return false;
} }
@@ -803,6 +818,7 @@ internal static partial class PrimeOrderCalculator
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryConfirmOrderHybrid( private static bool TryConfirmOrderHybrid(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong prime, ulong prime,
@@ -851,6 +867,7 @@ internal static partial class PrimeOrderCalculator
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool ValidateOrderAgainstFactors( private static bool ValidateOrderAgainstFactors(
ulong prime, ulong prime,
ulong order, ulong order,
@@ -916,6 +933,7 @@ internal static partial class PrimeOrderCalculator
return !violates; return !violates;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool ValidateOrderForFactor(Span<ulong> buffer, ulong primeFactor, int exponent, ulong order, ref ExponentRemainderStepperCpu stepper) private static bool ValidateOrderForFactor(Span<ulong> buffer, ulong primeFactor, int exponent, ulong order, ref ExponentRemainderStepperCpu stepper)
{ {
ulong working = order; ulong working = order;
@@ -964,13 +982,13 @@ internal static partial class PrimeOrderCalculator
return false; return false;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryHeuristicFinishCpu( private static bool TryHeuristicFinishCpu(
ulong prime, ulong prime,
ulong order, ulong order,
ulong? previousOrder, ulong? previousOrder,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
in PrimeOrderCalculatorConfig config, in PrimeOrderCalculatorConfig config,
PartialFactorResult phiFactors,
PartialFactorResult? cachedOrderFactors, PartialFactorResult? cachedOrderFactors,
out ulong result) out ulong result)
{ {
@@ -1005,7 +1023,7 @@ internal static partial class PrimeOrderCalculator
orderFactors.WithAdditionalPrime(orderFactors.Cofactor); orderFactors.WithAdditionalPrime(orderFactors.Cofactor);
} }
int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecks << 2; int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecksCapacity;
List<ulong> candidates = ThreadStaticPools.RentUlongList(capacity); List<ulong> candidates = ThreadStaticPools.RentUlongList(capacity);
candidates.Clear(); candidates.Clear();
ulong[] factorArray = orderFactors.Factors!; ulong[] factorArray = orderFactors.Factors!;
@@ -1025,29 +1043,11 @@ internal static partial class PrimeOrderCalculator
int powUsed = 0; int powUsed = 0;
Span<ulong> candidateSpan = CollectionsMarshal.AsSpan(candidates); Span<ulong> candidateSpan = CollectionsMarshal.AsSpan(candidates);
ExponentRemainderStepperCpu powStepper = ThreadStaticPools.RentExponentStepperCpu(divisorData); ExponentRemainderStepperCpu powStepper = ThreadStaticPools.RentExponentStepperCpu(divisorData);
bool powStepperInitialized = false;
int index = 0; ulong candidate = candidateSpan[0];
while (index < candidateCount && powUsed < powBudget)
{
int remaining = candidateCount - index;
int budgetRemaining = powBudget - powUsed;
int batchSize = Math.Min(remaining, Math.Min(budgetRemaining, PrimeOrderConstants.MaxGpuBatchSize));
if (batchSize <= 0)
{
break;
}
ReadOnlySpan<ulong> batch = candidateSpan.Slice(index, batchSize);
int startIndex = 0;
if (!powStepperInitialized)
{
ulong candidate = batch[0];
powUsed++; powUsed++;
bool equalsOne = powStepper.InitializeCpuIsUnity(candidate); bool equalsOne = powStepper.InitializeCpuIsUnity(candidate);
powStepperInitialized = true;
if (equalsOne && TryConfirmCandidateCpu(prime, candidate, divisorData, config, ref powUsed, powBudget)) if (equalsOne && TryConfirmCandidateCpu(prime, candidate, divisorData, config, ref powUsed, powBudget))
{ {
candidates.Clear(); candidates.Clear();
@@ -1057,15 +1057,19 @@ internal static partial class PrimeOrderCalculator
return true; return true;
} }
startIndex = 1; int index = 1;
while (index < candidateCount && powUsed < powBudget)
{
int budgetRemaining = powBudget - powUsed;
if (budgetRemaining <= 0)
{
break;
} }
for (int i = startIndex; i < batchSize && powUsed < powBudget; i++) candidate = candidateSpan[index++];
{
ulong candidate = batch[i];
powUsed++; powUsed++;
bool equalsOne = powStepper.ComputeNextIsUnity(candidate); equalsOne = powStepper.ComputeNextIsUnity(candidate);
if (!equalsOne) if (!equalsOne)
{ {
continue; continue;
@@ -1081,9 +1085,7 @@ internal static partial class PrimeOrderCalculator
ThreadStaticPools.ReturnExponentStepperCpu(powStepper); ThreadStaticPools.ReturnExponentStepperCpu(powStepper);
result = candidate; result = candidate;
return true; return true;
}
index += batchSize;
} }
candidates.Clear(); candidates.Clear();
@@ -1098,6 +1100,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryHeuristicFinishHybrid( private static bool TryHeuristicFinishHybrid(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong prime, ulong prime,
@@ -1135,7 +1138,7 @@ internal static partial class PrimeOrderCalculator
orderFactors.WithAdditionalPrime(orderFactors.Cofactor); orderFactors.WithAdditionalPrime(orderFactors.Cofactor);
} }
int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecks << 2; int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecksCapacity;
List<ulong> candidates = ThreadStaticPools.RentUlongList(capacity); List<ulong> candidates = ThreadStaticPools.RentUlongList(capacity);
candidates.Clear(); candidates.Clear();
ulong[] factorArray = orderFactors.Factors!; ulong[] factorArray = orderFactors.Factors!;
@@ -1230,6 +1233,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryHeuristicFinishGpu( private static bool TryHeuristicFinishGpu(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ulong prime, ulong prime,
@@ -1267,7 +1271,7 @@ internal static partial class PrimeOrderCalculator
orderFactors.WithAdditionalPrime(orderFactors.Cofactor); orderFactors.WithAdditionalPrime(orderFactors.Cofactor);
} }
int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecks << 2; int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecksCapacity;
List<ulong> candidates = ThreadStaticPools.RentUlongList(capacity); List<ulong> candidates = ThreadStaticPools.RentUlongList(capacity);
candidates.Clear(); candidates.Clear();
ulong[] factorArray = orderFactors.Factors!; ulong[] factorArray = orderFactors.Factors!;
@@ -1428,6 +1432,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void SortCandidates(ulong prime, ulong? previousOrder, List<ulong> candidates) private static void SortCandidates(ulong prime, ulong? previousOrder, List<ulong> candidates)
{ {
ulong previous = previousOrder ?? 0UL; ulong previous = previousOrder ?? 0UL;
@@ -1437,56 +1442,73 @@ internal static partial class PrimeOrderCalculator
ulong threshold3 = (prime * 3UL) >> 3; ulong threshold3 = (prime * 3UL) >> 3;
int previousGroup = hasPrevious ? GetGroup(previous, threshold1, threshold2, threshold3) : 1; int previousGroup = hasPrevious ? GetGroup(previous, threshold1, threshold2, threshold3) : 1;
candidates.Sort((x, y) => candidates.Sort((x, y) => CompareCandidates(x, y, previous, previousGroup, hasPrevious, threshold1, threshold2, threshold3));
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static int CompareCandidates(ulong left, ulong right, ulong previous, int previousGroup, bool hasPrevious, ulong threshold1, ulong threshold2, ulong threshold3)
{ {
CandidateKey keyX = BuildKey(x, previous, previousGroup, hasPrevious, threshold1, threshold2, threshold3); int leftGroup = GetGroup(left, threshold1, threshold2, threshold3);
CandidateKey keyY = BuildKey(y, previous, previousGroup, hasPrevious, threshold1, threshold2, threshold3); int rightGroup = GetGroup(right, threshold1, threshold2, threshold3);
int compare = keyX.Primary.CompareTo(keyY.Primary); if (leftGroup == 0)
{
return rightGroup == 0 ? 0 : 1;
}
if (rightGroup == 0)
{
return -1;
}
bool leftIsGe = !hasPrevious || left >= previous;
bool rightIsGe = !hasPrevious || right >= previous;
int leftPrimary = ComputePrimary(leftGroup, leftIsGe, previousGroup);
int rightPrimary = ComputePrimary(rightGroup, rightIsGe, previousGroup);
int compare = leftPrimary.CompareTo(rightPrimary);
if (compare != 0) if (compare != 0)
{ {
return compare; return compare;
} }
compare = keyX.Secondary.CompareTo(keyY.Secondary); long leftSecondary;
if (compare != 0) long leftTertiary;
if (leftGroup == 3)
{ {
return compare; leftSecondary = -(long)left;
} leftTertiary = -(long)left;
return keyX.Tertiary.CompareTo(keyY.Tertiary);
});
}
private static CandidateKey BuildKey(ulong value, ulong previous, int previousGroup, bool hasPrevious, ulong threshold1, ulong threshold2, ulong threshold3)
{
int group = GetGroup(value, threshold1, threshold2, threshold3);
if (group == 0)
{
return CandidateKey.Max;
}
bool isGe = !hasPrevious || value >= previous;
int primary = ComputePrimary(group, isGe, previousGroup);
long secondary;
long tertiary;
if (group == 3)
{
secondary = -(long)value;
tertiary = -(long)value;
} }
else else
{ {
ulong reference = hasPrevious ? previous : 0UL; ulong leftReference = hasPrevious ? (left > previous ? left - previous : previous - left) : left;
reference = hasPrevious ? (value > reference ? value - reference : reference - value) : value; leftSecondary = (long)leftReference;
secondary = (long)reference; leftTertiary = (long)left;
tertiary = (long)value;
} }
return new CandidateKey(primary, secondary, tertiary); long rightSecondary;
long rightTertiary;
if (rightGroup == 3)
{
rightSecondary = -(long)right;
rightTertiary = -(long)right;
}
else
{
ulong rightReference = hasPrevious ? (right > previous ? right - previous : previous - right) : right;
rightSecondary = (long)rightReference;
rightTertiary = (long)right;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] compare = leftSecondary.CompareTo(rightSecondary);
if (compare != 0)
{
return compare;
}
return leftTertiary.CompareTo(rightTertiary);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static int ComputePrimary(int group, bool isGe, int previousGroup) private static int ComputePrimary(int group, bool isGe, int previousGroup)
{ {
int groupOffset = group switch int groupOffset = group switch
@@ -1510,7 +1532,7 @@ internal static partial class PrimeOrderCalculator
return groupOffset + (isGe ? 0 : 1); return groupOffset + (isGe ? 0 : 1);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static int GetGroup(ulong value, ulong threshold1, ulong threshold2, ulong threshold3) private static int GetGroup(ulong value, ulong threshold1, ulong threshold2, ulong threshold3)
{ {
if (value <= threshold1) if (value <= threshold1)
@@ -1531,6 +1553,7 @@ internal static partial class PrimeOrderCalculator
return 0; return 0;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static void BuildCandidates(ulong order, ulong[] factors, int[] exponents, int count, List<ulong> candidates, int limit) private static void BuildCandidates(ulong order, ulong[] factors, int[] exponents, int count, List<ulong> candidates, int limit)
{ {
if (count == 0) if (count == 0)
@@ -1542,7 +1565,7 @@ internal static partial class PrimeOrderCalculator
BuildCandidatesRecursive(order, factors, exponents, 0, 1UL, candidates, limit); BuildCandidatesRecursive(order, factors, exponents, 0, 1UL, candidates, limit);
} }
// private static void BuildCandidatesRecursive(ulong order, in ReadOnlySpan<FactorEntry> factors, int index, ulong divisorProduct, List<ulong> candidates, int limit) [MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void BuildCandidatesRecursive(ulong order, in ulong[] factors, in int[] exponents, int index, ulong divisorProduct, List<ulong> candidates, int limit) private static void BuildCandidatesRecursive(ulong order, in ulong[] factors, in int[] exponents, int index, ulong divisorProduct, List<ulong> candidates, int limit)
{ {
if (candidates.Count >= limit) if (candidates.Count >= limit)
@@ -1603,6 +1626,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryConfirmCandidateCpu(ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget) private static bool TryConfirmCandidateCpu(ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget)
{ {
PartialFactorResult factorization = PartialFactorCpu(candidate, config); PartialFactorResult factorization = PartialFactorCpu(candidate, config);
@@ -1682,6 +1706,7 @@ internal static partial class PrimeOrderCalculator
return !violates; return !violates;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryConfirmCandidateHybrid(PrimeOrderCalculatorAccelerator gpu, ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget) private static bool TryConfirmCandidateHybrid(PrimeOrderCalculatorAccelerator gpu, ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget)
{ {
PartialFactorResult factorization = PartialFactorHybrid(gpu, candidate, config); PartialFactorResult factorization = PartialFactorHybrid(gpu, candidate, config);
@@ -1760,6 +1785,7 @@ internal static partial class PrimeOrderCalculator
return !violates; return !violates;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool CheckCandidateViolation(Span<ulong> buffer, ulong primeFactor, int exponent, ulong candidate, ulong prime, ref int powUsed, int powBudget, ref ExponentRemainderStepperCpu stepper) private static bool CheckCandidateViolation(Span<ulong> buffer, ulong primeFactor, int exponent, ulong candidate, ulong prime, ref int powUsed, int powBudget, ref ExponentRemainderStepperCpu stepper)
{ {
ulong working = candidate; ulong working = candidate;
@@ -1841,10 +1867,11 @@ internal static partial class PrimeOrderCalculator
return false; return false;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static bool Pow2EqualsOneCpu(ulong exponent, ulong prime, in MontgomeryDivisorData divisorData) private static bool Pow2EqualsOneCpu(ulong exponent, in MontgomeryDivisorData divisorData)
=> exponent.Pow2MontgomeryModWindowedConvertToStandardCpu(divisorData) == 1UL; => exponent.Pow2MontgomeryModWindowedConvertToStandardCpu(divisorData) == 1UL;
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static bool Pow2EqualsOneHybrid(PrimeOrderCalculatorAccelerator gpu, ulong exponent, ulong prime, in MontgomeryDivisorData divisorData) private static bool Pow2EqualsOneHybrid(PrimeOrderCalculatorAccelerator gpu, ulong exponent, ulong prime, in MontgomeryDivisorData divisorData)
{ {
// if (exponent >= PerfectNumberConstants.MaxQForDivisorCycles || prime >= PerfectNumberConstants.MaxQForDivisorCycles) // if (exponent >= PerfectNumberConstants.MaxQForDivisorCycles || prime >= PerfectNumberConstants.MaxQForDivisorCycles)
@@ -1869,6 +1896,7 @@ internal static partial class PrimeOrderCalculator
private static readonly ulong[] _emptyUlongArray = []; private static readonly ulong[] _emptyUlongArray = [];
private static readonly int[] _emptyIntArray = []; private static readonly int[] _emptyIntArray = [];
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static PartialFactorResult PartialFactorCpu(ulong value, in PrimeOrderCalculatorConfig config) private static PartialFactorResult PartialFactorCpu(ulong value, in PrimeOrderCalculatorConfig config)
{ {
if (value <= 1UL) if (value <= 1UL)
@@ -1884,8 +1912,8 @@ internal static partial class PrimeOrderCalculator
// primeSlots.Clear(); // primeSlots.Clear();
// exponentSlots.Clear(); // exponentSlots.Clear();
ArgumentOutOfRangeException.ThrowIfEqual(config.SmallFactorLimit, 0U);
uint limit = config.SmallFactorLimit == 0 ? uint.MaxValue : config.SmallFactorLimit; uint limit = config.SmallFactorLimit == 0 ? uint.MaxValue : config.SmallFactorLimit;
ulong remaining = value;
List<PendingEntry> pending = ThreadStaticPools.RentPrimeOrderPendingEntryList(PrimeOrderConstants.GpuSmallPrimeFactorSlots); List<PendingEntry> pending = ThreadStaticPools.RentPrimeOrderPendingEntryList(PrimeOrderConstants.GpuSmallPrimeFactorSlots);
@@ -1895,7 +1923,7 @@ internal static partial class PrimeOrderCalculator
primeSlots, primeSlots,
exponentSlots, exponentSlots,
out int factorCount, out int factorCount,
out remaining); out ulong remaining);
bool limitReached; bool limitReached;
if (remaining > 1UL) if (remaining > 1UL)
@@ -2033,6 +2061,7 @@ internal static partial class PrimeOrderCalculator
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static PartialFactorResult PartialFactorHybrid(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderCalculatorConfig config) private static PartialFactorResult PartialFactorHybrid(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderCalculatorConfig config)
{ {
if (value <= 1UL) if (value <= 1UL)
@@ -2205,6 +2234,7 @@ internal static partial class PrimeOrderCalculator
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static PartialFactorResult PartialFactorGpu(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderCalculatorConfig config) private static PartialFactorResult PartialFactorGpu(PrimeOrderCalculatorAccelerator gpu, ulong value, in PrimeOrderCalculatorConfig config)
{ {
if (value <= 1UL) if (value <= 1UL)
@@ -2382,7 +2412,7 @@ internal static partial class PrimeOrderCalculator
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void CollectFactorsHybrid(PrimeOrderCalculatorAccelerator gpu, Span<ulong> primeSlots, Span<int> exponentSlots, ref ulong[] primeSlotArray, ref int[] exponentSlotArray, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, out bool pollardRhoDeadlineReached) private static void CollectFactorsHybrid(PrimeOrderCalculatorAccelerator gpu, Span<ulong> primeSlots, Span<int> exponentSlots, ref ulong[] primeSlotArray, ref int[] exponentSlotArray, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, out bool pollardRhoDeadlineReached)
{ {
while (compositeStack.Count > 0) while (compositeStack.Count > 0)
@@ -2417,7 +2447,7 @@ internal static partial class PrimeOrderCalculator
pollardRhoDeadlineReached = false; pollardRhoDeadlineReached = false;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void CollectFactorsCpu(Span<ulong> primeSlots, Span<int> exponentSlots, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, out bool pollardRhoDeadlineReached) private static void CollectFactorsCpu(Span<ulong> primeSlots, Span<int> exponentSlots, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, out bool pollardRhoDeadlineReached)
{ {
while (compositeStack.Count > 0) while (compositeStack.Count > 0)
@@ -2452,7 +2482,7 @@ internal static partial class PrimeOrderCalculator
pollardRhoDeadlineReached = false; pollardRhoDeadlineReached = false;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void CollectFactorsGpu(PrimeOrderCalculatorAccelerator gpu, ref Span<ulong> primeSlots, ref Span<int> exponentSlots, ref ulong[] primeSlotArray, ref int[] exponentSlotArray, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, ref bool pollardRhoDeadlineReached) private static void CollectFactorsGpu(PrimeOrderCalculatorAccelerator gpu, ref Span<ulong> primeSlots, ref Span<int> exponentSlots, ref ulong[] primeSlotArray, ref int[] exponentSlotArray, ref int factorCount, List<PendingEntry> pending, Stack<ulong> compositeStack, long deadlineTimestamp, ref bool pollardRhoDeadlineReached)
{ {
while (compositeStack.Count > 0) while (compositeStack.Count > 0)
@@ -2487,6 +2517,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool RunOnCpu() private static bool RunOnCpu()
{ {
if (PerfectNumberConstants.GpuRatio == 0) if (PerfectNumberConstants.GpuRatio == 0)
@@ -2525,6 +2556,7 @@ internal static partial class PrimeOrderCalculator
return cpuCount != PerfectNumberConstants.GpuRatio; return cpuCount != PerfectNumberConstants.GpuRatio;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void PopulateSmallPrimeFactorsCpu( private static void PopulateSmallPrimeFactorsCpu(
ulong value, ulong value,
uint limit, uint limit,
@@ -2534,48 +2566,45 @@ internal static partial class PrimeOrderCalculator
out ulong remaining) out ulong remaining)
{ {
factorCount = 0; factorCount = 0;
ulong remainingLocal = value;
if (value <= 1UL) if (value <= 1UL)
{ {
remaining = remainingLocal; remaining = value;
return; return;
} }
uint[] primes = PrimesGenerator.SmallPrimes; uint[] primes = PrimesGenerator.SmallPrimes;
ulong[] squares = PrimesGenerator.SmallPrimesPow2; ulong[] squares = PrimesGenerator.SmallPrimesPow2;
int primeCount = primes.Length; int primeCount = primes.Length;
uint effectiveLimit = limit == 0 ? uint.MaxValue : limit;
for (int i = 0; i < primeCount && remainingLocal > 1UL; i++) for (int i = 0; i < primeCount && value > 1UL; i++)
{ {
uint primeCandidate = primes[i]; uint primeCandidate = primes[i];
if (primeCandidate > effectiveLimit) if (primeCandidate > limit)
{ {
break; break;
} }
ulong primeSquare = squares[i]; ulong primeValue = squares[i];
// primeSquare will never == 0 in production code // primeSquare will never == 0 in production code
// if (primeSquare != 0 && primeSquare > remainingLocal) // if (primeSquare != 0 && primeSquare > remainingLocal)
if (primeSquare > remainingLocal) if (primeValue > value)
{ {
break; break;
} }
ulong primeValue = primeCandidate; primeValue = primeCandidate;
// primeCandidate will never equal 0 in production code // primeCandidate will never equal 0 in production code
// if (primeCandidate == 0UL) // if (primeCandidate == 0UL)
// { // {
// continue; // continue;
// } // }
if (remainingLocal.ReduceCycleRemainder(primeValue) != 0UL) if (value.ReduceCycleRemainder(primeValue) != 0UL)
{ {
continue; continue;
} }
int exponent = ExtractSmallPrimeExponent(ref remainingLocal, primeValue); int exponent = ExtractSmallPrimeExponent(ref value, primeValue);
if (exponent == 0) if (exponent == 0)
{ {
continue; continue;
@@ -2590,10 +2619,10 @@ internal static partial class PrimeOrderCalculator
factorCount++; factorCount++;
} }
remaining = remainingLocal; remaining = value;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
// Unroll the initial divisions because small exponents dominate in practice. // Unroll the initial divisions because small exponents dominate in practice.
private static int ExtractSmallPrimeExponent(ref ulong value, ulong primeValue) private static int ExtractSmallPrimeExponent(ref ulong value, ulong primeValue)
{ {
@@ -2658,6 +2687,7 @@ internal static partial class PrimeOrderCalculator
return exponent; return exponent;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static long CreateDeadlineTimestamp(int milliseconds) private static long CreateDeadlineTimestamp(int milliseconds)
{ {
if (milliseconds <= 0) if (milliseconds <= 0)
@@ -2665,9 +2695,9 @@ internal static partial class PrimeOrderCalculator
return long.MaxValue; return long.MaxValue;
} }
long stopwatchTicks = ConvertMillisecondsToStopwatchTicks(milliseconds);
long startTimestamp = Stopwatch.GetTimestamp(); long startTimestamp = Stopwatch.GetTimestamp();
long deadline = startTimestamp + stopwatchTicks; long deadline = ConvertMillisecondsToStopwatchTicks(milliseconds);
deadline += startTimestamp;
if (deadline < startTimestamp) if (deadline < startTimestamp)
{ {
return long.MaxValue; return long.MaxValue;
@@ -2676,7 +2706,7 @@ internal static partial class PrimeOrderCalculator
return deadline; return deadline;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static long ConvertMillisecondsToStopwatchTicks(int milliseconds) private static long ConvertMillisecondsToStopwatchTicks(int milliseconds)
{ {
long frequency = Stopwatch.Frequency; long frequency = Stopwatch.Frequency;
@@ -2685,6 +2715,7 @@ internal static partial class PrimeOrderCalculator
return baseTicks + (remainder / 1000L); return baseTicks + (remainder / 1000L);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryPollardRhoCpu(ulong n, long deadlineTimestamp, out ulong factor) private static bool TryPollardRhoCpu(ulong n, long deadlineTimestamp, out ulong factor)
{ {
factor = 0UL; factor = 0UL;
@@ -2724,22 +2755,23 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong AdvancePolynomialCpu(ulong x, ulong c, ulong modulus) private static ulong AdvancePolynomialCpu(ulong x, ulong c, ulong modulus)
{ {
UInt128 value = (UInt128)x * x + c; UInt128 value = (UInt128)x * x + c;
return (ulong)value.ReduceCycleRemainder(modulus); return (ulong)value.ReduceCycleRemainder(modulus);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong AdvancePolynomialTwiceCpu(ulong x, ulong c, ulong modulus) private static ulong AdvancePolynomialTwiceCpu(ulong x, ulong c, ulong modulus)
{ {
UInt128 value = (UInt128)x * x + c; UInt128 value = (UInt128)x * x + c;
var remainder = (ulong)value.ReduceCycleRemainder(modulus); x = (ulong)value.ReduceCycleRemainder(modulus);
value = (UInt128)remainder * remainder + c; value = (UInt128)x * x + c;
return (ulong)value.ReduceCycleRemainder(modulus); return (ulong)value.ReduceCycleRemainder(modulus);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static ulong BinaryGcd(ulong a, ulong b) private static ulong BinaryGcd(ulong a, ulong b)
{ {
if (a == 0UL) if (a == 0UL)
@@ -2771,6 +2803,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static void AddFactor(Dictionary<ulong, int> counts, ulong prime, int exponent) private static void AddFactor(Dictionary<ulong, int> counts, ulong prime, int exponent)
{ {
if (counts.TryGetValue(prime, out int existing)) if (counts.TryGetValue(prime, out int existing))
@@ -2783,6 +2816,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void AddFactorToCollector( private static void AddFactorToCollector(
Span<ulong> primes, Span<ulong> primes,
Span<int> exponents, Span<int> exponents,
@@ -2813,7 +2847,7 @@ internal static partial class PrimeOrderCalculator
count++; count++;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static void EnsureCollectorCapacity( private static void EnsureCollectorCapacity(
Span<ulong> primes, Span<ulong> primes,
int requiredCapacity) int requiredCapacity)
@@ -2821,6 +2855,7 @@ internal static partial class PrimeOrderCalculator
ArgumentOutOfRangeException.ThrowIfGreaterThan(requiredCapacity, primes.Length); ArgumentOutOfRangeException.ThrowIfGreaterThan(requiredCapacity, primes.Length);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong CalculateByFactorizationCpu(ulong prime, in MontgomeryDivisorData divisorData) private static ulong CalculateByFactorizationCpu(ulong prime, in MontgomeryDivisorData divisorData)
{ {
ulong phi = prime - 1UL; ulong phi = prime - 1UL;
@@ -2868,6 +2903,7 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static void FactorCompletelyCpu(ulong value, Dictionary<ulong, int> counts, bool knownComposite) private static void FactorCompletelyCpu(ulong value, Dictionary<ulong, int> counts, bool knownComposite)
{ {
if (value <= 1UL) if (value <= 1UL)
@@ -2927,6 +2963,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong PollardRhoStrict(ulong n) private static ulong PollardRhoStrict(ulong n)
{ {
if ((n & 1UL) == 0UL) if ((n & 1UL) == 0UL)
@@ -2944,8 +2981,7 @@ internal static partial class PrimeOrderCalculator
while (d == 1UL) while (d == 1UL)
{ {
x = AdvancePolynomialCpu(x, c, n); x = AdvancePolynomialCpu(x, c, n);
y = AdvancePolynomialCpu(y, c, n); y = AdvancePolynomialTwiceCpu(y, c, n);
y = AdvancePolynomialCpu(y, c, n);
ulong diff = x > y ? x - y : y - x; ulong diff = x > y ? x - y : y - x;
d = BinaryGcd(diff, n); d = BinaryGcd(diff, n);
} }
@@ -2957,6 +2993,7 @@ internal static partial class PrimeOrderCalculator
} }
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static UInt128 Pow2ModWideCpu(in UInt128 exponent, in UInt128 modulus, in MontgomeryDivisorData? divisorData) private static UInt128 Pow2ModWideCpu(in UInt128 exponent, in UInt128 modulus, in MontgomeryDivisorData? divisorData)
{ {
if (modulus == UInt128.One) if (modulus == UInt128.One)
@@ -2967,6 +3004,7 @@ internal static partial class PrimeOrderCalculator
return exponent.Pow2MontgomeryModWindowed(modulus); return exponent.Pow2MontgomeryModWindowed(modulus);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryConfirmCandidateWideCpu(in UInt128 prime, in UInt128 candidate, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget, in MontgomeryDivisorData? divisorData) private static bool TryConfirmCandidateWideCpu(in UInt128 prime, in UInt128 candidate, in PrimeOrderCalculatorConfig config, ref int powUsed, int powBudget, in MontgomeryDivisorData? divisorData)
{ {
PartialFactorResult128 factorization = PartialFactorWide(candidate, config); PartialFactorResult128 factorization = PartialFactorWide(candidate, config);
@@ -3020,13 +3058,7 @@ internal static partial class PrimeOrderCalculator
return true; return true;
} }
private readonly struct CandidateKey(int primary, long secondary, long tertiary)
{
public static readonly CandidateKey Max = new(int.MaxValue, long.MaxValue, long.MaxValue);
public readonly int Primary = primary;
public readonly long Secondary = secondary;
public readonly long Tertiary = tertiary;
}
} }
@@ -1,4 +1,5 @@
using System.Buffers; using System.Buffers;
using System.Runtime.CompilerServices;
using ILGPU; using ILGPU;
using ILGPU.Runtime; using ILGPU.Runtime;
using PerfectNumbers.Core.Gpu; using PerfectNumbers.Core.Gpu;
@@ -86,6 +87,7 @@ internal static partial class PrimeOrderCalculator
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static UInt128 CalculateWideInternalGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config) private static UInt128 CalculateWideInternalGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 prime, in UInt128? previousOrder, in MontgomeryDivisorData? divisorData, in PrimeOrderCalculatorConfig config)
{ {
if (prime <= UInt128.One) if (prime <= UInt128.One)
@@ -361,7 +363,7 @@ internal static partial class PrimeOrderCalculator
orderFactors = orderFactors.WithAdditionalPrime(orderFactors.Cofactor); orderFactors = orderFactors.WithAdditionalPrime(orderFactors.Cofactor);
} }
int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecks * 4; int capacity = config.MaxPowChecks <= 0 ? 64 : config.MaxPowChecksCapacity;
List<UInt128> candidates = new(capacity); List<UInt128> candidates = new(capacity);
FactorEntry128[] factorArray = orderFactors.Factors!; FactorEntry128[] factorArray = orderFactors.Factors!;
BuildCandidatesWide(order, factorArray, orderFactors.Count, candidates, capacity); BuildCandidatesWide(order, factorArray, orderFactors.Count, candidates, capacity);
@@ -403,6 +405,7 @@ internal static partial class PrimeOrderCalculator
return false; return false;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static ulong CalculateByFactorizationGpu(PrimeOrderCalculatorAccelerator gpu, ulong prime, in MontgomeryDivisorData divisorData) private static ulong CalculateByFactorizationGpu(PrimeOrderCalculatorAccelerator gpu, ulong prime, in MontgomeryDivisorData divisorData)
{ {
ulong phi = prime - 1UL; ulong phi = prime - 1UL;
@@ -445,6 +448,7 @@ internal static partial class PrimeOrderCalculator
return order; return order;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool TryPopulateSmallPrimeFactorsGpu(PrimeOrderCalculatorAccelerator gpu, ulong value, uint limit, Dictionary<ulong, int> counts, out int factorCount, out ulong remaining) private static bool TryPopulateSmallPrimeFactorsGpu(PrimeOrderCalculatorAccelerator gpu, ulong value, uint limit, Dictionary<ulong, int> counts, out int factorCount, out ulong remaining)
{ {
var primeBufferArray = ThreadStaticPools.UlongPool.Rent(GpuSmallPrimeFactorSlots); var primeBufferArray = ThreadStaticPools.UlongPool.Rent(GpuSmallPrimeFactorSlots);
@@ -511,6 +515,7 @@ internal static partial class PrimeOrderCalculator
return true; return true;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static bool EvaluateSpecialMaxCandidatesGpu( private static bool EvaluateSpecialMaxCandidatesGpu(
PrimeOrderCalculatorAccelerator gpu, PrimeOrderCalculatorAccelerator gpu,
ReadOnlySpan<ulong> factors, ReadOnlySpan<ulong> factors,
@@ -548,6 +553,7 @@ internal static partial class PrimeOrderCalculator
return result != 0; return result != 0;
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
private static UInt128 Pow2ModWideGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 exponent, in UInt128 modulus, in MontgomeryDivisorData? divisorData) private static UInt128 Pow2ModWideGpu(PrimeOrderCalculatorAccelerator gpu, in UInt128 exponent, in UInt128 modulus, in MontgomeryDivisorData? divisorData)
{ {
if (modulus == UInt128.One) if (modulus == UInt128.One)
@@ -30,6 +30,7 @@ internal static partial class PrimeOrderCalculator
public readonly uint SmallFactorLimit = smallFactorLimit; public readonly uint SmallFactorLimit = smallFactorLimit;
public readonly int PollardRhoMilliseconds = pollardRhoMilliseconds; public readonly int PollardRhoMilliseconds = pollardRhoMilliseconds;
public readonly int MaxPowChecks = maxPowChecks; public readonly int MaxPowChecks = maxPowChecks;
public readonly int MaxPowChecksCapacity = maxPowChecks << 2;
public readonly bool StrictMode = strictMode; public readonly bool StrictMode = strictMode;
} }
@@ -10,7 +10,7 @@ public sealed class PrimeTesterByLastDigit
[ThreadStatic] [ThreadStatic]
private static bool _mod10Initialized; private static bool _mod10Initialized;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static byte GetMod10(ulong value) private static byte GetMod10(ulong value)
{ {
if (!_mod10Initialized || _mod10Stepper.Modulus != 10UL) if (!_mod10Initialized || _mod10Stepper.Modulus != 10UL)
@@ -24,6 +24,7 @@ public sealed class PrimeTesterByLastDigit
return (byte)_mod10Stepper.Step(value); return (byte)_mod10Stepper.Step(value);
} }
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static bool IsPrimeCpu(ulong n) public static bool IsPrimeCpu(ulong n)
{ {
// The below IFs never trigger in production code of EvenPerfectBitScanner on --mersenne=bydivisor path. // The below IFs never trigger in production code of EvenPerfectBitScanner on --mersenne=bydivisor path.
+6 -6
View File
@@ -5,7 +5,7 @@ namespace PerfectNumbers.Core;
public static partial class ULongExtensions public static partial class ULongExtensions
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModWindowedKeepMontgomeryCpu(this ulong exponent, in MontgomeryDivisorData divisor) public static ulong Pow2MontgomeryModWindowedKeepMontgomeryCpu(this ulong exponent, in MontgomeryDivisorData divisor)
{ {
ulong modulus = divisor.Modulus; ulong modulus = divisor.Modulus;
@@ -75,7 +75,7 @@ public static partial class ULongExtensions
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModWindowedConvertToStandardCpu(this ulong exponent, in MontgomeryDivisorData divisor) public static ulong Pow2MontgomeryModWindowedConvertToStandardCpu(this ulong exponent, in MontgomeryDivisorData divisor)
{ {
ulong modulus = divisor.Modulus; ulong modulus = divisor.Modulus;
@@ -146,7 +146,7 @@ public static partial class ULongExtensions
return result; return result;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static void InitializeMontgomeryOddPowersCpu(in MontgomeryDivisorData divisor, ulong modulus, ulong nPrime, Span<ulong> oddPowers) private static void InitializeMontgomeryOddPowersCpu(in MontgomeryDivisorData divisor, ulong modulus, ulong nPrime, Span<ulong> oddPowers)
{ {
oddPowers[0] = divisor.MontgomeryTwo; oddPowers[0] = divisor.MontgomeryTwo;
@@ -165,20 +165,20 @@ public static partial class ULongExtensions
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModWithCycleConvertToStandardCpu(this ulong exponent, ulong cycleLength, in MontgomeryDivisorData divisor) public static ulong Pow2MontgomeryModWithCycleConvertToStandardCpu(this ulong exponent, ulong cycleLength, in MontgomeryDivisorData divisor)
{ {
ulong rotationCount = exponent % cycleLength; ulong rotationCount = exponent % cycleLength;
return Pow2MontgomeryModWindowedConvertToStandardCpu(rotationCount, divisor); return Pow2MontgomeryModWindowedConvertToStandardCpu(rotationCount, divisor);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModFromCycleRemainderCpu(this ulong reducedExponent, in MontgomeryDivisorData divisor) public static ulong Pow2MontgomeryModFromCycleRemainderCpu(this ulong reducedExponent, in MontgomeryDivisorData divisor)
{ {
return Pow2MontgomeryModWindowedConvertToStandardCpu(reducedExponent, divisor); return Pow2MontgomeryModWindowedConvertToStandardCpu(reducedExponent, divisor);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong CalculateMersenneDivisorCycleLengthUnrolledHexCpu(this ulong divisor) public static ulong CalculateMersenneDivisorCycleLengthUnrolledHexCpu(this ulong divisor)
{ {
// EvenPerfectBitScanner only routes odd divisors here; keep the guard commented out for benchmarks. // EvenPerfectBitScanner only routes odd divisors here; keep the guard commented out for benchmarks.
+8 -8
View File
@@ -7,7 +7,7 @@ namespace PerfectNumbers.Core;
public static partial class ULongExtensions public static partial class ULongExtensions
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
[Obsolete("Use ULongExtensions.MulHighCpu or ULongExtensions.MulHighGpu.")] [Obsolete("Use ULongExtensions.MulHighCpu or ULongExtensions.MulHighGpu.")]
public static ulong MulHighGpuCompatible(this ulong x, ulong y) public static ulong MulHighGpuCompatible(this ulong x, ulong y)
{ {
@@ -16,7 +16,7 @@ public static partial class ULongExtensions
return product.High; return product.High;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
[Obsolete("Use ULongExtensions.MulModGpu for GPU-compatible host code or GpuUInt128.MulMod inside kernels.")] [Obsolete("Use ULongExtensions.MulModGpu for GPU-compatible host code or GpuUInt128.MulMod inside kernels.")]
public static ulong MulMod64Gpu(this ulong a, ulong b, ulong modulus) public static ulong MulMod64Gpu(this ulong a, ulong b, ulong modulus)
{ {
@@ -26,7 +26,7 @@ public static partial class ULongExtensions
return state.MulMod(b, modulus); return state.MulMod(b, modulus);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
[Obsolete("Use ULongExtensions.MulModGpu for GPU-compatible host code or GpuUInt128.MulMod inside kernels.")] [Obsolete("Use ULongExtensions.MulModGpu for GPU-compatible host code or GpuUInt128.MulMod inside kernels.")]
public static ulong MulMod64GpuDeferred(this ulong a, ulong b, ulong modulus) public static ulong MulMod64GpuDeferred(this ulong a, ulong b, ulong modulus)
{ {
@@ -36,29 +36,29 @@ public static partial class ULongExtensions
return state.MulModWithNativeModulo(b, modulus); return state.MulModWithNativeModulo(b, modulus);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong MulModGpu(this ulong left, ulong right, ulong modulus) public static ulong MulModGpu(this ulong left, ulong right, ulong modulus)
{ {
GpuUInt128 state = new(left); GpuUInt128 state = new(left);
return state.MulMod(right, modulus); return state.MulMod(right, modulus);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModWindowedKeepGpu(this ulong exponent, PrimeOrderCalculatorAccelerator gpu, in MontgomeryDivisorData divisor) public static ulong Pow2MontgomeryModWindowedKeepGpu(this ulong exponent, PrimeOrderCalculatorAccelerator gpu, in MontgomeryDivisorData divisor)
=> Pow2MontgomeryGpuCalculator.CalculateKeep(gpu, exponent, divisor); => Pow2MontgomeryGpuCalculator.CalculateKeep(gpu, exponent, divisor);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModWindowedConvertGpu(this ulong exponent, PrimeOrderCalculatorAccelerator gpu, in MontgomeryDivisorData divisor) public static ulong Pow2MontgomeryModWindowedConvertGpu(this ulong exponent, PrimeOrderCalculatorAccelerator gpu, in MontgomeryDivisorData divisor)
=> Pow2MontgomeryGpuCalculator.CalculateConvert(gpu, exponent, divisor); => Pow2MontgomeryGpuCalculator.CalculateConvert(gpu, exponent, divisor);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModWithCycleGpu(this ulong exponent, PrimeOrderCalculatorAccelerator gpu, ulong cycleLength, in MontgomeryDivisorData divisor) public static ulong Pow2MontgomeryModWithCycleGpu(this ulong exponent, PrimeOrderCalculatorAccelerator gpu, ulong cycleLength, in MontgomeryDivisorData divisor)
{ {
ulong rotationCount = exponent % cycleLength; ulong rotationCount = exponent % cycleLength;
return Pow2MontgomeryGpuCalculator.CalculateConvert(gpu, rotationCount, divisor); return Pow2MontgomeryGpuCalculator.CalculateConvert(gpu, rotationCount, divisor);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong Pow2MontgomeryModFromCycleRemainderGpu(this ulong reducedExponent, PrimeOrderCalculatorAccelerator gpu, in MontgomeryDivisorData divisor) public static ulong Pow2MontgomeryModFromCycleRemainderGpu(this ulong reducedExponent, PrimeOrderCalculatorAccelerator gpu, in MontgomeryDivisorData divisor)
{ {
return Pow2MontgomeryGpuCalculator.CalculateConvert(gpu, reducedExponent, divisor); return Pow2MontgomeryGpuCalculator.CalculateConvert(gpu, reducedExponent, divisor);
+2 -2
View File
@@ -642,7 +642,7 @@ public static partial class ULongExtensions
return (ulong)(((UInt128)a * b) % modulus); return (ulong)(((UInt128)a * b) % modulus);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong MontgomeryMultiplyCpu(this ulong a, ulong b, ulong modulus, ulong nPrime) public static ulong MontgomeryMultiplyCpu(this ulong a, ulong b, ulong modulus, ulong nPrime)
{ {
ulong tLow = unchecked(a * b); ulong tLow = unchecked(a * b);
@@ -1133,7 +1133,7 @@ public static partial class ULongExtensions
return x1; return x1;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public static ulong ReduceCycleRemainder(this ulong value, ulong modulus) public static ulong ReduceCycleRemainder(this ulong value, ulong modulus)
{ {
// BigIntegerExtensions.Track(modulus); // BigIntegerExtensions.Track(modulus);