--mersenne=bydivisor testers and sessions integrated and converted to structs.
This commit is contained in:
1 parent
3c80221105
commit
2abc6aae49
32 files changed
+3814
-1505
No files matched your search
@@ -3,23 +3,31 @@ using PerfectNumbers.Core.Gpu.Accelerators;
|
||||
|
||||
namespace PerfectNumbers.Core.Cpu;
|
||||
|
||||
internal sealed class MersenneCpuDivisorScanSession(PrimeOrderCalculatorAccelerator gpu, ComputationDevice orderDevice) : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession
|
||||
{
|
||||
private Func<ulong, MontgomeryDivisorData, ulong> _getCycleLength = orderDevice switch
|
||||
internal struct MersenneCpuDivisorScanSessionWithCpuOrder() : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession
|
||||
{
|
||||
ComputationDevice.Gpu => (divisor, divisorData) => DivisorCycleCache.Shared.GetCycleLengthGpu(gpu, divisor, divisorData),
|
||||
ComputationDevice.Hybrid => (divisor, divisorData) => DivisorCycleCache.Shared.GetCycleLengthHybrid(gpu, divisor, divisorData),
|
||||
_ => static (divisor, divisorData) => DivisorCycleCache.Shared.GetCycleLengthCpu(divisor, divisorData),
|
||||
};
|
||||
private readonly CycleRemainderStepper _cycleStepper = new();
|
||||
private ExponentRemainderStepperCpu? _exponentStepper;
|
||||
|
||||
public void Configure(PrimeOrderCalculatorAccelerator gpu, ComputationDevice orderDevice)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public readonly void Configure()
|
||||
{
|
||||
_getCycleLength = orderDevice switch
|
||||
}
|
||||
|
||||
private static ulong _hits;
|
||||
private static ulong _misses;
|
||||
|
||||
private static void PrintStats(bool wasHit)
|
||||
{
|
||||
if (wasHit)
|
||||
{
|
||||
ComputationDevice.Gpu => (divisor, divisorData) => DivisorCycleCache.Shared.GetCycleLengthGpu(gpu, divisor, divisorData),
|
||||
ComputationDevice.Hybrid => (divisor, divisorData) => DivisorCycleCache.Shared.GetCycleLengthHybrid(gpu, divisor, divisorData),
|
||||
_ => static (divisor, divisorData) => DivisorCycleCache.Shared.GetCycleLengthCpu(divisor, divisorData),
|
||||
};
|
||||
Interlocked.Increment(ref _hits);
|
||||
}
|
||||
else
|
||||
{
|
||||
Interlocked.Increment(ref _misses);
|
||||
}
|
||||
|
||||
Console.WriteLine($"MersenneCpuDivisorScanSession, ExponentStepper hits: $_hits, misses: $_misses");
|
||||
}
|
||||
|
||||
public bool CheckDivisor(
|
||||
@@ -45,7 +53,154 @@ internal sealed class MersenneCpuDivisorScanSession(PrimeOrderCalculatorAccelera
|
||||
|
||||
if (divisorCycle == 0UL)
|
||||
{
|
||||
divisorCycle = _getCycleLength(divisor, divisorData);
|
||||
divisorCycle = DivisorCycleCache.Shared.GetCycleLengthCpu(divisor, divisorData);
|
||||
|
||||
// This never kicks off in production code
|
||||
// if (divisorCycle == 0UL)
|
||||
// {
|
||||
// // DivisorCycleCache guarantees a positive cycle for divisors greater than one.
|
||||
// throw new InvalidOperationException($"Divisor cycle solver returned zero for divisor {divisor}.");
|
||||
// }
|
||||
}
|
||||
|
||||
// Keep these remainder steppers in place so future updates continue reusing the previously computed residues.
|
||||
// They are critical for avoiding repeated full Montgomery exponentiation work when scanning divisors.
|
||||
CycleRemainderStepper cycleStepper = _cycleStepper;
|
||||
cycleStepper.CycleLength = divisorCycle;
|
||||
if (cycleStepper.Initialize(primes[0]) == 0UL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_exponentStepper is not { } exponentStepper)
|
||||
{
|
||||
_exponentStepper = exponentStepper = new(divisorData, divisorCycle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!exponentStepper.MatchesDivisor(divisorData, divisorCycle))
|
||||
{
|
||||
_exponentStepper = exponentStepper = new(divisorData, divisorCycle);
|
||||
}
|
||||
}
|
||||
|
||||
if (exponentStepper.InitializeCpuIsUnity(primes[0]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 1; i < length; i++)
|
||||
{
|
||||
if (cycleStepper.ComputeNext(primes[i]) != 0UL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (exponentStepper.ComputeNextIsUnity(primes[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public void Return() => ThreadStaticPools.ReturnMersenneCpuDivisorSession(this);
|
||||
}
|
||||
|
||||
internal struct MersenneCpuDivisorScanSessionWithHybridOrder() : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession
|
||||
{
|
||||
private PrimeOrderCalculatorAccelerator? _gpu;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public void Configure(PrimeOrderCalculatorAccelerator gpu)
|
||||
{
|
||||
_gpu = gpu;
|
||||
}
|
||||
|
||||
public bool CheckDivisor(
|
||||
ulong divisor,
|
||||
in MontgomeryDivisorData divisorData,
|
||||
ulong divisorCycle,
|
||||
in ReadOnlySpan<ulong> primes)
|
||||
{
|
||||
int length = primes.Length;
|
||||
var gpu = _gpu ?? throw new InvalidOperationException("Session was not configured with an accelerator.");
|
||||
if (divisorCycle == 0UL)
|
||||
{
|
||||
divisorCycle = DivisorCycleCache.Shared.GetCycleLengthHybrid(gpu, divisor, divisorData);
|
||||
}
|
||||
|
||||
// Keep these remainder steppers in place so future updates continue reusing the previously computed residues.
|
||||
// They are critical for avoiding repeated full Montgomery exponentiation work when scanning divisors.
|
||||
var cycleStepper = new CycleRemainderStepper(divisorCycle);
|
||||
if (cycleStepper.Initialize(primes[0]) == 0UL)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var exponentStepper = new ExponentRemainderStepperCpu(divisorData, divisorCycle);
|
||||
if (exponentStepper.InitializeCpuIsUnity(primes[0]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 1; i < length; i++)
|
||||
{
|
||||
if (cycleStepper.ComputeNext(primes[i]) != 0UL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (exponentStepper.ComputeNextIsUnity(primes[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public void Return() => ThreadStaticPools.ReturnMersenneCpuDivisorSession(this);
|
||||
}
|
||||
|
||||
internal struct MersenneCpuDivisorScanSessionWithGpuOrder() : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession
|
||||
{
|
||||
private PrimeOrderCalculatorAccelerator? _gpu;
|
||||
|
||||
public void Configure(PrimeOrderCalculatorAccelerator gpu)
|
||||
{
|
||||
_gpu = gpu;
|
||||
}
|
||||
|
||||
public bool CheckDivisor(
|
||||
ulong divisor,
|
||||
in MontgomeryDivisorData divisorData,
|
||||
ulong divisorCycle,
|
||||
in ReadOnlySpan<ulong> primes)
|
||||
{
|
||||
int length = primes.Length;
|
||||
var gpu = _gpu ?? throw new InvalidOperationException("Session was not configured with an accelerator.");
|
||||
// EvenPerfectBitScanner always provides at least one exponent on this path.
|
||||
// Keep the guard commented out for tests that might reuse the session differently.
|
||||
// if (length == 0)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// This never kicks off in production code
|
||||
// if (divisorData.Modulus != divisor)
|
||||
// {
|
||||
// throw new InvalidOperationException("Divisor data is for a different modulus");
|
||||
// // cachedData = MontgomeryDivisorData.FromModulus(divisor);
|
||||
// }
|
||||
|
||||
if (divisorCycle == 0UL)
|
||||
{
|
||||
divisorCycle = DivisorCycleCache.Shared.GetCycleLengthGpu(gpu, divisor, divisorData);
|
||||
|
||||
// This never kicks off in production code
|
||||
// if (divisorCycle == 0UL)
|
||||
// {
|
||||
@@ -84,6 +239,6 @@ internal sealed class MersenneCpuDivisorScanSession(PrimeOrderCalculatorAccelera
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Return() => ThreadStaticPools.ReturnMersenneCpuDivisorSession(this);
|
||||
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
// public void Return() => ThreadStaticPools.ReturnMersenneCpuDivisorSession(this);
|
||||
}
|
||||
Reference in new issue
Block a user