Add GPU options for by-divisor Montgomery data
This commit is contained in:
1 parent
ea29035c55
commit
483584b5d4
5 files changed
+449
-77
No files matched your search
@@ -19,7 +19,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
|
||||
private ulong _configuredMaxPrime;
|
||||
private ByDivisorDeltasDevice _deltasDevice = ByDivisorDeltasDevice.Cpu;
|
||||
|
||||
private ByDivisorMontgomeryDevice _montgomeryDevice = ByDivisorMontgomeryDevice.Cpu;
|
||||
|
||||
public int BatchSize
|
||||
{
|
||||
@@ -43,6 +43,18 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
}
|
||||
}
|
||||
|
||||
public ByDivisorMontgomeryDevice MontgomeryDevice
|
||||
{
|
||||
get => _montgomeryDevice;
|
||||
set
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
_montgomeryDevice = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ConfigureFromMaxPrime(ulong maxPrime)
|
||||
{
|
||||
lock (_sync)
|
||||
@@ -402,26 +414,51 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
MontgomeryDivisorData cachedDivisorData = default;
|
||||
bool hasCachedDivisorData = false;
|
||||
|
||||
byte step10 = (byte)(step % 10UL);
|
||||
byte step8 = (byte)(step % 8UL);
|
||||
byte step5 = (byte)(step % 5UL);
|
||||
byte step3 = (byte)(step % 3UL);
|
||||
byte step7 = (byte)(step % 7UL);
|
||||
byte step11 = (byte)(step % 11UL);
|
||||
const int RemainderTableSize = 6;
|
||||
byte[] remainderBuffer = ArrayPool<byte>.Shared.Rent(RemainderTableSize);
|
||||
byte[] stepBuffer = ArrayPool<byte>.Shared.Rent(RemainderTableSize);
|
||||
Span<byte> remainderSpan = remainderBuffer.AsSpan(0, RemainderTableSize);
|
||||
Span<byte> stepSpan = stepBuffer.AsSpan(0, RemainderTableSize);
|
||||
Span<byte> modulusSpan = stackalloc byte[RemainderTableSize]
|
||||
{
|
||||
10,
|
||||
8,
|
||||
5,
|
||||
3,
|
||||
7,
|
||||
11,
|
||||
};
|
||||
|
||||
ulong startDivisor64 = divisor128.Low;
|
||||
byte remainder10 = (byte)(startDivisor64 % 10UL);
|
||||
byte remainder8 = (byte)(startDivisor64 % 8UL);
|
||||
byte remainder5 = (byte)(startDivisor64 % 5UL);
|
||||
byte remainder3 = (byte)(startDivisor64 % 3UL);
|
||||
byte remainder7 = (byte)(startDivisor64 % 7UL);
|
||||
byte remainder11 = (byte)(startDivisor64 % 11UL);
|
||||
remainderSpan[0] = (byte)(startDivisor64 % 10UL);
|
||||
remainderSpan[1] = (byte)(startDivisor64 % 8UL);
|
||||
remainderSpan[2] = (byte)(startDivisor64 % 5UL);
|
||||
remainderSpan[3] = (byte)(startDivisor64 % 3UL);
|
||||
remainderSpan[4] = (byte)(startDivisor64 % 7UL);
|
||||
remainderSpan[5] = (byte)(startDivisor64 % 11UL);
|
||||
|
||||
stepSpan[0] = (byte)(step % 10UL);
|
||||
stepSpan[1] = (byte)(step % 8UL);
|
||||
stepSpan[2] = (byte)(step % 5UL);
|
||||
stepSpan[3] = (byte)(step % 3UL);
|
||||
stepSpan[4] = (byte)(step % 7UL);
|
||||
stepSpan[5] = (byte)(step % 11UL);
|
||||
|
||||
bool lastIsSeven = (prime & 3UL) == 3UL;
|
||||
|
||||
MersenneNumberDivisorRemainderGpuStepper remainderStepper = new(stepSpan, modulusSpan);
|
||||
MersenneNumberDivisorMontgomeryGpuBuilder? montgomeryBuilder = _montgomeryDevice == ByDivisorMontgomeryDevice.Gpu
|
||||
? new MersenneNumberDivisorMontgomeryGpuBuilder(batchCapacity)
|
||||
: null;
|
||||
MontgomeryDivisorData[]? montgomeryBuffer = montgomeryBuilder != null
|
||||
? ArrayPool<MontgomeryDivisorData>.Shared.Rent(batchCapacity)
|
||||
: null;
|
||||
|
||||
ulong remainingCandidates = ComputeRemainingCandidateCount(startDivisor64, limit64, step);
|
||||
|
||||
try
|
||||
{
|
||||
while (divisor128.CompareTo(limit128) <= 0)
|
||||
while (remainingCandidates > 0UL && divisor128.CompareTo(limit128) <= 0)
|
||||
{
|
||||
if (divisor128.High != 0UL)
|
||||
{
|
||||
@@ -429,7 +466,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
}
|
||||
|
||||
ulong currentDivisor = divisor128.Low;
|
||||
int chunkCount = ComputeChunkCount(currentDivisor, limit64, step, batchCapacity);
|
||||
int chunkCount = remainingCandidates > (ulong)batchCapacity
|
||||
? batchCapacity
|
||||
: (int)remainingCandidates;
|
||||
if (chunkCount <= 0)
|
||||
{
|
||||
break;
|
||||
@@ -442,22 +481,29 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
currentDivisor,
|
||||
step,
|
||||
limit64,
|
||||
remainder10,
|
||||
remainder8,
|
||||
remainder5,
|
||||
remainder3,
|
||||
remainder7,
|
||||
remainder11,
|
||||
step10,
|
||||
step8,
|
||||
step5,
|
||||
step3,
|
||||
step7,
|
||||
step11,
|
||||
remainderSpan[0],
|
||||
remainderSpan[1],
|
||||
remainderSpan[2],
|
||||
remainderSpan[3],
|
||||
remainderSpan[4],
|
||||
remainderSpan[5],
|
||||
stepSpan[0],
|
||||
stepSpan[1],
|
||||
stepSpan[2],
|
||||
stepSpan[3],
|
||||
stepSpan[4],
|
||||
stepSpan[5],
|
||||
lastIsSeven,
|
||||
candidateSpan,
|
||||
maskSpan);
|
||||
|
||||
Span<MontgomeryDivisorData> montgomerySpan = default;
|
||||
if (montgomeryBuilder != null && montgomeryBuffer != null)
|
||||
{
|
||||
montgomerySpan = montgomeryBuffer.AsSpan(0, chunkCount);
|
||||
montgomeryBuilder.Build(candidateSpan, montgomerySpan);
|
||||
}
|
||||
|
||||
for (int i = 0; i < chunkCount; i++)
|
||||
{
|
||||
if (enforceLimit && (iterationCounter == 0UL || (iterationCounter & 63UL) == 0UL) && limitGuard.HasExpired())
|
||||
@@ -477,16 +523,28 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasCachedDivisorData || cachedModulus != candidate)
|
||||
MontgomeryDivisorData divisorData;
|
||||
if (!montgomerySpan.IsEmpty)
|
||||
{
|
||||
cachedDivisorData = MontgomeryDivisorData.FromModulus(candidate);
|
||||
cachedModulus = candidate;
|
||||
hasCachedDivisorData = true;
|
||||
divisorData = montgomerySpan[i];
|
||||
if (divisorData.Modulus != candidate)
|
||||
{
|
||||
divisorData = MontgomeryDivisorData.FromModulus(candidate);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!hasCachedDivisorData || cachedModulus != candidate)
|
||||
{
|
||||
cachedDivisorData = MontgomeryDivisorData.FromModulus(candidate);
|
||||
cachedModulus = candidate;
|
||||
hasCachedDivisorData = true;
|
||||
}
|
||||
|
||||
divisorData = cachedDivisorData;
|
||||
}
|
||||
|
||||
MontgomeryDivisorData divisorData = cachedDivisorData;
|
||||
ulong divisorCycle;
|
||||
|
||||
if (candidate <= PerfectNumberConstants.MaxQForDivisorCycles)
|
||||
{
|
||||
divisorCycle = cycleCache.GetCycleLength(candidate);
|
||||
@@ -516,67 +574,40 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
increment.Mul((ulong)chunkCount);
|
||||
divisor128.Add(increment);
|
||||
|
||||
remainder10 = AdvanceRemainder(remainder10, step10, 10, chunkCount);
|
||||
remainder8 = AdvanceRemainder(remainder8, step8, 8, chunkCount);
|
||||
remainder5 = AdvanceRemainder(remainder5, step5, 5, chunkCount);
|
||||
remainder3 = AdvanceRemainder(remainder3, step3, 3, chunkCount);
|
||||
remainder7 = AdvanceRemainder(remainder7, step7, 7, chunkCount);
|
||||
remainder11 = AdvanceRemainder(remainder11, step11, 11, chunkCount);
|
||||
remainderStepper.Advance(chunkCount, remainderSpan);
|
||||
remainingCandidates -= (ulong)chunkCount;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
montgomeryBuilder?.Dispose();
|
||||
if (montgomeryBuffer != null)
|
||||
{
|
||||
ArrayPool<MontgomeryDivisorData>.Shared.Return(montgomeryBuffer, clearArray: false);
|
||||
}
|
||||
|
||||
remainderStepper.Dispose();
|
||||
ArrayPool<byte>.Shared.Return(remainderBuffer, clearArray: false);
|
||||
ArrayPool<byte>.Shared.Return(stepBuffer, clearArray: false);
|
||||
ArrayPool<ulong>.Shared.Return(candidateBuffer, clearArray: false);
|
||||
ArrayPool<byte>.Shared.Return(maskBuffer, clearArray: false);
|
||||
candidateEvaluator.Dispose();
|
||||
}
|
||||
|
||||
processedAll = divisor128.CompareTo(limit128) > 0;
|
||||
processedAll = remainingCandidates == 0UL && divisor128.CompareTo(limit128) > 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int ComputeChunkCount(ulong currentDivisor, ulong limit, ulong step, int maxCount)
|
||||
private static ulong ComputeRemainingCandidateCount(ulong currentDivisor, ulong limit, ulong step)
|
||||
{
|
||||
if (maxCount <= 0 || step == 0UL || currentDivisor > limit)
|
||||
if (step == 0UL || currentDivisor > limit)
|
||||
{
|
||||
return 0;
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
ulong distance = limit - currentDivisor;
|
||||
ulong stepsAvailable = step == 0UL ? 0UL : distance / step;
|
||||
ulong total = stepsAvailable + 1UL;
|
||||
if (total > (ulong)maxCount)
|
||||
{
|
||||
total = (ulong)maxCount;
|
||||
}
|
||||
|
||||
if (total > (ulong)int.MaxValue)
|
||||
{
|
||||
return int.MaxValue;
|
||||
}
|
||||
|
||||
return (int)total;
|
||||
}
|
||||
|
||||
private static byte AdvanceRemainder(byte remainder, byte step, byte modulus, int count)
|
||||
{
|
||||
if (modulus == 0 || count <= 0)
|
||||
{
|
||||
return remainder;
|
||||
}
|
||||
|
||||
int modulusValue = modulus;
|
||||
int remainderValue = remainder % modulusValue;
|
||||
int stepValue = step % modulusValue;
|
||||
|
||||
long delta = (long)stepValue * count;
|
||||
int adjusted = (int)((remainderValue + delta) % modulusValue);
|
||||
if (adjusted < 0)
|
||||
{
|
||||
adjusted += modulusValue;
|
||||
}
|
||||
|
||||
return (byte)adjusted;
|
||||
ulong stepsAvailable = distance / step;
|
||||
return stepsAvailable + 1UL;
|
||||
}
|
||||
|
||||
private static byte CheckDivisor(ulong prime, ulong divisorCycle, in MontgomeryDivisorData divisorData)
|
||||
|
||||
Reference in new issue
Block a user