Remove temporary by-divisor review documents
This commit is contained in:
1 parent
bd0727131f
commit
6dd5cea79f
27 files changed
+179
-281
No files matched your search
@@ -104,14 +104,7 @@ internal static class Program
|
|||||||
testPrimeCandidateLimit = Math.Max(1, threadCount) * 3;
|
testPrimeCandidateLimit = Math.Max(1, threadCount) * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useByDivisor)
|
_byDivisorStartPrime = useByDivisor && startPrimeProvided ? currentP : 0UL;
|
||||||
{
|
|
||||||
_byDivisorStartPrime = startPrimeProvided ? currentP : 0UL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_byDivisorStartPrime = 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useByDivisor && !testMode && string.IsNullOrEmpty(filterFile))
|
if (useByDivisor && !testMode && string.IsNullOrEmpty(filterFile))
|
||||||
{
|
{
|
||||||
@@ -177,10 +170,7 @@ internal static class Program
|
|||||||
|
|
||||||
Console.WriteLine("Divisor cycles are ready");
|
Console.WriteLine("Divisor cycles are ready");
|
||||||
|
|
||||||
if (useByDivisor)
|
blockSize = useByDivisor ? 1 : blockSize;
|
||||||
{
|
|
||||||
blockSize = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
CandidatesCalculator.Initialize(currentP);
|
CandidatesCalculator.Initialize(currentP);
|
||||||
PrimeTesters = new ThreadLocal<PrimeTester>(() => new PrimeTester(), trackAllValues: true);
|
PrimeTesters = new ThreadLocal<PrimeTester>(() => new PrimeTester(), trackAllValues: true);
|
||||||
|
|||||||
@@ -18,22 +18,33 @@ public class GpuPrimeLimiterTests
|
|||||||
var startedSecond = new TaskCompletionSource<bool>();
|
var startedSecond = new TaskCompletionSource<bool>();
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
|
|
||||||
using var first = GpuPrimeWorkLimiter.Acquire();
|
var first = GpuPrimeWorkLimiter.Acquire();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
var secondTask = Task.Run(() =>
|
var secondTask = Task.Run(() =>
|
||||||
{
|
{
|
||||||
using var second = GpuPrimeWorkLimiter.Acquire();
|
var second = GpuPrimeWorkLimiter.Acquire();
|
||||||
|
try
|
||||||
|
{
|
||||||
startedSecond.TrySetResult(true);
|
startedSecond.TrySetResult(true);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
second.Dispose();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
// Give secondTask a moment to attempt acquire (it should block).
|
// Give secondTask a moment to attempt acquire (it should block).
|
||||||
await Task.Delay(50);
|
await Task.Delay(50);
|
||||||
startedSecond.Task.IsCompleted.Should().BeFalse();
|
startedSecond.Task.IsCompleted.Should().BeFalse();
|
||||||
|
}
|
||||||
// Release first after short delay, allowing second to continue.
|
finally
|
||||||
// (Dispose at scope end, but we want to end now.)
|
{
|
||||||
|
// Release first after the initial wait so the second task can proceed.
|
||||||
first.Dispose();
|
first.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
await secondTask.WaitAsync(TimeSpan.FromSeconds(1));
|
await secondTask.WaitAsync(TimeSpan.FromSeconds(1));
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
|||||||
@@ -17,19 +17,31 @@ public class GpuWorkLimiterTests
|
|||||||
var startedSecond = new TaskCompletionSource<bool>();
|
var startedSecond = new TaskCompletionSource<bool>();
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
|
|
||||||
using var first = GpuWorkLimiter.Acquire();
|
var first = GpuWorkLimiter.Acquire();
|
||||||
sw.Start();
|
sw.Start();
|
||||||
|
|
||||||
var secondTask = Task.Run(() =>
|
var secondTask = Task.Run(() =>
|
||||||
{
|
{
|
||||||
using var second = GpuWorkLimiter.Acquire();
|
var second = GpuWorkLimiter.Acquire();
|
||||||
|
try
|
||||||
|
{
|
||||||
startedSecond.TrySetResult(true);
|
startedSecond.TrySetResult(true);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
second.Dispose();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
await Task.Delay(50);
|
await Task.Delay(50);
|
||||||
startedSecond.Task.IsCompleted.Should().BeFalse();
|
startedSecond.Task.IsCompleted.Should().BeFalse();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
first.Dispose();
|
first.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
await secondTask.WaitAsync(TimeSpan.FromSeconds(1));
|
await secondTask.WaitAsync(TimeSpan.FromSeconds(1));
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
||||||
tester.ConfigureFromMaxPrime(13UL);
|
tester.ConfigureFromMaxPrime(13UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] primes = { 5UL, 7UL, 11UL, 13UL };
|
ulong[] primes = { 5UL, 7UL, 11UL, 13UL };
|
||||||
byte[] hits = new byte[primes.Length];
|
byte[] hits = new byte[primes.Length];
|
||||||
|
|
||||||
@@ -43,6 +45,11 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
session.CheckDivisor(31UL, MontgomeryDivisorData.FromModulus(31UL), cycle31, primes, hits);
|
session.CheckDivisor(31UL, MontgomeryDivisorData.FromModulus(31UL), cycle31, primes, hits);
|
||||||
hits.Should().ContainInOrder(new byte[] { 1, 0, 0, 0 });
|
hits.Should().ContainInOrder(new byte[] { 1, 0, 0, 0 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
@@ -51,7 +58,9 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
||||||
tester.ConfigureFromMaxPrime(43UL);
|
tester.ConfigureFromMaxPrime(43UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
|
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -61,6 +70,11 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
|
|
||||||
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
@@ -69,7 +83,9 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
||||||
tester.ConfigureFromMaxPrime(61UL);
|
tester.ConfigureFromMaxPrime(61UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
|
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -79,5 +95,10 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
|
|
||||||
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +149,9 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorGpuTester();
|
var tester = new MersenneNumberDivisorByDivisorGpuTester();
|
||||||
tester.ConfigureFromMaxPrime(43UL);
|
tester.ConfigureFromMaxPrime(43UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] primes = { 31UL, 37UL, 41UL };
|
ulong[] primes = { 31UL, 37UL, 41UL };
|
||||||
byte[] hits = new byte[primes.Length];
|
byte[] hits = new byte[primes.Length];
|
||||||
|
|
||||||
@@ -157,6 +159,11 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
hits.Should().ContainInOrder(new byte[] { 0, 1, 0 });
|
hits.Should().ContainInOrder(new byte[] { 0, 1, 0 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
@@ -165,7 +172,9 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorGpuTester();
|
var tester = new MersenneNumberDivisorByDivisorGpuTester();
|
||||||
tester.ConfigureFromMaxPrime(43UL);
|
tester.ConfigureFromMaxPrime(43UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] primes = { 31UL, 37UL, 41UL, 43UL };
|
ulong[] primes = { 31UL, 37UL, 41UL, 43UL };
|
||||||
byte[] hits = new byte[primes.Length];
|
byte[] hits = new byte[primes.Length];
|
||||||
|
|
||||||
@@ -178,6 +187,11 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
session.CheckDivisor(13367UL, MontgomeryDivisorData.FromModulus(13367UL), cycle13367, primes, hits);
|
session.CheckDivisor(13367UL, MontgomeryDivisorData.FromModulus(13367UL), cycle13367, primes, hits);
|
||||||
hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 });
|
hits.Should().ContainInOrder(new byte[] { 0, 0, 1, 0 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
@@ -190,7 +204,9 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
tester.ConfigureFromMaxPrime(47UL);
|
tester.ConfigureFromMaxPrime(47UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
|
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
|
||||||
byte[] hits = new byte[primes.Length];
|
byte[] hits = new byte[primes.Length];
|
||||||
|
|
||||||
@@ -199,6 +215,11 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
|
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
@@ -210,7 +231,9 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
};
|
};
|
||||||
tester.ConfigureFromMaxPrime(43UL);
|
tester.ConfigureFromMaxPrime(43UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
|
ulong[] exponents = { 6UL, 7UL, 9UL, 10UL, 12UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -221,6 +244,11 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
@@ -232,7 +260,9 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
};
|
};
|
||||||
tester.ConfigureFromMaxPrime(61UL);
|
tester.ConfigureFromMaxPrime(61UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
|
ulong[] exponents = { 10UL, 11UL, 20UL, 21UL, 30UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -243,6 +273,11 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
hits.Should().Equal(new byte[] { 1, 0, 1, 0, 1 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Category", "Fast")]
|
[Trait("Category", "Fast")]
|
||||||
@@ -297,7 +332,9 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
tester.ConfigureFromMaxPrime(47UL);
|
tester.ConfigureFromMaxPrime(47UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
|
try
|
||||||
|
{
|
||||||
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
|
ulong[] primes = { 31UL, 37UL, 41UL, 43UL, 47UL };
|
||||||
byte[] hits = new byte[primes.Length];
|
byte[] hits = new byte[primes.Length];
|
||||||
|
|
||||||
@@ -306,5 +343,10 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
|
hits.Should().ContainInOrder(new byte[] { 0, 1, 0, 0, 0 });
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
session.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2,11 +2,8 @@ namespace PerfectNumbers.Core.Cpu;
|
|||||||
|
|
||||||
internal sealed class MersenneCpuDivisorScanSession : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession
|
internal sealed class MersenneCpuDivisorScanSession : IMersenneNumberDivisorByDivisorTester.IDivisorScanSession
|
||||||
{
|
{
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
_disposed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CheckDivisor(
|
public void CheckDivisor(
|
||||||
@@ -67,12 +64,6 @@ internal sealed class MersenneCpuDivisorScanSession : IMersenneNumberDivisorByDi
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
throw new ObjectDisposedException(nameof(MersenneCpuDivisorScanSession), "Divisor scan session disposed twice.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_disposed = true;
|
|
||||||
ThreadStaticPools.ReturnMersenneCpuDivisorSession(this);
|
ThreadStaticPools.ReturnMersenneCpuDivisorSession(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,14 +145,12 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
byte step10;
|
byte step10;
|
||||||
byte step8;
|
byte step8;
|
||||||
byte step5;
|
|
||||||
byte step3;
|
byte step3;
|
||||||
byte step7;
|
byte step7;
|
||||||
byte step11;
|
byte step11;
|
||||||
|
|
||||||
byte remainder10;
|
byte remainder10;
|
||||||
byte remainder8;
|
byte remainder8;
|
||||||
byte remainder5;
|
|
||||||
byte remainder3;
|
byte remainder3;
|
||||||
byte remainder7;
|
byte remainder7;
|
||||||
byte remainder11;
|
byte remainder11;
|
||||||
@@ -161,14 +159,12 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
{
|
{
|
||||||
step10 = (byte)(stepLow % 10UL);
|
step10 = (byte)(stepLow % 10UL);
|
||||||
step8 = (byte)(stepLow & 7UL);
|
step8 = (byte)(stepLow & 7UL);
|
||||||
step5 = (byte)(stepLow % 5UL);
|
|
||||||
step3 = (byte)(stepLow % 3UL);
|
step3 = (byte)(stepLow % 3UL);
|
||||||
step7 = (byte)(stepLow % 7UL);
|
step7 = (byte)(stepLow % 7UL);
|
||||||
step11 = (byte)(stepLow % 11UL);
|
step11 = (byte)(stepLow % 11UL);
|
||||||
|
|
||||||
remainder10 = (byte)(divisorLow % 10UL);
|
remainder10 = (byte)(divisorLow % 10UL);
|
||||||
remainder8 = (byte)(divisorLow & 7UL);
|
remainder8 = (byte)(divisorLow & 7UL);
|
||||||
remainder5 = (byte)(divisorLow % 5UL);
|
|
||||||
remainder3 = (byte)(divisorLow % 3UL);
|
remainder3 = (byte)(divisorLow % 3UL);
|
||||||
remainder7 = (byte)(divisorLow % 7UL);
|
remainder7 = (byte)(divisorLow % 7UL);
|
||||||
remainder11 = (byte)(divisorLow % 11UL);
|
remainder11 = (byte)(divisorLow % 11UL);
|
||||||
@@ -181,13 +177,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
decimalMask,
|
decimalMask,
|
||||||
step10,
|
step10,
|
||||||
step8,
|
step8,
|
||||||
step5,
|
|
||||||
step3,
|
step3,
|
||||||
step7,
|
step7,
|
||||||
step11,
|
step11,
|
||||||
remainder10,
|
remainder10,
|
||||||
remainder8,
|
remainder8,
|
||||||
remainder5,
|
|
||||||
remainder3,
|
remainder3,
|
||||||
remainder7,
|
remainder7,
|
||||||
remainder11,
|
remainder11,
|
||||||
@@ -197,21 +191,19 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
ulong divisorHigh = divisor.High;
|
ulong divisorHigh = divisor.High;
|
||||||
step10 = (byte)((((stepHigh % 10UL) * 6UL) + (stepLow % 10UL)) % 10UL);
|
step10 = (byte)((((stepHigh % 10UL) * 6UL) + (stepLow % 10UL)) % 10UL);
|
||||||
step8 = (byte)(stepLow % 8UL);
|
step8 = (byte)(stepLow % 8UL);
|
||||||
step5 = (byte)(((stepHigh % 5UL) + (stepLow % 5UL)) % 5UL);
|
|
||||||
step3 = (byte)(((stepHigh % 3UL) + (stepLow % 3UL)) % 3UL);
|
step3 = (byte)(((stepHigh % 3UL) + (stepLow % 3UL)) % 3UL);
|
||||||
step7 = (byte)((((stepHigh % 7UL) * 2UL) + (stepLow % 7UL)) % 7UL);
|
step7 = (byte)((((stepHigh % 7UL) * 2UL) + (stepLow % 7UL)) % 7UL);
|
||||||
step11 = (byte)((((stepHigh % 11UL) * 5UL) + (stepLow % 11UL)) % 11UL);
|
step11 = (byte)((((stepHigh % 11UL) * 5UL) + (stepLow % 11UL)) % 11UL);
|
||||||
|
|
||||||
remainder10 = (byte)((((divisorHigh % 10UL) * 6UL) + (divisorLow % 10UL)) % 10UL);
|
remainder10 = (byte)((((divisorHigh % 10UL) * 6UL) + (divisorLow % 10UL)) % 10UL);
|
||||||
remainder8 = (byte)(divisorLow % 8UL);
|
remainder8 = (byte)(divisorLow % 8UL);
|
||||||
remainder5 = (byte)(((divisorHigh % 5UL) + (divisorLow % 5UL)) % 5UL);
|
|
||||||
remainder3 = (byte)(((divisorHigh % 3UL) + (divisorLow % 3UL)) % 3UL);
|
remainder3 = (byte)(((divisorHigh % 3UL) + (divisorLow % 3UL)) % 3UL);
|
||||||
remainder7 = (byte)((((divisorHigh % 7UL) * 2UL) + (divisorLow % 7UL)) % 7UL);
|
remainder7 = (byte)((((divisorHigh % 7UL) * 2UL) + (divisorLow % 7UL)) % 7UL);
|
||||||
remainder11 = (byte)((((divisorHigh % 11UL) * 5UL) + (divisorLow % 11UL)) % 11UL);
|
remainder11 = (byte)((((divisorHigh % 11UL) * 5UL) + (divisorLow % 11UL)) % 11UL);
|
||||||
|
|
||||||
while (divisor.CompareTo(limit) <= 0)
|
while (divisor.CompareTo(limit) <= 0)
|
||||||
{
|
{
|
||||||
bool passesSmallModuli = remainder3 != 0 && remainder5 != 0 && remainder7 != 0 && remainder11 != 0;
|
bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0;
|
||||||
if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
|
if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
|
||||||
{
|
{
|
||||||
ulong candidate = divisor.Low;
|
ulong candidate = divisor.Low;
|
||||||
@@ -261,7 +253,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
divisor.Add(step);
|
divisor.Add(step);
|
||||||
remainder10 = AddMod10(remainder10, step10);
|
remainder10 = AddMod10(remainder10, step10);
|
||||||
remainder8 = AddMod8(remainder8, step8);
|
remainder8 = AddMod8(remainder8, step8);
|
||||||
remainder5 = AddMod5(remainder5, step5);
|
|
||||||
remainder3 = AddMod3(remainder3, step3);
|
remainder3 = AddMod3(remainder3, step3);
|
||||||
remainder7 = AddMod7(remainder7, step7);
|
remainder7 = AddMod7(remainder7, step7);
|
||||||
remainder11 = AddMod11(remainder11, step11);
|
remainder11 = AddMod11(remainder11, step11);
|
||||||
@@ -278,13 +269,11 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
ushort decimalMask,
|
ushort decimalMask,
|
||||||
byte step10,
|
byte step10,
|
||||||
byte step8,
|
byte step8,
|
||||||
byte step5,
|
|
||||||
byte step3,
|
byte step3,
|
||||||
byte step7,
|
byte step7,
|
||||||
byte step11,
|
byte step11,
|
||||||
byte remainder10,
|
byte remainder10,
|
||||||
byte remainder8,
|
byte remainder8,
|
||||||
byte remainder5,
|
|
||||||
byte remainder3,
|
byte remainder3,
|
||||||
byte remainder7,
|
byte remainder7,
|
||||||
byte remainder11,
|
byte remainder11,
|
||||||
@@ -297,7 +286,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
{
|
{
|
||||||
if (divisor <= limit)
|
if (divisor <= limit)
|
||||||
{
|
{
|
||||||
if (remainder3 != 0 && remainder5 != 0 && remainder7 != 0 && remainder11 != 0 && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
|
if (remainder3 != 0 && remainder7 != 0 && remainder11 != 0 && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
|
||||||
{
|
{
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
|
||||||
ulong divisorCycle;
|
ulong divisorCycle;
|
||||||
@@ -345,7 +334,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
bool passesSmallModuli = remainder3 != 0 && remainder5 != 0 && remainder7 != 0 && remainder11 != 0;
|
bool passesSmallModuli = remainder3 != 0 && remainder7 != 0 && remainder11 != 0;
|
||||||
if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
|
if (passesSmallModuli && (remainder8 == 1 || remainder8 == 7) && ((decimalMask >> remainder10) & 1) != 0)
|
||||||
{
|
{
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
|
||||||
@@ -389,7 +378,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
divisor += step;
|
divisor += step;
|
||||||
remainder10 = AddMod10(remainder10, step10);
|
remainder10 = AddMod10(remainder10, step10);
|
||||||
remainder8 = AddMod8(remainder8, step8);
|
remainder8 = AddMod8(remainder8, step8);
|
||||||
remainder5 = AddMod5(remainder5, step5);
|
|
||||||
remainder3 = AddMod3(remainder3, step3);
|
remainder3 = AddMod3(remainder3, step3);
|
||||||
remainder7 = AddMod7(remainder7, step7);
|
remainder7 = AddMod7(remainder7, step7);
|
||||||
remainder11 = AddMod11(remainder11, step11);
|
remainder11 = AddMod11(remainder11, step11);
|
||||||
@@ -416,19 +404,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
|
|||||||
return (byte)sum;
|
return (byte)sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static byte AddMod5(byte value, byte delta)
|
|
||||||
{
|
|
||||||
const int Modulus = 5;
|
|
||||||
int sum = value + delta;
|
|
||||||
|
|
||||||
if (sum >= Modulus)
|
|
||||||
{
|
|
||||||
sum -= Modulus;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (byte)sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static byte AddMod7(byte value, byte delta)
|
private static byte AddMod7(byte value, byte delta)
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ public static class GpuContextPool
|
|||||||
|
|
||||||
internal sealed class PooledContext
|
internal sealed class PooledContext
|
||||||
{
|
{
|
||||||
private bool disposed;
|
|
||||||
|
|
||||||
public Context Context { get; }
|
public Context Context { get; }
|
||||||
public Accelerator Accelerator { get; }
|
public Accelerator Accelerator { get; }
|
||||||
public bool IsCpu { get; }
|
public bool IsCpu { get; }
|
||||||
@@ -34,10 +32,6 @@ public static class GpuContextPool
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure all cached GPU buffers for this accelerator are released.
|
// Ensure all cached GPU buffers for this accelerator are released.
|
||||||
NttGpuMath.ClearCaches(Accelerator);
|
NttGpuMath.ClearCaches(Accelerator);
|
||||||
@@ -48,7 +42,6 @@ public static class GpuContextPool
|
|||||||
|
|
||||||
Accelerator.Dispose();
|
Accelerator.Dispose();
|
||||||
Context.Dispose();
|
Context.Dispose();
|
||||||
disposed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +124,6 @@ public static class GpuContextPool
|
|||||||
public struct GpuContextLease
|
public struct GpuContextLease
|
||||||
{
|
{
|
||||||
private readonly PooledContext _ctx;
|
private readonly PooledContext _ctx;
|
||||||
private bool disposed;
|
|
||||||
|
|
||||||
internal GpuContextLease(PooledContext ctx, object kernelInitLock)
|
internal GpuContextLease(PooledContext ctx, object kernelInitLock)
|
||||||
{
|
{
|
||||||
@@ -150,13 +142,8 @@ public static class GpuContextPool
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Return(_ctx);
|
Return(_ctx);
|
||||||
disposed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using ILGPU;
|
using ILGPU;
|
||||||
using ILGPU.Runtime;
|
using ILGPU.Runtime;
|
||||||
@@ -9,30 +10,28 @@ public sealed class GpuKernelLease
|
|||||||
{
|
{
|
||||||
private static readonly ConcurrentQueue<GpuKernelLease> Pool = new();
|
private static readonly ConcurrentQueue<GpuKernelLease> Pool = new();
|
||||||
|
|
||||||
private IDisposable? _limiter;
|
private Action? _releaseLimiter;
|
||||||
private GpuContextLease? _gpu;
|
private GpuContextLease? _gpu;
|
||||||
private KernelContainer? _kernels;
|
private KernelContainer? _kernels;
|
||||||
private AcceleratorStream? _stream;
|
private AcceleratorStream? _stream;
|
||||||
private object? _executionLock;
|
private object? _executionLock;
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
private GpuKernelLease()
|
private GpuKernelLease()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static GpuKernelLease Rent(IDisposable limiter, GpuContextLease gpu, KernelContainer kernels)
|
internal static GpuKernelLease Rent(GpuPrimeWorkLimiter.Lease limiter, GpuContextLease gpu, KernelContainer kernels)
|
||||||
{
|
{
|
||||||
if (!Pool.TryDequeue(out var lease))
|
if (!Pool.TryDequeue(out var lease))
|
||||||
{
|
{
|
||||||
lease = new GpuKernelLease();
|
lease = new GpuKernelLease();
|
||||||
}
|
}
|
||||||
|
|
||||||
lease._limiter = limiter;
|
lease._releaseLimiter = limiter.Dispose;
|
||||||
lease._gpu = gpu;
|
lease._gpu = gpu;
|
||||||
lease._kernels = kernels;
|
lease._kernels = kernels;
|
||||||
lease._stream = null;
|
lease._stream = null;
|
||||||
lease._executionLock = gpu.ExecutionLock;
|
lease._executionLock = gpu.ExecutionLock;
|
||||||
lease._disposed = false;
|
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,14 +157,7 @@ public sealed class GpuKernelLease
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
public void Dispose()
|
||||||
{
|
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (disposing)
|
|
||||||
{
|
{
|
||||||
_stream?.Dispose();
|
_stream?.Dispose();
|
||||||
_stream = null;
|
_stream = null;
|
||||||
@@ -175,20 +167,13 @@ public sealed class GpuKernelLease
|
|||||||
|
|
||||||
_executionLock = null;
|
_executionLock = null;
|
||||||
|
|
||||||
_limiter?.Dispose();
|
_releaseLimiter?.Invoke();
|
||||||
_limiter = null;
|
_releaseLimiter = null;
|
||||||
}
|
|
||||||
|
|
||||||
_kernels = null;
|
_kernels = null;
|
||||||
_disposed = true;
|
|
||||||
Pool.Enqueue(this);
|
Pool.Enqueue(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(disposing: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public readonly struct ExecutionScope
|
public readonly struct ExecutionScope
|
||||||
{
|
{
|
||||||
private readonly object? _lock;
|
private readonly object? _lock;
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ public static class GpuPrimeWorkLimiter
|
|||||||
private static readonly object _lock = new();
|
private static readonly object _lock = new();
|
||||||
private static int _currentLimit = 1;
|
private static int _currentLimit = 1;
|
||||||
|
|
||||||
public static IDisposable Acquire()
|
public static Lease Acquire()
|
||||||
{
|
{
|
||||||
// TODO: Inline the pooled limiter guard from the GpuLimiterThroughputBenchmarks so prime-sieve
|
// TODO: Inline the pooled limiter guard from the GpuLimiterThroughputBenchmarks so prime-sieve
|
||||||
// GPU jobs stop allocating Releaser instances on every acquisition.
|
// GPU jobs stop allocating Lease instances on every acquisition.
|
||||||
var sem = _semaphore;
|
var sem = _semaphore;
|
||||||
sem.Wait();
|
sem.Wait();
|
||||||
return new Releaser(sem);
|
return new Lease(sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetLimit(int value)
|
public static void SetLimit(int value)
|
||||||
@@ -36,25 +36,18 @@ public static class GpuPrimeWorkLimiter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class Releaser : IDisposable
|
public sealed class Lease
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _sem;
|
private readonly SemaphoreSlim _sem;
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
public Releaser(SemaphoreSlim sem)
|
internal Lease(SemaphoreSlim sem)
|
||||||
{
|
{
|
||||||
_sem = sem;
|
_sem = sem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_sem.Release();
|
_sem.Release();
|
||||||
_disposed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ public static class GpuWorkLimiter
|
|||||||
private static readonly object _lock = new();
|
private static readonly object _lock = new();
|
||||||
private static int _currentLimit = 1;
|
private static int _currentLimit = 1;
|
||||||
|
|
||||||
public static IDisposable Acquire()
|
public static Lease Acquire()
|
||||||
{
|
{
|
||||||
// TODO: Replace the per-call Releaser allocation with the pooled struct-based guard from the
|
// TODO: Replace the per-call Lease allocation with the pooled struct-based guard from the
|
||||||
// GpuLimiterThroughputBenchmarks so limiter acquisition does not allocate when we enter the
|
// GpuLimiterThroughputBenchmarks so limiter acquisition does not allocate when we enter the
|
||||||
// GPU scanning hot path.
|
// GPU scanning hot path.
|
||||||
var sem = _semaphore;
|
var sem = _semaphore;
|
||||||
sem.Wait();
|
sem.Wait();
|
||||||
return new Releaser(sem);
|
return new Lease(sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetLimit(int value)
|
public static void SetLimit(int value)
|
||||||
@@ -32,7 +32,7 @@ public static class GpuWorkLimiter
|
|||||||
|
|
||||||
// Swap to a new semaphore for the new limit. We intentionally
|
// Swap to a new semaphore for the new limit. We intentionally
|
||||||
// do not dispose the old semaphore to avoid releasing handles
|
// do not dispose the old semaphore to avoid releasing handles
|
||||||
// that may still be in use by existing Releaser instances.
|
// that may still be in use by existing Lease instances.
|
||||||
// TODO: Consolidate with GpuPrimeWorkLimiter so both limiters share a pooled SemaphoreSlim and avoid rebuilding the
|
// TODO: Consolidate with GpuPrimeWorkLimiter so both limiters share a pooled SemaphoreSlim and avoid rebuilding the
|
||||||
// limiter state whenever limits are adjusted from the CLI.
|
// limiter state whenever limits are adjusted from the CLI.
|
||||||
_semaphore = new SemaphoreSlim(value, value);
|
_semaphore = new SemaphoreSlim(value, value);
|
||||||
@@ -40,25 +40,18 @@ public static class GpuWorkLimiter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class Releaser : IDisposable
|
public sealed class Lease
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _sem;
|
private readonly SemaphoreSlim _sem;
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
public Releaser(SemaphoreSlim sem)
|
internal Lease(SemaphoreSlim sem)
|
||||||
{
|
{
|
||||||
_sem = sem;
|
_sem = sem;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_sem.Release();
|
_sem.Release();
|
||||||
_disposed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -220,7 +220,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
ulong stepValue = (ulong)twoP128;
|
ulong stepValue = (ulong)twoP128;
|
||||||
byte step10 = (byte)(stepValue % 10UL);
|
byte step10 = (byte)(stepValue % 10UL);
|
||||||
byte step8 = (byte)(stepValue & 7UL);
|
byte step8 = (byte)(stepValue & 7UL);
|
||||||
byte step5 = (byte)(stepValue % 5UL);
|
|
||||||
byte step3 = (byte)(stepValue % 3UL);
|
byte step3 = (byte)(stepValue % 3UL);
|
||||||
byte step7 = (byte)(stepValue % 7UL);
|
byte step7 = (byte)(stepValue % 7UL);
|
||||||
byte step11 = (byte)(stepValue % 11UL);
|
byte step11 = (byte)(stepValue % 11UL);
|
||||||
@@ -229,7 +228,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
ulong currentDivisorValue = (ulong)currentDivisor128;
|
ulong currentDivisorValue = (ulong)currentDivisor128;
|
||||||
byte remainder10 = (byte)(currentDivisorValue % 10UL);
|
byte remainder10 = (byte)(currentDivisorValue % 10UL);
|
||||||
byte remainder8 = (byte)(currentDivisorValue & 7UL);
|
byte remainder8 = (byte)(currentDivisorValue & 7UL);
|
||||||
byte remainder5 = (byte)(currentDivisorValue % 5UL);
|
|
||||||
byte remainder3 = (byte)(currentDivisorValue % 3UL);
|
byte remainder3 = (byte)(currentDivisorValue % 3UL);
|
||||||
byte remainder7 = (byte)(currentDivisorValue % 7UL);
|
byte remainder7 = (byte)(currentDivisorValue % 7UL);
|
||||||
byte remainder11 = (byte)(currentDivisorValue % 11UL);
|
byte remainder11 = (byte)(currentDivisorValue % 11UL);
|
||||||
@@ -275,14 +273,13 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
byte localRemainder10 = remainder10;
|
byte localRemainder10 = remainder10;
|
||||||
byte localRemainder8 = remainder8;
|
byte localRemainder8 = remainder8;
|
||||||
byte localRemainder5 = remainder5;
|
|
||||||
byte localRemainder3 = remainder3;
|
byte localRemainder3 = remainder3;
|
||||||
byte localRemainder7 = remainder7;
|
byte localRemainder7 = remainder7;
|
||||||
byte localRemainder11 = remainder11;
|
byte localRemainder11 = remainder11;
|
||||||
|
|
||||||
for (int i = 0; i < chunkCount; i++)
|
for (int i = 0; i < chunkCount; i++)
|
||||||
{
|
{
|
||||||
bool passesSmallModuli = localRemainder3 != 0 && localRemainder5 != 0 && localRemainder7 != 0 && localRemainder11 != 0;
|
bool passesSmallModuli = localRemainder3 != 0 && localRemainder7 != 0 && localRemainder11 != 0;
|
||||||
if (passesSmallModuli && (localRemainder8 == 1 || localRemainder8 == 7) && ((decimalMask >> localRemainder10) & 1) != 0)
|
if (passesSmallModuli && (localRemainder8 == 1 || localRemainder8 == 7) && ((decimalMask >> localRemainder10) & 1) != 0)
|
||||||
{
|
{
|
||||||
ulong divisorValue = (ulong)nextDivisor128;
|
ulong divisorValue = (ulong)nextDivisor128;
|
||||||
@@ -290,21 +287,16 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
ulong divisorCycle = ResolveDivisorCycle(divisorValue, prime, in montgomeryData);
|
ulong divisorCycle = ResolveDivisorCycle(divisorValue, prime, in montgomeryData);
|
||||||
if (divisorCycle == prime)
|
if (divisorCycle == prime)
|
||||||
{
|
{
|
||||||
int targetIndex = admissibleCount;
|
processedCount += (ulong)(i + 1);
|
||||||
divisorSpan[targetIndex] = divisorValue;
|
lastProcessed = divisorValue;
|
||||||
exponentSpan[targetIndex] = prime;
|
coveredRange = true;
|
||||||
divisorDataSpan[targetIndex] = new GpuDivisorPartialData(divisorValue);
|
return true;
|
||||||
offsetSpan[targetIndex] = targetIndex;
|
|
||||||
countSpan[targetIndex] = 1;
|
|
||||||
cycleSpan[targetIndex] = divisorCycle;
|
|
||||||
admissibleCount++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextDivisor128 += twoP128;
|
nextDivisor128 += twoP128;
|
||||||
localRemainder10 = AddMod10(localRemainder10, step10);
|
localRemainder10 = AddMod10(localRemainder10, step10);
|
||||||
localRemainder8 = AddMod8(localRemainder8, step8);
|
localRemainder8 = AddMod8(localRemainder8, step8);
|
||||||
localRemainder5 = AddMod5(localRemainder5, step5);
|
|
||||||
localRemainder3 = AddMod3(localRemainder3, step3);
|
localRemainder3 = AddMod3(localRemainder3, step3);
|
||||||
localRemainder7 = AddMod7(localRemainder7, step7);
|
localRemainder7 = AddMod7(localRemainder7, step7);
|
||||||
localRemainder11 = AddMod11(localRemainder11, step11);
|
localRemainder11 = AddMod11(localRemainder11, step11);
|
||||||
@@ -312,7 +304,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
remainder10 = localRemainder10;
|
remainder10 = localRemainder10;
|
||||||
remainder8 = localRemainder8;
|
remainder8 = localRemainder8;
|
||||||
remainder5 = localRemainder5;
|
|
||||||
remainder3 = localRemainder3;
|
remainder3 = localRemainder3;
|
||||||
remainder7 = localRemainder7;
|
remainder7 = localRemainder7;
|
||||||
remainder11 = localRemainder11;
|
remainder11 = localRemainder11;
|
||||||
@@ -380,19 +371,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
return (byte)sum;
|
return (byte)sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static byte AddMod5(byte value, byte delta)
|
|
||||||
{
|
|
||||||
const int Modulus = 5;
|
|
||||||
int sum = value + delta;
|
|
||||||
|
|
||||||
if (sum >= Modulus)
|
|
||||||
{
|
|
||||||
sum -= Modulus;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (byte)sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static byte AddMod7(byte value, byte delta)
|
private static byte AddMod7(byte value, byte delta)
|
||||||
@@ -490,7 +468,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
private MemoryBuffer1D<byte, Stride1D.Dense> _hitBuffer = null!;
|
private MemoryBuffer1D<byte, Stride1D.Dense> _hitBuffer = null!;
|
||||||
private ulong[] _hostBuffer = null!;
|
private ulong[] _hostBuffer = null!;
|
||||||
private int _capacity;
|
private int _capacity;
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner)
|
internal DivisorScanSession(MersenneNumberDivisorByDivisorGpuTester owner)
|
||||||
{
|
{
|
||||||
@@ -502,7 +479,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
internal void Reset()
|
internal void Reset()
|
||||||
{
|
{
|
||||||
_disposed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnsureExecutionResourcesLocked(int requiredCapacity)
|
private void EnsureExecutionResourcesLocked(int requiredCapacity)
|
||||||
@@ -549,11 +525,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
public void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes, Span<byte> hits)
|
public void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes, Span<byte> hits)
|
||||||
{
|
{
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
throw new ObjectDisposedException(nameof(DivisorScanSession));
|
|
||||||
}
|
|
||||||
|
|
||||||
int length = primes.Length;
|
int length = primes.Length;
|
||||||
// EvenPerfectBitScanner always supplies at least one exponent per divisor check, so the guard stays commented out.
|
// EvenPerfectBitScanner always supplies at least one exponent per divisor check, so the guard stays commented out.
|
||||||
// if (length == 0)
|
// if (length == 0)
|
||||||
@@ -622,12 +593,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
int sentinel = int.MaxValue;
|
int sentinel = int.MaxValue;
|
||||||
firstHitView.CopyFromCPU(ref sentinel, 1);
|
firstHitView.CopyFromCPU(ref sentinel, 1);
|
||||||
|
|
||||||
var kernel = _kernel;
|
var kernel = _kernel!;
|
||||||
if (kernel is null)
|
|
||||||
{
|
|
||||||
Monitor.Exit(_lease.ExecutionLock);
|
|
||||||
throw new InvalidOperationException("GPU divisor kernel was not initialized.");
|
|
||||||
}
|
|
||||||
|
|
||||||
kernel(1, divisorView, offsetView, countView, exponentView, cycleView, hitView, firstHitView);
|
kernel(1, divisorView, offsetView, countView, exponentView, cycleView, hitView, firstHitView);
|
||||||
|
|
||||||
@@ -640,12 +606,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_disposed = true;
|
|
||||||
_owner._sessionPool.Add(this);
|
_owner._sessionPool.Add(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -695,7 +655,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
private void ReturnBatchResources(BatchResources resources) => _resourcePool.Add(resources);
|
private void ReturnBatchResources(BatchResources resources) => _resourcePool.Add(resources);
|
||||||
|
|
||||||
private sealed class BatchResources : IDisposable
|
private sealed class BatchResources
|
||||||
{
|
{
|
||||||
private Accelerator? _accelerator;
|
private Accelerator? _accelerator;
|
||||||
private MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense>? _divisorDataBuffer;
|
private MemoryBuffer1D<GpuDivisorPartialData, Stride1D.Dense>? _divisorDataBuffer;
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
|||||||
int currentSize;
|
int currentSize;
|
||||||
int i;
|
int i;
|
||||||
UInt128 q = UInt128.Zero;
|
UInt128 q = UInt128.Zero;
|
||||||
try
|
|
||||||
{
|
|
||||||
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
while (kStart <= maxK && Volatile.Read(ref isPrime))
|
||||||
{
|
{
|
||||||
remaining = maxK - kStart + UInt128.One;
|
remaining = maxK - kStart + UInt128.One;
|
||||||
@@ -122,13 +120,10 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
|||||||
|
|
||||||
kStart += (UInt128)currentSize;
|
kStart += (UInt128)currentSize;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<ulong>.Shared.Return(orderArray);
|
ArrayPool<ulong>.Shared.Return(orderArray);
|
||||||
orderBuffer.Dispose();
|
orderBuffer.Dispose();
|
||||||
execution.Dispose();
|
execution.Dispose();
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -152,19 +152,13 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
}
|
}
|
||||||
|
|
||||||
GpuUInt128[] buffer = ArrayPool<GpuUInt128>.Shared.Rent(count);
|
GpuUInt128[] buffer = ArrayPool<GpuUInt128>.Shared.Rent(count);
|
||||||
try
|
|
||||||
{
|
|
||||||
ComputeResidues(exponents, buffer.AsSpan(0, count));
|
ComputeResidues(exponents, buffer.AsSpan(0, count));
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
results[i] = buffer[i].IsZero;
|
results[i] = buffer[i].IsZero;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<GpuUInt128>.Shared.Return(buffer);
|
ArrayPool<GpuUInt128>.Shared.Return(buffer);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
|
private bool IsMersennePrimeNtt(ulong exponent, GpuUInt128 nttMod, GpuUInt128 primitiveRoot, bool runOnGpu)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
|
|
||||||
var foundBuffer = accelerator.Allocate1D<int>(1); // TODO: Replace this allocation with the pooled device buffer from GpuOrderKernelBenchmarks so repeated scans reuse the pinned staging memory instead of allocating per run.
|
var foundBuffer = accelerator.Allocate1D<int>(1); // TODO: Replace this allocation with the pooled device buffer from GpuOrderKernelBenchmarks so repeated scans reuse the pinned staging memory instead of allocating per run.
|
||||||
exponent.Mod10_8_5_3Steps(out ulong step10, out ulong step8, out ulong step5, out ulong step3);
|
exponent.Mod10_8_5_3Steps(out ulong step10, out ulong step8, out ulong step5, out ulong step3);
|
||||||
try
|
|
||||||
{
|
|
||||||
UInt128 remaining;
|
UInt128 remaining;
|
||||||
int currentSize;
|
int currentSize;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
@@ -45,7 +44,6 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
q0.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
q0.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
||||||
var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
||||||
|
|
||||||
|
|
||||||
// Ensure device has small cycles table for early rejections in order kernels
|
// Ensure device has small cycles table for early rejections in order kernels
|
||||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||||
kernel(stream, currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
kernel(stream, currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
||||||
@@ -61,13 +59,9 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
|||||||
|
|
||||||
kStart += (UInt128)currentSize;
|
kStart += (UInt128)currentSize;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
foundBuffer.Dispose();
|
foundBuffer.Dispose();
|
||||||
execution.Dispose();
|
execution.Dispose();
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -161,7 +161,7 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
|
|||||||
private void ReturnResources(Accelerator accelerator, ResidueResources resources) =>
|
private void ReturnResources(Accelerator accelerator, ResidueResources resources) =>
|
||||||
_resourcePools.GetOrAdd(accelerator, static _ => new ConcurrentBag<ResidueResources>()).Add(resources);
|
_resourcePools.GetOrAdd(accelerator, static _ => new ConcurrentBag<ResidueResources>()).Add(resources);
|
||||||
|
|
||||||
private sealed class ResidueResources : IDisposable
|
private sealed class ResidueResources
|
||||||
{
|
{
|
||||||
internal ResidueResources(Accelerator accelerator, int capacity)
|
internal ResidueResources(Accelerator accelerator, int capacity)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public static class NttGpuMath
|
|||||||
|
|
||||||
private static readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<GpuUInt128>, int>> BitReverseKernelCache = new(); // TODO: Precompute bit-reversal kernels during boot so we can remove the concurrent lookup overhead flagged in the benchmarks.
|
private static readonly ConcurrentDictionary<Accelerator, Action<Index1D, ArrayView<GpuUInt128>, int>> BitReverseKernelCache = new(); // TODO: Precompute bit-reversal kernels during boot so we can remove the concurrent lookup overhead flagged in the benchmarks.
|
||||||
|
|
||||||
private sealed class SquareCacheEntry : IDisposable
|
private sealed class SquareCacheEntry
|
||||||
{
|
{
|
||||||
public MemoryBuffer1D<GpuUInt128, Stride1D.Dense> Buffer { get; }
|
public MemoryBuffer1D<GpuUInt128, Stride1D.Dense> Buffer { get; }
|
||||||
public GpuUInt128 Root { get; }
|
public GpuUInt128 Root { get; }
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ public interface IMersenneNumberDivisorByDivisorTester
|
|||||||
|
|
||||||
void PrepareCandidates(in ReadOnlySpan<ulong> primes, Span<ulong> allowedMaxValues);
|
void PrepareCandidates(in ReadOnlySpan<ulong> primes, Span<ulong> allowedMaxValues);
|
||||||
|
|
||||||
public interface IDivisorScanSession : IDisposable
|
public interface IDivisorScanSession
|
||||||
{
|
{
|
||||||
void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes, Span<byte> hits);
|
void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, in ReadOnlySpan<ulong> primes, Span<byte> hits);
|
||||||
|
|
||||||
|
void Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,20 +137,31 @@ public class MersenneDivisorCycles
|
|||||||
{
|
{
|
||||||
// Binary pairs: (ulong divisor, ulong cycle)
|
// Binary pairs: (ulong divisor, ulong cycle)
|
||||||
using var reader = new BinaryReader(compressor, Encoding.UTF8, leaveOpen: true);
|
using var reader = new BinaryReader(compressor, Encoding.UTF8, leaveOpen: true);
|
||||||
|
Stream stream = reader.BaseStream;
|
||||||
|
byte[] buffer = new byte[16];
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ulong d, c;
|
int read = 0;
|
||||||
try
|
Span<byte> span = buffer;
|
||||||
|
while (read < span.Length)
|
||||||
{
|
{
|
||||||
d = reader.ReadUInt64();
|
int chunk = stream.Read(span[read..]);
|
||||||
c = reader.ReadUInt64();
|
if (chunk == 0)
|
||||||
}
|
{
|
||||||
catch (EndOfStreamException)
|
if (read == 0)
|
||||||
{
|
{
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return (d, c);
|
throw new EndOfStreamException("Incomplete divisor-cycle entry.");
|
||||||
|
}
|
||||||
|
|
||||||
|
read += chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong divisor = BinaryPrimitives.ReadUInt64LittleEndian(span[..8]);
|
||||||
|
ulong cycle = BinaryPrimitives.ReadUInt64LittleEndian(span[8..]);
|
||||||
|
yield return (divisor, cycle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -167,14 +167,10 @@ public static class MersenneNumberDivisorByDivisorTester
|
|||||||
|
|
||||||
if (primesToTest.Count == 0)
|
if (primesToTest.Count == 0)
|
||||||
{
|
{
|
||||||
if (applyStartPrime)
|
string message = applyStartPrime
|
||||||
{
|
? $"No primes greater than or equal to {startPrime.ToString(CultureInfo.InvariantCulture)} were found for --mersenne=bydivisor."
|
||||||
Console.WriteLine($"No primes greater than or equal to {startPrime.ToString(CultureInfo.InvariantCulture)} were found for --mersenne=bydivisor.");
|
: "No prime candidates remain for --mersenne=bydivisor after filtering.";
|
||||||
}
|
Console.WriteLine(message);
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine("No prime candidates remain for --mersenne=bydivisor after filtering.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,8 +152,6 @@ public sealed class MersenneNumberTester(
|
|||||||
var stream = gpuLease.Stream;
|
var stream = gpuLease.Stream;
|
||||||
var orderKernel = gpuLease.OrderKernel!;
|
var orderKernel = gpuLease.OrderKernel!;
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Guard long-running kernels by chunking the warm-up across batches.
|
// Guard long-running kernels by chunking the warm-up across batches.
|
||||||
// Reuse the same ScanBatchSize knob used for scanning.
|
// Reuse the same ScanBatchSize knob used for scanning.
|
||||||
int batchSize = GpuConstants.ScanBatchSize;
|
int batchSize = GpuConstants.ScanBatchSize;
|
||||||
@@ -195,14 +193,11 @@ public sealed class MersenneNumberTester(
|
|||||||
orderBuffer.Dispose();
|
orderBuffer.Dispose();
|
||||||
qBuffer.Dispose();
|
qBuffer.Dispose();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
execution.Dispose();
|
execution.Dispose();
|
||||||
gpuLease.Dispose();
|
gpuLease.Dispose();
|
||||||
ArrayPool<UInt128>.Shared.Return(qs);
|
ArrayPool<UInt128>.Shared.Return(qs);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMersennePrime(ulong exponent)
|
public bool IsMersennePrime(ulong exponent)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public static class MersennePrimeFactorTester
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool IsPrimeFactor(ulong p, ulong q, CancellationToken ct)
|
public static bool IsPrimeFactor(ulong p, ulong q, CancellationToken ct)
|
||||||
{
|
{
|
||||||
if (q < 2UL || (q & 1UL) == 0)
|
if (q < 2UL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,22 +19,15 @@ internal static partial class PrimeOrderCalculator
|
|||||||
var exponentBufferArray = ThreadStaticPools.IntPool.Rent(GpuSmallPrimeFactorSlots);
|
var exponentBufferArray = ThreadStaticPools.IntPool.Rent(GpuSmallPrimeFactorSlots);
|
||||||
Span<ulong> primeBuffer = primeBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
|
Span<ulong> primeBuffer = primeBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
|
||||||
Span<int> exponentBuffer = exponentBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
|
Span<int> exponentBuffer = exponentBufferArray.AsSpan(0, GpuSmallPrimeFactorSlots);
|
||||||
// primeBuffer.Clear();
|
|
||||||
// exponentBuffer.Clear();
|
|
||||||
remaining = value;
|
remaining = value;
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
|
var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
|
||||||
var execution = lease.EnterExecutionScope();
|
var execution = lease.EnterExecutionScope();
|
||||||
try
|
|
||||||
{
|
|
||||||
Accelerator accelerator = lease.Accelerator;
|
Accelerator accelerator = lease.Accelerator;
|
||||||
AcceleratorStream stream = lease.Stream;
|
AcceleratorStream stream = lease.Stream;
|
||||||
|
|
||||||
SmallPrimeFactorTables tables = GpuKernelPool.EnsureSmallPrimeFactorTables(accelerator);
|
SmallPrimeFactorTables tables = GpuKernelPool.EnsureSmallPrimeFactorTables(accelerator);
|
||||||
SmallPrimeFactorScratch scratch = GpuKernelPool.EnsureSmallPrimeFactorScratch(accelerator, GpuSmallPrimeFactorSlots);
|
SmallPrimeFactorScratch scratch = GpuKernelPool.EnsureSmallPrimeFactorScratch(accelerator, GpuSmallPrimeFactorSlots);
|
||||||
// scratch.Clear();
|
|
||||||
|
|
||||||
var kernel = lease.SmallPrimeFactorKernel;
|
var kernel = lease.SmallPrimeFactorKernel;
|
||||||
kernel(
|
kernel(
|
||||||
@@ -68,27 +61,13 @@ internal static partial class PrimeOrderCalculator
|
|||||||
{
|
{
|
||||||
ulong primeValue = primeBuffer[i];
|
ulong primeValue = primeBuffer[i];
|
||||||
int exponent = exponentBuffer[i];
|
int exponent = exponentBuffer[i];
|
||||||
// This will never happen in production code
|
|
||||||
// if (primeValue == 0UL || exponent == 0)
|
|
||||||
// {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
counts.Add(primeValue, exponent);
|
counts.Add(primeValue, exponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
execution.Dispose();
|
execution.Dispose();
|
||||||
lease.Dispose();
|
lease.Dispose();
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ThreadStaticPools.UlongPool.Return(primeBufferArray);
|
ThreadStaticPools.UlongPool.Return(primeBufferArray);
|
||||||
ThreadStaticPools.IntPool.Return(exponentBufferArray);
|
ThreadStaticPools.IntPool.Return(exponentBufferArray);
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,9 +193,7 @@ internal static partial class PrimeOrderCalculator
|
|||||||
// {
|
// {
|
||||||
// return order;
|
// return order;
|
||||||
// }
|
// }
|
||||||
FactorEntry128[]? tempArray = pool.Rent(length + 1);
|
FactorEntry128[] tempArray = pool.Rent(length + 1);
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
Span<FactorEntry128> buffer = tempArray.AsSpan(0, length);
|
Span<FactorEntry128> buffer = tempArray.AsSpan(0, length);
|
||||||
factorSpan.CopyTo(buffer);
|
factorSpan.CopyTo(buffer);
|
||||||
@@ -228,12 +226,8 @@ internal static partial class PrimeOrderCalculator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
pool.Return(tempArray, clearArray: false);
|
pool.Return(tempArray, clearArray: false);
|
||||||
}
|
return order;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryConfirmOrderWide(in UInt128 prime, in UInt128 order, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
|
private static bool TryConfirmOrderWide(in UInt128 prime, in UInt128 order, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
|
||||||
|
|||||||
@@ -149,9 +149,8 @@ public sealed class PrimeTester
|
|||||||
|
|
||||||
internal static class PrimeTesterGpuContextPool
|
internal static class PrimeTesterGpuContextPool
|
||||||
{
|
{
|
||||||
internal sealed class PooledContext : IDisposable
|
internal sealed class PooledContext
|
||||||
{
|
{
|
||||||
private bool _disposed;
|
|
||||||
|
|
||||||
public Context Context { get; }
|
public Context Context { get; }
|
||||||
|
|
||||||
@@ -167,15 +166,9 @@ public sealed class PrimeTester
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_disposed)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrimeTester.ClearGpuCaches(Accelerator);
|
PrimeTester.ClearGpuCaches(Accelerator);
|
||||||
Accelerator.Dispose();
|
Accelerator.Dispose();
|
||||||
Context.Dispose();
|
Context.Dispose();
|
||||||
_disposed = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +202,7 @@ public sealed class PrimeTester
|
|||||||
Pool.Enqueue(ctx);
|
Pool.Enqueue(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal struct PrimeTesterGpuContextLease : IDisposable
|
internal struct PrimeTesterGpuContextLease
|
||||||
{
|
{
|
||||||
private PooledContext? _ctx;
|
private PooledContext? _ctx;
|
||||||
|
|
||||||
@@ -224,11 +217,7 @@ public sealed class PrimeTester
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (_ctx is { } ctx)
|
Return(_ctx ?? throw new InvalidOperationException("GPU context lease is not initialized."));
|
||||||
{
|
|
||||||
Return(ctx);
|
|
||||||
_ctx = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +246,7 @@ public sealed class PrimeTester
|
|||||||
DevicePrimes.View.CopyFromCPU(primes);
|
DevicePrimes.View.CopyFromCPU(primes);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal sealed class ScratchBuffers : IDisposable
|
internal sealed class ScratchBuffers
|
||||||
{
|
{
|
||||||
public MemoryBuffer1D<ulong, Stride1D.Dense> Input { get; private set; }
|
public MemoryBuffer1D<ulong, Stride1D.Dense> Input { get; private set; }
|
||||||
public MemoryBuffer1D<byte, Stride1D.Dense> Output { get; private set; }
|
public MemoryBuffer1D<byte, Stride1D.Dense> Output { get; private set; }
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core;
|
namespace PerfectNumbers.Core;
|
||||||
|
|
||||||
internal sealed class TaskThreadPool : IDisposable
|
internal sealed class TaskThreadPool
|
||||||
{
|
{
|
||||||
private readonly struct WorkItem
|
private readonly struct WorkItem
|
||||||
{
|
{
|
||||||
@@ -22,8 +22,6 @@ internal sealed class TaskThreadPool : IDisposable
|
|||||||
private readonly BlockingCollection<WorkItem> _pendingTasks;
|
private readonly BlockingCollection<WorkItem> _pendingTasks;
|
||||||
private readonly Thread[] _threads;
|
private readonly Thread[] _threads;
|
||||||
private readonly Action<Task> _taskExecutor;
|
private readonly Action<Task> _taskExecutor;
|
||||||
private int _disposed;
|
|
||||||
|
|
||||||
public TaskThreadPool(int minimumThreads, Action<Task> taskExecutor)
|
public TaskThreadPool(int minimumThreads, Action<Task> taskExecutor)
|
||||||
{
|
{
|
||||||
if (minimumThreads <= 0)
|
if (minimumThreads <= 0)
|
||||||
@@ -57,22 +55,18 @@ internal sealed class TaskThreadPool : IDisposable
|
|||||||
throw new ArgumentNullException(nameof(task));
|
throw new ArgumentNullException(nameof(task));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Volatile.Read(ref _disposed) != 0)
|
|
||||||
{
|
|
||||||
throw new ObjectDisposedException(nameof(TaskThreadPool));
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_pendingTasks.Add(new WorkItem(task));
|
_pendingTasks.Add(new WorkItem(task));
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException ex) when (Volatile.Read(ref _disposed) != 0)
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (ex is InvalidOperationException || ex is ObjectDisposedException)
|
||||||
{
|
{
|
||||||
throw new ObjectDisposedException(nameof(TaskThreadPool), ex);
|
throw new ObjectDisposedException(nameof(TaskThreadPool), ex);
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException ex)
|
|
||||||
{
|
throw;
|
||||||
throw new ObjectDisposedException(nameof(TaskThreadPool), ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,11 +91,6 @@ internal sealed class TaskThreadPool : IDisposable
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (Interlocked.Exchange(ref _disposed, 1) != 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_pendingTasks.CompleteAdding();
|
_pendingTasks.CompleteAdding();
|
||||||
|
|
||||||
foreach (Thread thread in _threads)
|
foreach (Thread thread in _threads)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ namespace PerfectNumbers.Core;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides thread-safe file writing for both text and binary data.
|
/// Provides thread-safe file writing for both text and binary data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class TextFileWriter : IDisposable
|
public sealed class TextFileWriter
|
||||||
{
|
{
|
||||||
private readonly FileStream _stream;
|
private readonly FileStream _stream;
|
||||||
private StreamWriter? _textWriter;
|
private StreamWriter? _textWriter;
|
||||||
|
|||||||
Reference in new issue
Block a user