Merge pull request #88 from mlemanczyk/codex/fix-divisor-cycle-handling-in-gpu-mode

Filter disallowed divisors when scanning by divisor
This commit is contained in:
Marek Lemańczyk authored and GitHub committed 2025-09-25 10:04:59 +02:00
commit 5bfc9b1c30
1 file changed
+98 -57
+98 -57
View File
@@ -1014,72 +1014,113 @@ internal static class Program
private static void RunByDivisorMode(List<ulong> primes, ulong divisorCyclesSearchLimit, int threadCount) => ByDivisorScanner.Run(primes, divisorCyclesSearchLimit, threadCount); private static void RunByDivisorMode(List<ulong> primes, ulong divisorCyclesSearchLimit, int threadCount) => ByDivisorScanner.Run(primes, divisorCyclesSearchLimit, threadCount);
private static ulong AcquireNextDivisor(ref ulong nextDivisor, ulong divisorLimit, ref int divisorsExhaustedFlag, ref long finalDivisorBits, out bool exhausted, ref ulong localDivisorCursor, ref int localDivisorsRemaining) private static ulong AcquireNextDivisor(ref ulong nextDivisor, ulong divisorLimit, ref int divisorsExhaustedFlag, ref long finalDivisorBits, out bool exhausted, ref ulong localDivisorCursor, ref int localDivisorsRemaining)
{ {
ref long nextDivisorBits = ref Unsafe.As<ulong, long>(ref nextDivisor); ref long nextDivisorBits = ref Unsafe.As<ulong, long>(ref nextDivisor);
ulong blockStride = unchecked(DivisorAllocationBlockSize * 2); ulong blockStride = unchecked(DivisorAllocationBlockSize * 2);
if (localDivisorsRemaining > 0) if (TryAcquireLocalDivisor(ref localDivisorCursor, ref localDivisorsRemaining, out ulong localDivisor))
{ {
ulong currentValue = localDivisorCursor; exhausted = false;
localDivisorCursor += 2UL; return localDivisor;
localDivisorsRemaining--; }
exhausted = false;
return currentValue;
}
while (true) while (true)
{ {
if (Volatile.Read(ref divisorsExhaustedFlag) != 0) if (Volatile.Read(ref divisorsExhaustedFlag) != 0)
{ {
exhausted = true; exhausted = true;
return 0UL; return 0UL;
} }
long currentBits = Volatile.Read(ref nextDivisorBits); long currentBits = Volatile.Read(ref nextDivisorBits);
ulong currentValue = unchecked((ulong)currentBits); ulong currentValue = unchecked((ulong)currentBits);
if (currentValue > divisorLimit) if (currentValue > divisorLimit)
{ {
if (Interlocked.CompareExchange(ref divisorsExhaustedFlag, 1, 0) == 0) if (Interlocked.CompareExchange(ref divisorsExhaustedFlag, 1, 0) == 0)
{ {
Volatile.Write(ref finalDivisorBits, currentBits); Volatile.Write(ref finalDivisorBits, currentBits);
} }
exhausted = true; exhausted = true;
return 0UL; return 0UL;
} }
ulong maximumNext = divisorLimit >= ulong.MaxValue - 1UL ? ulong.MaxValue : divisorLimit + 2UL; ulong maximumNext = divisorLimit >= ulong.MaxValue - 1UL ? ulong.MaxValue : divisorLimit + 2UL;
ulong requestedNext = currentValue > ulong.MaxValue - blockStride ? ulong.MaxValue : currentValue + blockStride; ulong requestedNext = currentValue > ulong.MaxValue - blockStride ? ulong.MaxValue : currentValue + blockStride;
if (requestedNext > maximumNext) if (requestedNext > maximumNext)
{ {
requestedNext = maximumNext; requestedNext = maximumNext;
} }
long nextBits = unchecked((long)requestedNext); long nextBits = unchecked((long)requestedNext);
if (Interlocked.CompareExchange(ref nextDivisorBits, nextBits, currentBits) != currentBits) if (Interlocked.CompareExchange(ref nextDivisorBits, nextBits, currentBits) != currentBits)
{ {
continue; continue;
} }
ulong available = requestedNext - currentValue; ulong available = requestedNext - currentValue;
if (available == 0UL) if (available == 0UL)
{ {
continue; continue;
} }
int count = (int)(available >> 1); int count = (int)(available >> 1);
if (count <= 0) if (count <= 0)
{ {
continue; continue;
} }
localDivisorCursor = currentValue + 2UL; localDivisorCursor = currentValue;
localDivisorsRemaining = count - 1; localDivisorsRemaining = count;
exhausted = false;
return currentValue; if (TryAcquireLocalDivisor(ref localDivisorCursor, ref localDivisorsRemaining, out ulong candidate))
} {
} exhausted = false;
return candidate;
}
// No valid divisor was found in this range; attempt to acquire the next block.
localDivisorCursor = 0UL;
localDivisorsRemaining = 0;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool TryAcquireLocalDivisor(ref ulong cursor, ref int remaining, out ulong divisor)
{
while (remaining > 0)
{
ulong candidate = cursor;
cursor += 2UL;
remaining--;
if (IsAllowedDivisorCandidate(candidate))
{
divisor = candidate;
return true;
}
}
divisor = 0UL;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsAllowedDivisorCandidate(ulong divisor)
{
if ((divisor & 1UL) == 0UL)
{
return false;
}
if ((divisor % 3UL) == 0UL || (divisor % 5UL) == 0UL || (divisor % 7UL) == 0UL || (divisor % 11UL) == 0UL)
{
return false;
}
return true;
}
private static int BuildPrimeBuffer(ulong divisor, in ulong[] primeValues, in ulong[] allowedMaxValues, int[] stateFlags, ulong[] primeBuffer, int[] indexBuffer, PendingResult[] completionsBuffer, ref int completionsCount, ref int remainingStates, long[] activeStateMask, ref int activeStartIndex) private static int BuildPrimeBuffer(ulong divisor, in ulong[] primeValues, in ulong[] allowedMaxValues, int[] stateFlags, ulong[] primeBuffer, int[] indexBuffer, PendingResult[] completionsBuffer, ref int completionsCount, ref int remainingStates, long[] activeStateMask, ref int activeStartIndex)
{ {