Clarify invariants across GPU divisor helpers
This commit is contained in:
1 parent
bccb2f43c9
commit
6e89700f80
5 files changed
+44
-52
No files matched your search
@@ -152,18 +152,14 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
// throw new ArgumentException("allowedMaxValues span must be at least as long as primes span.", nameof(allowedMaxValues));
|
||||
// }
|
||||
|
||||
ulong divisorLimit;
|
||||
|
||||
lock (_sync)
|
||||
if (!_isConfigured)
|
||||
{
|
||||
if (!_isConfigured)
|
||||
{
|
||||
throw new InvalidOperationException("ConfigureFromMaxPrime must be called before using the tester.");
|
||||
}
|
||||
|
||||
divisorLimit = _divisorLimit;
|
||||
throw new InvalidOperationException("ConfigureFromMaxPrime must be called before using the tester.");
|
||||
}
|
||||
|
||||
// Configuration is immutable after startup, so reading the cached limit does not require locking.
|
||||
ulong divisorLimit = _divisorLimit;
|
||||
|
||||
for (int index = 0; index < primes.Length; index++)
|
||||
{
|
||||
allowedMaxValues[index] = ComputeAllowedMaxDivisor(primes[index], divisorLimit);
|
||||
@@ -172,21 +168,18 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
|
||||
public IMersenneNumberDivisorByDivisorTester.IDivisorScanSession CreateDivisorSession()
|
||||
{
|
||||
lock (_sync)
|
||||
if (!_isConfigured)
|
||||
{
|
||||
if (!_isConfigured)
|
||||
{
|
||||
throw new InvalidOperationException("ConfigureFromMaxPrime must be called before using the tester.");
|
||||
}
|
||||
|
||||
if (_sessionPool.TryTake(out DivisorScanSession? session))
|
||||
{
|
||||
session.Reset();
|
||||
return session;
|
||||
}
|
||||
|
||||
return new DivisorScanSession(this);
|
||||
throw new InvalidOperationException("ConfigureFromMaxPrime must be called before using the tester.");
|
||||
}
|
||||
|
||||
if (_sessionPool.TryTake(out DivisorScanSession? session))
|
||||
{
|
||||
session.Reset();
|
||||
return session;
|
||||
}
|
||||
|
||||
return new DivisorScanSession(this);
|
||||
}
|
||||
|
||||
private void ReturnSession(DivisorScanSession session)
|
||||
@@ -323,11 +316,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
return true;
|
||||
}
|
||||
|
||||
// DivisorCycleCache guarantees a non-zero cycle for every divisor reached on the EvenPerfectBitScanner path.
|
||||
// if (divisorCycle == 0UL)
|
||||
// {
|
||||
// Console.WriteLine($"Divisor cycle was not calculated for {prime}");
|
||||
// }
|
||||
if (divisorCycle == 0UL)
|
||||
{
|
||||
// Keep this guard active to surface mismatches between generated candidates and the snapshot cache.
|
||||
Console.WriteLine($"Divisor cycle was not calculated for {prime}");
|
||||
}
|
||||
}
|
||||
|
||||
divisor += step;
|
||||
@@ -830,7 +823,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
int newCapacity = _bufferCapacity;
|
||||
if (newCapacity == 0)
|
||||
{
|
||||
// Fresh sessions start without buffers; seed the first rent with a single-slot array.
|
||||
// EvenPerfectBitScanner hits this branch on the first batch of each session, so keep the seed allocation.
|
||||
newCapacity = 1;
|
||||
}
|
||||
|
||||
@@ -908,6 +901,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
||||
{
|
||||
if (modulus == 0UL)
|
||||
{
|
||||
// A zero modulus indicates a missing cycle entry; preserve the fallback so snapshot regressions remain visible.
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,28 +64,22 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
||||
|
||||
public void ConfigureFromMaxPrime(ulong maxPrime)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
_divisorLimit = ComputeDivisorLimitFromMaxPrime(maxPrime);
|
||||
_isConfigured = true;
|
||||
}
|
||||
// Configuration happens once during startup, so no synchronization is required to cache the divisor limit.
|
||||
_divisorLimit = ComputeDivisorLimitFromMaxPrime(maxPrime);
|
||||
_isConfigured = true;
|
||||
}
|
||||
|
||||
public bool IsPrime(ulong prime, out bool divisorsExhausted, TimeSpan? timeLimit = null)
|
||||
{
|
||||
ulong allowedMax;
|
||||
int batchCapacity;
|
||||
// The CLI always configures the tester during startup, so the historical guard is commented out to avoid branching.
|
||||
// if (!_isConfigured)
|
||||
// {
|
||||
// throw new InvalidOperationException("ConfigureFromMaxPrime must be called before using the tester.");
|
||||
// }
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_isConfigured)
|
||||
{
|
||||
throw new InvalidOperationException("ConfigureFromMaxPrime must be called before using the tester.");
|
||||
}
|
||||
|
||||
allowedMax = ComputeAllowedMaxDivisor(prime, _divisorLimit);
|
||||
batchCapacity = _gpuBatchSize;
|
||||
}
|
||||
// Configuration is immutable, so the cached values can be read without locking.
|
||||
ulong allowedMax = ComputeAllowedMaxDivisor(prime, _divisorLimit);
|
||||
int batchCapacity = _gpuBatchSize;
|
||||
|
||||
// The GPU path always receives an allowed maximum well above the minimal divisor, so the legacy
|
||||
// guard stays commented out to document the invariant without branching.
|
||||
|
||||
@@ -75,7 +75,10 @@ internal sealed class MersenneNumberDivisorCandidateGpuEvaluator : IDisposable
|
||||
// return;
|
||||
// }
|
||||
|
||||
EnsureCapacity(count);
|
||||
if (count > _capacity)
|
||||
{
|
||||
EnsureCapacity(count);
|
||||
}
|
||||
|
||||
Span<ulong> hostCandidateSpan = _hostCandidates.AsSpan(0, count);
|
||||
Span<byte> hostMaskSpan = _hostMask.AsSpan(0, count);
|
||||
|
||||
@@ -52,7 +52,7 @@ internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
throw new InvalidOperationException("MersenneNumberDivisorRemainderGpuStepper was disposed more than once.");
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
@@ -78,10 +78,11 @@ internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (remainders.Length != _length)
|
||||
{
|
||||
throw new ArgumentException("Remainder buffer length must match the configured length.");
|
||||
}
|
||||
// Production code always calls the stepper with a fixed-length table, so the historical length guard stays commented.
|
||||
// if (remainders.Length != _length)
|
||||
// {
|
||||
// throw new ArgumentException("Remainder buffer length must match the configured length.");
|
||||
// }
|
||||
|
||||
Span<byte> hostRemainderSpan = _hostRemainders.AsSpan(0, _length);
|
||||
remainders.CopyTo(hostRemainderSpan);
|
||||
|
||||
@@ -33,7 +33,7 @@ internal sealed class MersenneNumberDivisorResidueGpuEvaluator : IDisposable
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
throw new InvalidOperationException("MersenneNumberDivisorResidueGpuEvaluator was disposed more than once.");
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
|
||||
Reference in new issue
Block a user