Merge pull request #168 from mlemanczyk/codex/remove-redundant-wrapper-methods-in-mersenne-path
Eliminate IDisposable dependencies
This commit is contained in:
28 files changed
+168
-126
No files matched your search
@@ -540,7 +540,7 @@ public class ProgramTests
|
|||||||
public void Main_displays_help_when_requested()
|
public void Main_displays_help_when_requested()
|
||||||
{
|
{
|
||||||
var main = typeof(Program).GetMethod("Main", BindingFlags.NonPublic | BindingFlags.Static)!;
|
var main = typeof(Program).GetMethod("Main", BindingFlags.NonPublic | BindingFlags.Static)!;
|
||||||
using var writer = new StringWriter();
|
var writer = new StringWriter();
|
||||||
TextWriter original = Console.Out;
|
TextWriter original = Console.Out;
|
||||||
Console.SetOut(writer);
|
Console.SetOut(writer);
|
||||||
|
|
||||||
@@ -554,6 +554,7 @@ public class ProgramTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
string output = writer.ToString();
|
string output = writer.ToString();
|
||||||
|
writer.Dispose();
|
||||||
output.Should().Contain("Usage:");
|
output.Should().Contain("Usage:");
|
||||||
output.Should().Contain("--mersenne-device=cpu|gpu");
|
output.Should().Contain("--mersenne-device=cpu|gpu");
|
||||||
output.Should().Contain("--primes-device=cpu|gpu");
|
output.Should().Contain("--primes-device=cpu|gpu");
|
||||||
|
|||||||
@@ -720,7 +720,21 @@ internal static class Program
|
|||||||
|
|
||||||
if (_useByDivisorMode)
|
if (_useByDivisorMode)
|
||||||
{
|
{
|
||||||
RunByDivisorMode(byDivisorCandidates, threadCount, _primeTestLimit);
|
if (_byDivisorTester is null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("By-divisor tester has not been initialized.");
|
||||||
|
}
|
||||||
|
|
||||||
|
MersenneNumberDivisorByDivisorTester.Run(
|
||||||
|
byDivisorCandidates,
|
||||||
|
_byDivisorTester,
|
||||||
|
_byDivisorPreviousResults,
|
||||||
|
_byDivisorStartPrime,
|
||||||
|
static () => _lastCompositeP = true,
|
||||||
|
static () => _lastCompositeP = false,
|
||||||
|
PrintResult,
|
||||||
|
threadCount,
|
||||||
|
_primeTestLimit);
|
||||||
FlushBuffer();
|
FlushBuffer();
|
||||||
StringBuilderPool.Return(_outputBuilder!);
|
StringBuilderPool.Return(_outputBuilder!);
|
||||||
return;
|
return;
|
||||||
@@ -861,27 +875,6 @@ internal static class Program
|
|||||||
return candidates;
|
return candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RunByDivisorMode(List<ulong> candidates, int threadCount, TimeSpan? primeTestLimit)
|
|
||||||
{
|
|
||||||
if (_byDivisorTester is null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("By-divisor tester has not been initialized.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Inline this helper by invoking MersenneNumberDivisorByDivisorTester.Run directly at call sites so
|
|
||||||
// the CLI avoids this extra frame during the hot composite-reporting path.
|
|
||||||
MersenneNumberDivisorByDivisorTester.Run(
|
|
||||||
candidates,
|
|
||||||
_byDivisorTester,
|
|
||||||
_byDivisorPreviousResults,
|
|
||||||
_byDivisorStartPrime,
|
|
||||||
static () => _lastCompositeP = true,
|
|
||||||
static () => _lastCompositeP = false,
|
|
||||||
PrintResult,
|
|
||||||
threadCount,
|
|
||||||
primeTestLimit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static unsafe void LoadResultsFile(string resultsFileName, Action<ulong, bool, bool> lineProcessorAction)
|
private static unsafe void LoadResultsFile(string resultsFileName, Action<ulong, bool, bool> lineProcessorAction)
|
||||||
{
|
{
|
||||||
using FileStream readStream = new(resultsFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
using FileStream readStream = new(resultsFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
|||||||
@@ -18,13 +18,14 @@ 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();
|
||||||
startedSecond.TrySetResult(true);
|
startedSecond.TrySetResult(true);
|
||||||
|
second.Dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Give secondTask a moment to attempt acquire (it should block).
|
// Give secondTask a moment to attempt acquire (it should block).
|
||||||
|
|||||||
@@ -34,23 +34,19 @@ public class NttMontgomeryTests
|
|||||||
|
|
||||||
// Device execution
|
// Device execution
|
||||||
GpuContextPool.GpuContextLease context = GpuContextPool.Rent();
|
GpuContextPool.GpuContextLease context = GpuContextPool.Rent();
|
||||||
try
|
var accelerator = context.Accelerator;
|
||||||
{
|
var buffer = accelerator.Allocate1D<GpuUInt128>(gpu.Length);
|
||||||
var accelerator = context.Accelerator;
|
buffer.View.CopyFromCPU(ref gpu[0], gpu.Length);
|
||||||
using var buffer = accelerator.Allocate1D<GpuUInt128>(gpu.Length);
|
NttGpuMath.SquareDevice(accelerator, buffer.View, modulus, primitiveRoot);
|
||||||
buffer.View.CopyFromCPU(ref gpu[0], gpu.Length);
|
buffer.View.CopyToCPU(ref gpu[0], gpu.Length);
|
||||||
NttGpuMath.SquareDevice(accelerator, buffer.View, modulus, primitiveRoot);
|
|
||||||
buffer.View.CopyToCPU(ref gpu[0], gpu.Length);
|
|
||||||
|
|
||||||
for (int i = 0; i < cpu.Length; i++)
|
for (int i = 0; i < cpu.Length; i++)
|
||||||
{
|
|
||||||
gpu[i].Should().Be(cpu[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
{
|
||||||
context.Dispose();
|
gpu[i].Should().Be(cpu[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer.Dispose();
|
||||||
|
context.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ 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();
|
||||||
startedSecond.TrySetResult(true);
|
startedSecond.TrySetResult(true);
|
||||||
|
second.Dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
await Task.Delay(50);
|
await Task.Delay(50);
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ public class MersenneDivisorCyclesGenerateGpuTests
|
|||||||
{
|
{
|
||||||
MersenneDivisorCycles.GenerateGpu(path, maxDivisor: 50UL, batchSize: 16, skipCount: 0, nextPosition: 0);
|
MersenneDivisorCycles.GenerateGpu(path, maxDivisor: 50UL, batchSize: 16, skipCount: 0, nextPosition: 0);
|
||||||
var pairs = new List<(ulong divisor, ulong cycle)>();
|
var pairs = new List<(ulong divisor, ulong cycle)>();
|
||||||
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
using var reader = new BinaryReader(stream);
|
var reader = new BinaryReader(stream);
|
||||||
while (stream.Position < stream.Length)
|
while (stream.Position < stream.Length)
|
||||||
{
|
{
|
||||||
ulong d = reader.ReadUInt64();
|
ulong d = reader.ReadUInt64();
|
||||||
@@ -41,6 +41,9 @@ public class MersenneDivisorCyclesGenerateGpuTests
|
|||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(pair.divisor);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(pair.divisor);
|
||||||
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLength(pair.divisor, divisorData));
|
pair.cycle.Should().Be(MersenneDivisorCycles.CalculateCycleLength(pair.divisor, divisorData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader.Dispose();
|
||||||
|
stream.Dispose();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -61,8 +64,8 @@ public class MersenneDivisorCyclesGenerateGpuTests
|
|||||||
MersenneDivisorCycles.Generate(path, maxDivisor: 50UL, threads: 4);
|
MersenneDivisorCycles.Generate(path, maxDivisor: 50UL, threads: 4);
|
||||||
|
|
||||||
var pairs = new List<(ulong divisor, ulong cycle)>();
|
var pairs = new List<(ulong divisor, ulong cycle)>();
|
||||||
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||||
using var reader = new BinaryReader(stream);
|
var reader = new BinaryReader(stream);
|
||||||
while (stream.Position < stream.Length)
|
while (stream.Position < stream.Length)
|
||||||
{
|
{
|
||||||
ulong divisor = reader.ReadUInt64();
|
ulong divisor = reader.ReadUInt64();
|
||||||
@@ -95,6 +98,9 @@ public class MersenneDivisorCyclesGenerateGpuTests
|
|||||||
|
|
||||||
var (_, completeCount) = MersenneDivisorCycles.FindLast(path);
|
var (_, completeCount) = MersenneDivisorCycles.FindLast(path);
|
||||||
completeCount.Should().Be(expected.Count);
|
completeCount.Should().Be(expected.Count);
|
||||||
|
|
||||||
|
reader.Dispose();
|
||||||
|
stream.Dispose();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
ulong[] exponents = { 59UL, 61UL, 67UL, 71UL, 73UL, 79UL, 117_652UL, 333_380UL };
|
ulong[] exponents = { 59UL, 61UL, 67UL, 71UL, 73UL, 79UL, 117_652UL, 333_380UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -74,6 +74,8 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
hits.Should().Equal(expected2);
|
hits.Should().Equal(expected2);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -83,7 +85,7 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(LargeDivisor1);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(LargeDivisor1);
|
||||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(LargeDivisor1, divisorData);
|
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(LargeDivisor1, divisorData);
|
||||||
|
|
||||||
@@ -98,6 +100,8 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
hits.Should().Equal(expected);
|
hits.Should().Equal(expected);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -107,7 +111,7 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
var tester = new MersenneNumberDivisorByDivisorCpuTester();
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(LargeDivisor2);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(LargeDivisor2);
|
||||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(LargeDivisor2, divisorData);
|
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(LargeDivisor2, divisorData);
|
||||||
|
|
||||||
@@ -122,5 +126,7 @@ public class MersenneNumberDivisorCpuTesterTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
hits.Should().Equal(expected);
|
hits.Should().Equal(expected);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorGpuTester();
|
var tester = new MersenneNumberDivisorByDivisorGpuTester();
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
ulong[] exponents = { 59UL, 61UL, 67UL, 71UL, 73UL, 79UL, 117_652UL, 333_380UL };
|
ulong[] exponents = { 59UL, 61UL, 67UL, 71UL, 73UL, 79UL, 117_652UL, 333_380UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -185,6 +185,8 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
hits.Should().Equal(expected2);
|
hits.Should().Equal(expected2);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -198,7 +200,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
ulong[] exponents = { 59UL, 61UL, 67UL, 71UL, 73UL, 79UL, 117_652UL };
|
ulong[] exponents = { 59UL, 61UL, 67UL, 71UL, 73UL, 79UL, 117_652UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -213,6 +215,8 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
hits.Should().Equal(expected);
|
hits.Should().Equal(expected);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -225,7 +229,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
};
|
};
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(4_000_169UL);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(4_000_169UL);
|
||||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(4_000_169UL, divisorData);
|
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(4_000_169UL, divisorData);
|
||||||
|
|
||||||
@@ -252,6 +256,8 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
expected.Should().Equal(direct);
|
expected.Should().Equal(direct);
|
||||||
hits.Should().Equal(direct);
|
hits.Should().Equal(direct);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -264,7 +270,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
};
|
};
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(4_000_561UL);
|
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(4_000_561UL);
|
||||||
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(4_000_561UL, divisorData);
|
ulong cycle = MersenneDivisorCycles.CalculateCycleLength(4_000_561UL, divisorData);
|
||||||
|
|
||||||
@@ -291,6 +297,8 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
expected.Should().Equal(direct);
|
expected.Should().Equal(direct);
|
||||||
hits.Should().Equal(direct);
|
hits.Should().Equal(direct);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -300,7 +308,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
var tester = new MersenneNumberDivisorByDivisorGpuTester();
|
var tester = new MersenneNumberDivisorByDivisorGpuTester();
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
ulong[] exponents = { 59UL, 67UL, 117_652UL };
|
ulong[] exponents = { 59UL, 67UL, 117_652UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -316,6 +324,8 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
hits.Should().Equal(expected);
|
hits.Should().Equal(expected);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -329,7 +339,7 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
|
|
||||||
tester.ConfigureFromMaxPrime(197UL);
|
tester.ConfigureFromMaxPrime(197UL);
|
||||||
|
|
||||||
using var session = tester.CreateDivisorSession();
|
var session = tester.CreateDivisorSession();
|
||||||
ulong[] exponents = { 59UL, 61UL, 67UL, 71UL, 73UL, 79UL, 117_652UL };
|
ulong[] exponents = { 59UL, 61UL, 67UL, 71UL, 73UL, 79UL, 117_652UL };
|
||||||
byte[] hits = new byte[exponents.Length];
|
byte[] hits = new byte[exponents.Length];
|
||||||
|
|
||||||
@@ -344,6 +354,8 @@ public class MersenneNumberDivisorGpuTesterTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
hits.Should().Equal(expected);
|
hits.Should().Equal(expected);
|
||||||
|
|
||||||
|
session.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,10 +76,10 @@ public readonly struct ResiduePrimeViews(
|
|||||||
public readonly ArrayView1D<ulong, Stride1D.Dense> LastSevenPow2 = lastSevenPow2;
|
public readonly ArrayView1D<ulong, Stride1D.Dense> LastSevenPow2 = lastSevenPow2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, KernelContainer kernels)
|
public ref struct GpuKernelLease(GpuPrimeWorkLimiter.Lease limiter, GpuContextLease gpu, KernelContainer kernels)
|
||||||
{
|
{
|
||||||
private bool disposedValue;
|
private bool disposedValue;
|
||||||
private IDisposable? _limiter = limiter;
|
private GpuPrimeWorkLimiter.Lease? _limiter = limiter;
|
||||||
private GpuContextLease? _gpu = gpu;
|
private GpuContextLease? _gpu = gpu;
|
||||||
private KernelContainer _kernels = kernels;
|
private KernelContainer _kernels = kernels;
|
||||||
private AcceleratorStream? _stream;
|
private AcceleratorStream? _stream;
|
||||||
|
|||||||
@@ -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 Releaser 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,12 +36,12 @@ public static class GpuPrimeWorkLimiter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class Releaser : IDisposable
|
public sealed class Lease
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _sem;
|
private readonly SemaphoreSlim _sem;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public Releaser(SemaphoreSlim sem)
|
public Lease(SemaphoreSlim sem)
|
||||||
{
|
{
|
||||||
_sem = sem;
|
_sem = sem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 Releaser 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)
|
||||||
@@ -40,12 +40,12 @@ public static class GpuWorkLimiter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class Releaser : IDisposable
|
public sealed class Lease
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _sem;
|
private readonly SemaphoreSlim _sem;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public Releaser(SemaphoreSlim sem)
|
public Lease(SemaphoreSlim sem)
|
||||||
{
|
{
|
||||||
_sem = sem;
|
_sem = sem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@@ -122,6 +123,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
resources.CycleCandidates,
|
resources.CycleCandidates,
|
||||||
resources.CycleLengths,
|
resources.CycleLengths,
|
||||||
resources.CycleCapacity,
|
resources.CycleCapacity,
|
||||||
|
resources,
|
||||||
out lastProcessed,
|
out lastProcessed,
|
||||||
out coveredRange,
|
out coveredRange,
|
||||||
out processedCount
|
out processedCount
|
||||||
@@ -186,6 +188,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
ulong[] cycleCandidates,
|
ulong[] cycleCandidates,
|
||||||
ulong[] cycleLengths,
|
ulong[] cycleLengths,
|
||||||
int cycleCapacity,
|
int cycleCapacity,
|
||||||
|
BatchResources resources,
|
||||||
out ulong lastProcessed,
|
out ulong lastProcessed,
|
||||||
out bool coveredRange,
|
out bool coveredRange,
|
||||||
out ulong processedCount)
|
out ulong processedCount)
|
||||||
@@ -340,10 +343,10 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
gapView.CopyFromCPU(ref MemoryMarshal.GetReference(gapSpan), chunkCount);
|
gapView.CopyFromCPU(ref MemoryMarshal.GetReference(gapSpan), chunkCount);
|
||||||
|
|
||||||
ComputeRemaindersOnGpu(chunkCount, remainder10, 10, gapView, deltaView, remainder10View, remainderDeltaKernel, remainderScanKernel);
|
ComputeRemaindersOnGpu(chunkCount, remainder10, 10, gapView, deltaView, remainder10View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
|
||||||
ComputeRemaindersOnGpu(chunkCount, remainder8, 8, gapView, deltaView, remainder8View, remainderDeltaKernel, remainderScanKernel);
|
ComputeRemaindersOnGpu(chunkCount, remainder8, 8, gapView, deltaView, remainder8View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
|
||||||
ComputeRemaindersOnGpu(chunkCount, remainder5, 5, gapView, deltaView, remainder5View, remainderDeltaKernel, remainderScanKernel);
|
ComputeRemaindersOnGpu(chunkCount, remainder5, 5, gapView, deltaView, remainder5View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
|
||||||
ComputeRemaindersOnGpu(chunkCount, remainder3, 3, gapView, deltaView, remainder3View, remainderDeltaKernel, remainderScanKernel);
|
ComputeRemaindersOnGpu(chunkCount, remainder3, 3, gapView, deltaView, remainder3View, remainderDeltaKernel, remainderScanKernel, resources.GetRemainderScanConfig);
|
||||||
|
|
||||||
BuildCandidateMaskOnGpu(chunkCount, remainder10View, remainder8View, remainder5View, remainder3View, lastIsSevenFlag, maskView, maskSpan, candidateMaskKernel);
|
BuildCandidateMaskOnGpu(chunkCount, remainder10View, remainder8View, remainder5View, remainder3View, lastIsSevenFlag, maskView, maskSpan, candidateMaskKernel);
|
||||||
|
|
||||||
@@ -461,7 +464,8 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
ArrayView1D<byte, Stride1D.Dense> deltaView,
|
ArrayView1D<byte, Stride1D.Dense> deltaView,
|
||||||
ArrayView1D<byte, Stride1D.Dense> remainderView,
|
ArrayView1D<byte, Stride1D.Dense> remainderView,
|
||||||
Action<Index1D, ArrayView<ulong>, ArrayView<byte>, byte> deltaKernel,
|
Action<Index1D, ArrayView<ulong>, ArrayView<byte>, byte> deltaKernel,
|
||||||
Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<byte>, byte, byte> scanKernel)
|
Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<byte>, byte, byte> scanKernel,
|
||||||
|
Func<int, KernelConfig> configProvider)
|
||||||
{
|
{
|
||||||
// GPU batches always contain at least one divisor gap, so the empty-count guard remains commented
|
// GPU batches always contain at least one divisor gap, so the empty-count guard remains commented
|
||||||
// to eliminate redundant branching.
|
// to eliminate redundant branching.
|
||||||
@@ -471,10 +475,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
deltaKernel(count, gapView, deltaView, modulus);
|
deltaKernel(count, gapView, deltaView, modulus);
|
||||||
SharedMemoryConfig sharedMemoryConfig = SharedMemoryConfig.RequestDynamic<int>(count);
|
KernelConfig kernelConfig = configProvider(count);
|
||||||
Index1D gridDim = new Index1D(1);
|
|
||||||
Index1D groupDim = new Index1D(count);
|
|
||||||
KernelConfig kernelConfig = new KernelConfig(gridDim, groupDim, sharedMemoryConfig);
|
|
||||||
|
|
||||||
scanKernel(kernelConfig, new Index1D(count), deltaView, remainderView, baseRemainder, modulus);
|
scanKernel(kernelConfig, new Index1D(count), deltaView, remainderView, baseRemainder, modulus);
|
||||||
}
|
}
|
||||||
@@ -844,7 +845,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
private void ReturnBatchResources(Accelerator accelerator, BatchResources resources) => _resourcePools.GetOrAdd(accelerator, static _ => []).Add(resources);
|
private void ReturnBatchResources(Accelerator accelerator, BatchResources resources) => _resourcePools.GetOrAdd(accelerator, static _ => []).Add(resources);
|
||||||
|
|
||||||
private sealed class BatchResources : IDisposable
|
private sealed class BatchResources
|
||||||
{
|
{
|
||||||
internal BatchResources(MersenneNumberDivisorByDivisorGpuTester owner, Accelerator accelerator, int capacity)
|
internal BatchResources(MersenneNumberDivisorByDivisorGpuTester owner, Accelerator accelerator, int capacity)
|
||||||
{
|
{
|
||||||
@@ -906,10 +907,24 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
internal readonly Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<byte>, byte, byte> RemainderScanKernel;
|
internal readonly Action<KernelConfig, Index1D, ArrayView<byte>, ArrayView<byte>, byte, byte> RemainderScanKernel;
|
||||||
internal readonly Action<Index1D, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, byte, ArrayView<byte>> CandidateMaskKernel;
|
internal readonly Action<Index1D, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, ArrayView<byte>, byte, ArrayView<byte>> CandidateMaskKernel;
|
||||||
|
|
||||||
|
private readonly Dictionary<int, KernelConfig> _remainderScanConfigs = new();
|
||||||
|
|
||||||
internal readonly int Capacity;
|
internal readonly int Capacity;
|
||||||
|
|
||||||
internal readonly int CycleCapacity;
|
internal readonly int CycleCapacity;
|
||||||
|
|
||||||
|
internal KernelConfig GetRemainderScanConfig(int count)
|
||||||
|
{
|
||||||
|
if (!_remainderScanConfigs.TryGetValue(count, out KernelConfig config))
|
||||||
|
{
|
||||||
|
SharedMemoryConfig sharedMemoryConfig = SharedMemoryConfig.RequestDynamic<int>(count);
|
||||||
|
config = new KernelConfig(new Index1D(1), new Index1D(count), sharedMemoryConfig);
|
||||||
|
_remainderScanConfigs[count] = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
DivisorsBuffer.Dispose();
|
DivisorsBuffer.Dispose();
|
||||||
@@ -948,7 +963,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
return ComputeAllowedMaxDivisor(prime, _divisorLimit);
|
return ComputeAllowedMaxDivisor(prime, _divisorLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DivisorScanSession CreateDivisorSession()
|
public IMersenneNumberDivisorByDivisorTester.IDivisorScanSession CreateDivisorSession()
|
||||||
{
|
{
|
||||||
// Divisor sessions are handed out only after configuration, so this guard would never trigger on the
|
// Divisor sessions are handed out only after configuration, so this guard would never trigger on the
|
||||||
// production path.
|
// production path.
|
||||||
@@ -965,8 +980,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
|
|||||||
|
|
||||||
return new DivisorScanSession(this);
|
return new DivisorScanSession(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
IMersenneNumberDivisorByDivisorTester.IDivisorScanSession IMersenneNumberDivisorByDivisorTester.CreateDivisorSession() => CreateDivisorSession();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using ILGPU.Runtime;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
internal sealed class MersenneNumberDivisorCandidateGpuEvaluator : IDisposable
|
internal sealed class MersenneNumberDivisorCandidateGpuEvaluator
|
||||||
{
|
{
|
||||||
private const int RemainderCount = 6;
|
private const int RemainderCount = 6;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using ILGPU.Runtime;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
internal sealed class MersenneNumberDivisorMontgomeryGpuBuilder : IDisposable
|
internal sealed class MersenneNumberDivisorMontgomeryGpuBuilder
|
||||||
{
|
{
|
||||||
private readonly GpuContextPool.GpuContextLease _lease;
|
private readonly GpuContextPool.GpuContextLease _lease;
|
||||||
private readonly Accelerator _accelerator;
|
private readonly Accelerator _accelerator;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ using ILGPU.Runtime;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
internal sealed class MersenneNumberDivisorRemainderGpuStepper : IDisposable
|
internal sealed class MersenneNumberDivisorRemainderGpuStepper
|
||||||
{
|
{
|
||||||
private const int RemainderCount = 6;
|
private const int RemainderCount = 6;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using ILGPU.Runtime;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core.Gpu;
|
namespace PerfectNumbers.Core.Gpu;
|
||||||
|
|
||||||
internal sealed class MersenneNumberDivisorResidueGpuEvaluator : IDisposable
|
internal sealed class MersenneNumberDivisorResidueGpuEvaluator
|
||||||
{
|
{
|
||||||
private readonly GpuContextPool.GpuContextLease _lease;
|
private readonly GpuContextPool.GpuContextLease _lease;
|
||||||
private readonly Accelerator _accelerator;
|
private readonly Accelerator _accelerator;
|
||||||
|
|||||||
@@ -327,8 +327,9 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
// TODO: Replace StreamWriter with the pooled TextFileWriter pipeline so persisting NTT
|
// TODO: Replace StreamWriter with the pooled TextFileWriter pipeline so persisting NTT
|
||||||
// parameters reuses the zero-allocation buffered writes highlighted in the scanner I/O
|
// parameters reuses the zero-allocation buffered writes highlighted in the scanner I/O
|
||||||
// benchmarks instead of allocating a new encoder per append.
|
// benchmarks instead of allocating a new encoder per append.
|
||||||
using var writer = new StreamWriter(ParameterFilePath, append: true);
|
var writer = new StreamWriter(ParameterFilePath, append: true);
|
||||||
writer.WriteLine($"{length} {modulus.High} {modulus.Low} {primitiveRoot.High} {primitiveRoot.Low}");
|
writer.WriteLine($"{length} {modulus.High} {modulus.Low} {primitiveRoot.High} {primitiveRoot.Low}");
|
||||||
|
writer.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +339,7 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
ulong foundRoot = 0UL;
|
ulong foundRoot = 0UL;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
var processorCount = Environment.ProcessorCount;
|
var processorCount = Environment.ProcessorCount;
|
||||||
using var cts = new System.Threading.CancellationTokenSource();
|
var cts = new System.Threading.CancellationTokenSource();
|
||||||
object sync = new();
|
object sync = new();
|
||||||
|
|
||||||
// TODO: Move this Parallel.For to the shared low-overhead work scheduler once the NTT parameter
|
// TODO: Move this Parallel.For to the shared low-overhead work scheduler once the NTT parameter
|
||||||
@@ -381,11 +382,13 @@ public class MersenneNumberLucasLehmerGpuTester
|
|||||||
{
|
{
|
||||||
modulus = new GpuUInt128(0UL, foundCandidate);
|
modulus = new GpuUInt128(0UL, foundCandidate);
|
||||||
primitiveRoot = new GpuUInt128(0UL, foundRoot);
|
primitiveRoot = new GpuUInt128(0UL, foundRoot);
|
||||||
|
cts.Dispose();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
modulus = new GpuUInt128(0UL, 18446744069414584321UL);
|
modulus = new GpuUInt128(0UL, 18446744069414584321UL);
|
||||||
primitiveRoot = new GpuUInt128(0UL, 7UL);
|
primitiveRoot = new GpuUInt128(0UL, 7UL);
|
||||||
|
cts.Dispose();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,31 +64,25 @@ internal static class MontgomeryOddPowerGpu
|
|||||||
var accelerator = lease.Accelerator;
|
var accelerator = lease.Accelerator;
|
||||||
var stream = lease.Stream;
|
var stream = lease.Stream;
|
||||||
|
|
||||||
using var divisorBuffer = accelerator.Allocate1D<MontgomeryDivisorData>(divisorCount);
|
var divisorBuffer = accelerator.Allocate1D<MontgomeryDivisorData>(divisorCount);
|
||||||
using var countBuffer = accelerator.Allocate1D<int>(divisorCount);
|
var countBuffer = accelerator.Allocate1D<int>(divisorCount);
|
||||||
using var resultBuffer = accelerator.Allocate1D<ulong>(divisorCount * stride);
|
var resultBuffer = accelerator.Allocate1D<ulong>(divisorCount * stride);
|
||||||
|
|
||||||
try
|
divisorBuffer.View.CopyFromCPU(ref MemoryMarshal.GetReference(divisors), divisorCount);
|
||||||
{
|
countBuffer.View.CopyFromCPU(ref MemoryMarshal.GetReference(oddPowerCounts), divisorCount);
|
||||||
divisorBuffer.View.CopyFromCPU(ref MemoryMarshal.GetReference(divisors), divisorCount);
|
resultBuffer.MemSetToZero();
|
||||||
countBuffer.View.CopyFromCPU(ref MemoryMarshal.GetReference(oddPowerCounts), divisorCount);
|
|
||||||
resultBuffer.MemSetToZero();
|
|
||||||
|
|
||||||
var kernel = lease.MontgomeryOddPowerKernel;
|
var kernel = lease.MontgomeryOddPowerKernel;
|
||||||
kernel(stream, divisorCount, divisorBuffer.View, countBuffer.View, resultBuffer.View, stride);
|
kernel(stream, divisorCount, divisorBuffer.View, countBuffer.View, resultBuffer.View, stride);
|
||||||
stream.Synchronize();
|
stream.Synchronize();
|
||||||
|
|
||||||
resultBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(results), divisorCount * stride);
|
resultBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(results), divisorCount * stride);
|
||||||
return true;
|
|
||||||
}
|
resultBuffer.Dispose();
|
||||||
catch
|
countBuffer.Dispose();
|
||||||
{
|
divisorBuffer.Dispose();
|
||||||
return false;
|
execution.Dispose();
|
||||||
}
|
lease.Dispose();
|
||||||
finally
|
return true;
|
||||||
{
|
|
||||||
execution.Dispose();
|
|
||||||
lease.Dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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; }
|
||||||
|
|||||||
@@ -1611,7 +1611,7 @@ internal static partial class PrimeOrderGpuHeuristics
|
|||||||
private static ulong CalculateByDoublingKernel(ulong prime)
|
private static ulong CalculateByDoublingKernel(ulong prime)
|
||||||
{
|
{
|
||||||
ulong order = 1UL;
|
ulong order = 1UL;
|
||||||
ulong value = 2UL % prime;
|
ulong value = 2UL; // Candidate primes exceed two, so the modulo would always return two.
|
||||||
|
|
||||||
while (value != 1UL)
|
while (value != 1UL)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,8 +18,10 @@ public interface IMersenneNumberDivisorByDivisorTester
|
|||||||
|
|
||||||
void PrepareCandidates(ReadOnlySpan<ulong> primes, Span<ulong> allowedMaxValues);
|
void PrepareCandidates(ReadOnlySpan<ulong> primes, Span<ulong> allowedMaxValues);
|
||||||
|
|
||||||
public interface IDivisorScanSession : IDisposable
|
public interface IDivisorScanSession
|
||||||
{
|
{
|
||||||
void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, ReadOnlySpan<ulong> primes, Span<byte> hits);
|
void CheckDivisor(ulong divisor, in MontgomeryDivisorData divisorData, ulong divisorCycle, ReadOnlySpan<ulong> primes, Span<byte> hits);
|
||||||
|
|
||||||
|
void Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +196,7 @@ public class MersenneDivisorCycles
|
|||||||
public static IEnumerable<(ulong divisor, ulong cycleLength)> EnumerateStream(Stream compressor)
|
public static IEnumerable<(ulong divisor, ulong cycleLength)> EnumerateStream(Stream compressor)
|
||||||
{
|
{
|
||||||
// Binary pairs: (ulong divisor, ulong cycle)
|
// Binary pairs: (ulong divisor, ulong cycle)
|
||||||
using var reader = new BinaryReader(compressor, Encoding.UTF8, leaveOpen: true);
|
var reader = new BinaryReader(compressor, Encoding.UTF8, leaveOpen: true);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ulong d, c;
|
ulong d, c;
|
||||||
@@ -207,6 +207,7 @@ public class MersenneDivisorCycles
|
|||||||
}
|
}
|
||||||
catch (EndOfStreamException)
|
catch (EndOfStreamException)
|
||||||
{
|
{
|
||||||
|
reader.Dispose();
|
||||||
yield break;
|
yield break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -829,7 +830,7 @@ public class MersenneDivisorCycles
|
|||||||
// Start fresh to avoid mixing formats
|
// Start fresh to avoid mixing formats
|
||||||
outputStream.SetLength(0L);
|
outputStream.SetLength(0L);
|
||||||
outputStream.Position = 0L;
|
outputStream.Position = 0L;
|
||||||
using var writer = new BinaryWriter(outputStream, Encoding.UTF8, leaveOpen: false);
|
var writer = new BinaryWriter(outputStream, Encoding.UTF8, leaveOpen: false);
|
||||||
for (var taskIndex = 0; taskIndex < threads; taskIndex++)
|
for (var taskIndex = 0; taskIndex < threads; taskIndex++)
|
||||||
{
|
{
|
||||||
ulong threadStart = start + (ulong)taskIndex * blockSize;
|
ulong threadStart = start + (ulong)taskIndex * blockSize;
|
||||||
@@ -911,6 +912,7 @@ public class MersenneDivisorCycles
|
|||||||
}
|
}
|
||||||
|
|
||||||
Task.WaitAll(tasks);
|
Task.WaitAll(tasks);
|
||||||
|
writer.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GenerateGpu(string path, ulong maxDivisor, int batchSize = 1_000_000, long skipCount = 0L, long nextPosition = 0L)
|
public static void GenerateGpu(string path, ulong maxDivisor, int batchSize = 1_000_000, long skipCount = 0L, long nextPosition = 0L)
|
||||||
@@ -947,7 +949,7 @@ public class MersenneDivisorCycles
|
|||||||
outputStream.Position = 0L;
|
outputStream.Position = 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
using var writer = new BinaryWriter(outputStream, Encoding.UTF8, leaveOpen: false);
|
var writer = new BinaryWriter(outputStream, Encoding.UTF8, leaveOpen: false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (skipCount > 0L && start <= maxDivisor)
|
while (skipCount > 0L && start <= maxDivisor)
|
||||||
@@ -1022,6 +1024,7 @@ public class MersenneDivisorCycles
|
|||||||
pool.Return(outCycles, clearArray: false);
|
pool.Return(outCycles, clearArray: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writer.Dispose();
|
||||||
stream.Dispose();
|
stream.Dispose();
|
||||||
lease.Dispose();
|
lease.Dispose();
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Buffers;
|
|||||||
|
|
||||||
namespace PerfectNumbers.Core
|
namespace PerfectNumbers.Core
|
||||||
{
|
{
|
||||||
internal sealed class PrimeFactorPartialResult : IDisposable
|
internal sealed class PrimeFactorPartialResult
|
||||||
{
|
{
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static PrimeFactorPartialResult? s_poolHead;
|
private static PrimeFactorPartialResult? s_poolHead;
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ public sealed class PrimeTester(bool useInternal = false)
|
|||||||
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; }
|
||||||
|
|||||||
@@ -3,7 +3,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;
|
||||||
|
|||||||
@@ -530,7 +530,9 @@ public static class ULongExtensions
|
|||||||
ulong modulus = divisor.Modulus;
|
ulong modulus = divisor.Modulus;
|
||||||
if (exponent == 0UL)
|
if (exponent == 0UL)
|
||||||
{
|
{
|
||||||
return keepMontgomery ? divisor.MontgomeryOne : 1UL % modulus;
|
return keepMontgomery
|
||||||
|
? divisor.MontgomeryOne
|
||||||
|
: 1UL; // Montgomery moduli stay above one on the scanning path, so the modulo would always yield one.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exponent <= Pow2WindowFallbackThreshold)
|
if (exponent <= Pow2WindowFallbackThreshold)
|
||||||
@@ -622,7 +624,9 @@ public static class ULongExtensions
|
|||||||
ulong modulus = divisor.Modulus;
|
ulong modulus = divisor.Modulus;
|
||||||
if (exponent == 0UL)
|
if (exponent == 0UL)
|
||||||
{
|
{
|
||||||
return keepMontgomery ? divisor.MontgomeryOne : 1UL % modulus;
|
return keepMontgomery
|
||||||
|
? divisor.MontgomeryOne
|
||||||
|
: 1UL; // Montgomery moduli stay above one on the scanning path, so the modulo would always yield one.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exponent <= Pow2WindowFallbackThreshold)
|
if (exponent <= Pow2WindowFallbackThreshold)
|
||||||
@@ -769,7 +773,7 @@ public static class ULongExtensions
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong baseValue = 2UL % modulus;
|
ulong baseValue = 2UL; // Moduli arrive as odd primes greater than two, so the modulo would always return two.
|
||||||
destination[0] = baseValue;
|
destination[0] = baseValue;
|
||||||
if (oddPowerCount == 1)
|
if (oddPowerCount == 1)
|
||||||
{
|
{
|
||||||
|
|||||||
+7
-4
@@ -335,10 +335,13 @@ if (patchResults.Any(static r => !r.Success))
|
|||||||
|
|
||||||
static List<PatchFile> ParsePatchFromFile(string patchFilePath)
|
static List<PatchFile> ParsePatchFromFile(string patchFilePath)
|
||||||
{
|
{
|
||||||
using var stream = File.OpenRead(patchFilePath);
|
var stream = File.OpenRead(patchFilePath);
|
||||||
using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 16_384, leaveOpen: false);
|
var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 16_384, leaveOpen: false);
|
||||||
using var lineReader = new PatchLineReader(reader);
|
var lineReader = new PatchLineReader(reader);
|
||||||
var files = ParsePatch(lineReader);
|
var files = ParsePatch(lineReader);
|
||||||
|
lineReader.Dispose();
|
||||||
|
reader.Dispose();
|
||||||
|
stream.Dispose();
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +503,7 @@ static void FinalizePatchFile(
|
|||||||
files.Add(new PatchFile(originalPath, modifiedPath, hunks ?? new List<PatchHunk>(), type));
|
files.Add(new PatchFile(originalPath, modifiedPath, hunks ?? new List<PatchHunk>(), type));
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class PatchLineReader : IDisposable
|
private sealed class PatchLineReader
|
||||||
{
|
{
|
||||||
private const int ReadBufferSize = 4096;
|
private const int ReadBufferSize = 4096;
|
||||||
private const int InitialLineBufferSize = 256;
|
private const int InitialLineBufferSize = 256;
|
||||||
|
|||||||
@@ -54,10 +54,11 @@ static ProbeResult ProbeBigInteger(Accelerator accelerator)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<int, Stride1D.Dense>>(BigIntegerKernel);
|
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<int, Stride1D.Dense>>(BigIntegerKernel);
|
||||||
using var buffer = accelerator.Allocate1D<int>(1);
|
var buffer = accelerator.Allocate1D<int>(1);
|
||||||
var extent = new Index1D((int)buffer.Length);
|
var extent = new Index1D((int)buffer.Length);
|
||||||
kernel(extent, buffer.View);
|
kernel(extent, buffer.View);
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
buffer.Dispose();
|
||||||
return ProbeResult.Success(
|
return ProbeResult.Success(
|
||||||
"System.Numerics.BigInteger",
|
"System.Numerics.BigInteger",
|
||||||
"Addition, subtraction, multiplication, division, and modulo compile on the CPU accelerator.");
|
"Addition, subtraction, multiplication, division, and modulo compile on the CPU accelerator.");
|
||||||
@@ -73,9 +74,10 @@ static ProbeResult ProbeEInteger(Accelerator accelerator)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<int, Stride1D.Dense>>(EIntegerKernel);
|
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<int, Stride1D.Dense>>(EIntegerKernel);
|
||||||
using var buffer = accelerator.Allocate1D<int>(1);
|
var buffer = accelerator.Allocate1D<int>(1);
|
||||||
kernel(new Index1D((int)buffer.Length), buffer.View);
|
kernel(new Index1D((int)buffer.Length), buffer.View);
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
buffer.Dispose();
|
||||||
return ProbeResult.Success(
|
return ProbeResult.Success(
|
||||||
"PeterO.Numbers.EInteger",
|
"PeterO.Numbers.EInteger",
|
||||||
"Addition, subtraction, multiplication, division, and remainder compile on the CPU accelerator.");
|
"Addition, subtraction, multiplication, division, and remainder compile on the CPU accelerator.");
|
||||||
@@ -93,7 +95,7 @@ static ProbeResult ProbeERational(Accelerator accelerator)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<int, Stride1D.Dense>>(ERationalKernel);
|
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<int, Stride1D.Dense>>(ERationalKernel);
|
||||||
using var buffer = accelerator.Allocate1D<int>(1);
|
var buffer = accelerator.Allocate1D<int>(1);
|
||||||
kernel(new Index1D((int)buffer.Length), buffer.View);
|
kernel(new Index1D((int)buffer.Length), buffer.View);
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
|
||||||
@@ -101,6 +103,7 @@ static ProbeResult ProbeERational(Accelerator accelerator)
|
|||||||
details += hasRemainder
|
details += hasRemainder
|
||||||
? " ERational exposes a remainder API that requires further investigation."
|
? " ERational exposes a remainder API that requires further investigation."
|
||||||
: " ERational does not expose a remainder/modulo API.";
|
: " ERational does not expose a remainder/modulo API.";
|
||||||
|
buffer.Dispose();
|
||||||
return ProbeResult.Success("PeterO.Numbers.ERational", details);
|
return ProbeResult.Success("PeterO.Numbers.ERational", details);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -120,9 +123,10 @@ static ProbeResult ProbeOpenNumericPrimesIsPrime(Accelerator accelerator)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<int, Stride1D.Dense>>(OpenNumericPrimesIsPrimeKernel);
|
var kernel = accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<int, Stride1D.Dense>>(OpenNumericPrimesIsPrimeKernel);
|
||||||
using var buffer = accelerator.Allocate1D<int>(4);
|
var buffer = accelerator.Allocate1D<int>(4);
|
||||||
kernel(new Index1D((int)buffer.Length), buffer.View);
|
kernel(new Index1D((int)buffer.Length), buffer.View);
|
||||||
accelerator.Synchronize();
|
accelerator.Synchronize();
|
||||||
|
buffer.Dispose();
|
||||||
return ProbeResult.Success(
|
return ProbeResult.Success(
|
||||||
"Open.Numeric.Primes.Prime.Numbers.IsPrime",
|
"Open.Numeric.Primes.Prime.Numbers.IsPrime",
|
||||||
"IsPrime compiles and runs on the CPU accelerator kernel.");
|
"IsPrime compiles and runs on the CPU accelerator kernel.");
|
||||||
|
|||||||
Reference in new issue
Block a user