Compare commits

..
Author SHA1 Message Date
mlemanczyk b031003a46 GPU usage restored to duplicate CL exceptions. 2025-11-19 17:18:19 +01:00
mlemanczyk 8541bc4928 Test file added 2025-11-19 16:58:29 +01:00
22 changed files with 228 additions and 209 deletions

No files matched your search

@@ -28,8 +28,8 @@ public class PrimeTesterBenchmarks
PrimeOrderCalculatorAccelerator.WarmUp();
// HeuristicGroupABPrimeTesterAccelerator.WarmUp();
_ = HeuristicPrimeTester.IsPrimeCpu(_candidates[0]);
_ = HeuristicPrimeTester.IsPrimeGpu(_candidates[0]);
_ = _heuristicTester.IsPrimeCpu(_candidates[0]);
_ = _heuristicTester.IsPrimeGpu(_candidates[0]);
_ = Prime.Numbers.IsPrime(_candidates[0]);
}
@@ -42,7 +42,7 @@ public class PrimeTesterBenchmarks
for (int i = 0; i < values.Length; i++)
{
if (HeuristicPrimeTester.IsPrimeCpu(values[i]))
if (tester.IsPrimeCpu(values[i]))
{
primeCount++;
}
@@ -60,7 +60,7 @@ public class PrimeTesterBenchmarks
for (int i = 0; i < values.Length; i++)
{
if (HeuristicPrimeTester.IsPrimeGpu(values[i]))
if (tester.IsPrimeGpu(values[i]))
{
primeCount++;
}
@@ -19,7 +19,7 @@ internal static class Program
"/help"
};
private const string DefaultHeader = "p,divisor,searchedMersenne,detailedCheck,passedAllTests";
private const string DefaultHeader = "p,searchedMersenne,detailedCheck,passedAllTests";
private static int Main(string[] args)
{
@@ -7,7 +7,7 @@ namespace EvenPerfectBitScanner;
internal static class CalculationResultHandler
{
private const string ResultsHeader = "p,divisor,searchedMersenne,detailedCheck,passedAllTests";
private const string ResultsHeader = "p,searchedMersenne,detailedCheck,passedAllTests";
private const string PrimeFoundSuffix = " (FOUND VALID CANDIDATES)";
internal const int DefaultWriteBatchSize = 100;
@@ -93,19 +93,19 @@ internal static class CalculationResultHandler
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void HandleResult(ulong currentP, ulong divisor, bool searchedMersenne, bool detailedCheck, bool passedAllTests, bool lastWasComposite)
internal static void HandleResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool passedAllTests, bool lastWasComposite)
{
// Program flow ensures Initialize(...) and InitializeOutputBuffer() ran before this call. Do not add initialization guards here.
Span<byte> stackBuffer = stackalloc byte[128];
byte[]? rentedBuffer = null;
Span<byte> utf8Span = stackBuffer;
int byteCount = TryFormatResultLine(utf8Span, currentP, divisor, searchedMersenne, detailedCheck, passedAllTests);
int byteCount = TryFormatResultLine(utf8Span, currentP, searchedMersenne, detailedCheck, passedAllTests);
if (byteCount < 0)
{
rentedBuffer = ThreadStaticPools.BytePool.Rent(256);
utf8Span = rentedBuffer;
byteCount = TryFormatResultLine(utf8Span, currentP, divisor, searchedMersenne, detailedCheck, passedAllTests);
byteCount = TryFormatResultLine(utf8Span, currentP, searchedMersenne, detailedCheck, passedAllTests);
if (byteCount < 0)
{
ThreadStaticPools.BytePool.Return(rentedBuffer);
@@ -229,7 +229,7 @@ internal static class CalculationResultHandler
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int TryFormatResultLine(Span<byte> destination, ulong currentP, ulong divisor, bool searchedMersenne, bool detailedCheck, bool passedAllTests)
private static int TryFormatResultLine(Span<byte> destination, ulong currentP, bool searchedMersenne, bool detailedCheck, bool passedAllTests)
{
int offset = 0;
@@ -246,19 +246,6 @@ internal static class CalculationResultHandler
destination[offset++] = (byte)',';
if (!Utf8Formatter.TryFormat(divisor, destination[offset..], out written))
{
return -1;
}
offset += written;
if (offset >= destination.Length)
{
return -1;
}
destination[offset++] = (byte)',';
if (!Utf8Formatter.TryFormat(searchedMersenne, destination[offset..], out written))
{
return -1;
@@ -100,7 +100,6 @@ internal static class CalculationResultsFile
int first = 0;
int second = 0;
int third = 0;
int fourth = 0;
ulong parsedP = 0UL;
ReadOnlySpan<char> detailedSpan = default;
ReadOnlySpan<char> passedAllTestsSpan = default;
@@ -140,15 +139,8 @@ internal static class CalculationResultsFile
continue;
}
span = span[(third + 1)..];
fourth = span.IndexOf(',');
if (fourth < 0)
{
continue;
}
detailedSpan = span[..fourth];
passedAllTestsSpan = span[(fourth + 1)..];
detailedSpan = span[..third];
passedAllTestsSpan = span[(third + 1)..];
if (Utf8CliParser.TryParseBoolean(detailedSpan, out detailed) && Utf8CliParser.TryParseBoolean(passedAllTestsSpan, out passedAllTests))
{
+4 -4
View File
@@ -422,7 +422,7 @@ internal static class Program
_byDivisorStartPrime,
static () => _lastCompositeP = true,
static () => _lastCompositeP = false,
static (candidate, searchedMersenne, detailedCheck, passedAllTests, divisor) => CalculationResultHandler.HandleResult(candidate, divisor, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
static (candidate, searchedMersenne, detailedCheck, passedAllTests) => CalculationResultHandler.HandleResult(candidate, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP),
threadCount,
byDivisorPrimeRange);
@@ -483,7 +483,7 @@ internal static class Program
{
p = buffer[j];
passedAllTests = IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out searchedMersenne, out detailedCheck);
CalculationResultHandler.HandleResult(p, 0UL, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP);
CalculationResultHandler.HandleResult(p, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP);
}
continue;
@@ -506,7 +506,7 @@ internal static class Program
}
passedAllTests = IsEvenPerfectCandidate(p, divisorCyclesSearchLimit, out searchedMersenne, out detailedCheck);
CalculationResultHandler.HandleResult(p, 0UL, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP);
CalculationResultHandler.HandleResult(p, searchedMersenne, detailedCheck, passedAllTests, _lastCompositeP);
if (p == maxP)
{
@@ -649,7 +649,7 @@ internal static class Program
if (_cliArguments.UseByDivisor)
{
// Windowed pow2mod kernel handles by-divisor scans.
return _byDivisorTester!.IsPrime(p, out detailedCheck, out _);
return _byDivisorTester!.IsPrime(p, out detailedCheck);
}
detailedCheck = MersenneTesters.Value!.IsMersennePrime(p);
@@ -11,7 +11,7 @@ public class MersenneNumberDivisorByDivisorTesterTests
{
var candidates = new List<ulong> { 5UL, 7UL, 11UL, 13UL };
var tester = new FakeTester();
var results = new List<(ulong Prime, bool Searched, bool Detailed, bool Passed, ulong Divisor)>();
var results = new List<(ulong Prime, bool Searched, bool Detailed, bool Passed)>();
int compositeMarks = 0;
int clearedMarks = 0;
@@ -22,7 +22,7 @@ public class MersenneNumberDivisorByDivisorTesterTests
startPrime: 0UL,
markComposite: () => compositeMarks++,
clearComposite: () => clearedMarks++,
printResult: (prime, searched, detailed, passed, divisor) => results.Add((prime, searched, detailed, passed, divisor)),
printResult: (prime, searched, detailed, passed) => results.Add((prime, searched, detailed, passed)),
threadCount: 1,
primesPerTask: 2);
@@ -32,10 +32,10 @@ public class MersenneNumberDivisorByDivisorTesterTests
results.Should().Equal(
new[]
{
(5UL, true, true, true, 0UL),
(7UL, true, true, false, 7UL),
(11UL, true, true, false, 11UL),
(13UL, true, true, true, 0UL),
(5UL, true, true, true),
(7UL, true, true, false),
(11UL, true, true, false),
(13UL, true, true, true),
});
}
@@ -57,23 +57,10 @@ public class MersenneNumberDivisorByDivisorTesterTests
return DivisorLimit;
}
public bool IsPrime(ulong prime, out bool divisorsExhausted, out ulong divisor)
public bool IsPrime(ulong prime, out bool divisorsExhausted)
{
divisorsExhausted = true;
if (prime % 7UL == 0UL)
{
divisor = 7UL;
return false;
}
if (prime % 11UL == 0UL)
{
divisor = 11UL;
return false;
}
divisor = 0UL;
return true;
return prime % 7UL != 0UL && prime % 11UL != 0UL;
}
public IMersenneNumberDivisorByDivisorTester.IDivisorScanSession CreateDivisorSession()
@@ -13,17 +13,14 @@ public class MersenneNumberDivisorCpuTesterTests
var tester = new MersenneNumberDivisorByDivisorCpuTester();
tester.ConfigureFromMaxPrime(11UL);
tester.IsPrime(5UL, out bool divisorsExhausted, out ulong divisor).Should().BeTrue();
tester.IsPrime(5UL, out bool divisorsExhausted).Should().BeTrue();
divisorsExhausted.Should().BeTrue();
divisor.Should().Be(0UL);
tester.IsPrime(7UL, out divisorsExhausted, out divisor).Should().BeTrue();
tester.IsPrime(7UL, out divisorsExhausted).Should().BeTrue();
divisorsExhausted.Should().BeTrue();
divisor.Should().Be(0UL);
tester.IsPrime(11UL, out divisorsExhausted, out divisor).Should().BeFalse();
tester.IsPrime(11UL, out divisorsExhausted).Should().BeFalse();
divisorsExhausted.Should().BeTrue();
divisor.Should().BeGreaterThan(0UL);
}
[Fact]
@@ -73,17 +73,14 @@ public class MersenneNumberDivisorGpuTesterTests
var tester = new MersenneNumberDivisorByDivisorGpuTester();
tester.ConfigureFromMaxPrime(43UL);
tester.IsPrime(31UL, out bool exhausted, out ulong divisor).Should().BeTrue();
tester.IsPrime(31UL, out bool exhausted).Should().BeTrue();
exhausted.Should().BeTrue();
divisor.Should().Be(0UL);
tester.IsPrime(37UL, out exhausted, out divisor).Should().BeFalse();
tester.IsPrime(37UL, out exhausted).Should().BeFalse();
exhausted.Should().BeTrue();
divisor.Should().BeGreaterThan(0UL);
tester.IsPrime(43UL, out exhausted, out divisor).Should().BeFalse();
tester.IsPrime(43UL, out exhausted).Should().BeFalse();
exhausted.Should().BeTrue();
divisor.Should().BeGreaterThan(0UL);
}
[Fact]
@@ -108,15 +105,12 @@ public class MersenneNumberDivisorGpuTesterTests
var tester = new MersenneNumberDivisorByDivisorGpuTester();
tester.ConfigureFromMaxPrime(41UL);
tester.IsPrime(31UL, out _, out ulong divisor).Should().BeTrue();
divisor.Should().Be(0UL);
tester.IsPrime(37UL, out bool exhausted, out divisor).Should().BeFalse();
tester.IsPrime(31UL, out _).Should().BeTrue();
tester.IsPrime(37UL, out bool exhausted).Should().BeFalse();
exhausted.Should().BeTrue();
divisor.Should().BeGreaterThan(0UL);
tester.IsPrime(41UL, out bool divisorsExhausted, out divisor).Should().BeFalse();
tester.IsPrime(41UL, out bool divisorsExhausted).Should().BeFalse();
divisorsExhausted.Should().BeTrue();
divisor.Should().BeGreaterThan(0UL);
}
@@ -130,16 +124,8 @@ public class MersenneNumberDivisorGpuTesterTests
var tester = new MersenneNumberDivisorByDivisorGpuTester();
tester.ConfigureFromMaxPrime(exponent);
tester.IsPrime(exponent, out bool exhausted, out ulong divisor).Should().Be(expectedPrime);
tester.IsPrime(exponent, out bool exhausted).Should().Be(expectedPrime);
exhausted.Should().BeTrue();
if (expectedPrime)
{
divisor.Should().Be(0UL);
}
else
{
divisor.Should().BeGreaterThan(0UL);
}
}
[Fact]
[Trait("Category", "Fast")]
@@ -152,9 +138,8 @@ public class MersenneNumberDivisorGpuTesterTests
tester.ConfigureFromMaxPrime(43UL);
tester.IsPrime(41UL, out bool divisorsExhausted, out ulong divisor).Should().BeFalse();
tester.IsPrime(41UL, out bool divisorsExhausted).Should().BeFalse();
divisorsExhausted.Should().BeTrue();
divisor.Should().BeGreaterThan(0UL);
}
[Fact]
@@ -324,9 +309,8 @@ public class MersenneNumberDivisorGpuTesterTests
.GetField("_divisorLimit", BindingFlags.NonPublic | BindingFlags.Instance)!
.SetValue(tester, 200UL);
tester.IsPrime(19UL, out bool divisorsExhausted, out ulong divisor).Should().BeTrue();
tester.IsPrime(19UL, out bool divisorsExhausted).Should().BeTrue();
divisorsExhausted.Should().BeTrue();
divisor.Should().Be(0UL);
}
finally
{
@@ -42,7 +42,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong GetAllowedMaxDivisor(ulong prime) => ComputeAllowedMaxDivisor(prime, _divisorLimit);
public bool IsPrime(ulong prime, out bool divisorsExhausted, out ulong divisor)
public bool IsPrime(ulong prime, out bool divisorsExhausted)
{
ulong allowedMax = ComputeAllowedMaxDivisor(prime, _divisorLimit);
@@ -60,8 +60,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
bool composite = CheckDivisors(
prime,
allowedMax,
out processedAll,
out divisor);
out processedAll);
if (composite)
{
@@ -70,7 +69,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
}
divisorsExhausted = processedAll || composite;
divisor = 0UL;
return true;
}
@@ -98,10 +96,8 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
private bool CheckDivisors(
ulong prime,
ulong allowedMax,
out bool processedAll,
out ulong foundDivisor)
out bool processedAll)
{
foundDivisor = 0UL;
// The EvenPerfectBitScanner feeds primes >= 138,000,000 here, so allowedMax >= 3 in production runs.
// Keeping the guard commented out documents the reasoning for benchmarks and tests.
// if (allowedMax < 3UL)
@@ -127,7 +123,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
if (divisor.CompareTo(limit) > 0)
{
processedAll = true;
foundDivisor = 0UL;
return false;
}
@@ -187,8 +182,7 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
remainder3,
remainder7,
remainder11,
out processedAll,
out foundDivisor);
out processedAll);
}
ulong divisorHigh = divisor.High;
@@ -246,7 +240,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
{
// A cycle equal to the tested exponent (which is prime in this path) guarantees that the candidate divides
// the corresponding Mersenne number because the order of 2 modulo the divisor is exactly p.
foundDivisor = candidate;
processedAll = true;
PrimeOrderCalculatorAccelerator.Return(gpu);
return true;
@@ -268,7 +261,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
PrimeOrderCalculatorAccelerator.Return(gpu);
processedAll = true;
foundDivisor = 0UL;
return false;
}
@@ -288,11 +280,9 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
byte remainder3,
byte remainder7,
byte remainder11,
out bool processedAll,
out ulong foundDivisor)
out bool processedAll)
{
processedAll = false;
foundDivisor = 0UL;
bool canAdvance = step <= limit;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
@@ -324,7 +314,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
if (divisorCycle == prime)
{
foundDivisor = divisor;
processedAll = true;
PrimeOrderCalculatorAccelerator.Return(gpu);
return true;
@@ -338,14 +327,12 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
}
processedAll = true;
foundDivisor = 0UL;
return false;
}
if (divisor > limit)
{
processedAll = true;
foundDivisor = 0UL;
return false;
}
@@ -378,7 +365,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
if (divisorCycle == prime)
{
foundDivisor = divisor;
processedAll = true;
PrimeOrderCalculatorAccelerator.Return(gpu);
return true;
@@ -394,7 +380,6 @@ public sealed class MersenneNumberDivisorByDivisorCpuTester : IMersenneNumberDiv
if (remainingIterations == 0UL)
{
processedAll = true;
foundDivisor = 0UL;
return false;
}
@@ -115,18 +115,20 @@ public sealed class PrimeOrderCalculatorAccelerator
public Dictionary<ulong, int> Pow2ModEntriesToTestOnHost = [];
public readonly Action<AcceleratorStream, int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> CheckFactorsKernelLauncher;
public readonly Kernel CheckFactorsKernel;
public readonly Kernel ConvertToStandardKernel;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> ConvertToStandardKernelLauncher;
public readonly Kernel HeuristicCombinedTrialDivisionKernel;
public readonly Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews> HeuristicCombinedTrialDivisionKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>> KeepMontgomeryKernelLauncher;
public readonly Action<AcceleratorStream, ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> PollardRhoKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>> Pow2ModWideKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>> SharesFactorKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SmallPrimeFactorKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>> SmallPrimeSieveKernelLauncher;
public readonly Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>> SpecialMaxKernelLauncher;
public readonly Kernel KeepMontgomeryKernel;
public readonly Kernel PollardRhoKernel;
public readonly Kernel Pow2ModWideKernel;
public readonly Kernel SharesFactorKernel;
public readonly Kernel SmallPrimeFactorKernel;
public readonly Kernel SmallPrimeSieveKernel;
public readonly Kernel SpecialMaxKernel;
public void EnsureCapacity(int factorsCount, int primeTesterCapacity)
{
@@ -260,25 +262,31 @@ public sealed class PrimeOrderCalculatorAccelerator
SmallPrimeFactorSquares = tables.Squares.View;
}
CheckFactorsKernelLauncher = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel)).CreateLauncherDelegate<Action<AcceleratorStream, int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
CheckFactorsKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.CheckFactorsKernel));
ConvertToStandardKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
Kernel convertToStandardKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelConvertToStandard));
HeuristicCombinedTrialDivisionKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>>();
ConvertToStandardKernel = convertToStandardKernel;
ConvertToStandardKernelLauncher = convertToStandardKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
KeepMontgomeryKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
var heuristicCombinedTrialDivisionKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>(PrimeTesterKernels.HeuristicTrialCombinedDivisionKernel));
PollardRhoKernelLauncher = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel)).CreateLauncherDelegate<Action<AcceleratorStream, ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
HeuristicCombinedTrialDivisionKernel = heuristicCombinedTrialDivisionKernel;
HeuristicCombinedTrialDivisionKernelLauncher = heuristicCombinedTrialDivisionKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicCombinedGpuViews>>();
Pow2ModWideKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderGpuHeuristics.Pow2ModKernelWide)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>>();
KeepMontgomeryKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.Pow2MontgomeryKernelKeepMontgomery));
SharesFactorKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SharesFactorKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>>>();
PollardRhoKernel = KernelUtil.GetKernel(accelerator.LoadStreamKernel<ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(Pow2MontgomeryKernels.TryPollardRhoKernel));
SmallPrimeFactorKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
Pow2ModWideKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>(PrimeOrderGpuHeuristics.Pow2ModKernelWide));
SmallPrimeSieveKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
SharesFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SharesFactorKernel));
SpecialMaxKernelLauncher = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel)).CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
SmallPrimeFactorKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(SmallPrimeFactorKernels.SmallPrimeFactorKernelScan));
SmallPrimeSieveKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>(PrimeTesterKernels.SmallPrimeSieveKernel));
SpecialMaxKernel = KernelUtil.GetKernel(accelerator.LoadAutoGroupedStreamKernel<Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>(PrimeOrderGpuHeuristics.EvaluateSpecialMaxCandidatesKernel));
}
}
@@ -70,7 +70,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
private static readonly Accelerator[] _accelerators = AcceleratorPool.Shared.Accelerators;
public bool IsPrime(ulong prime, out bool divisorsExhausted, out ulong divisor)
public bool IsPrime(ulong prime, out bool divisorsExhausted)
{
ulong allowedMax;
int batchCapacity;
@@ -147,12 +147,10 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
if (composite)
{
divisorsExhausted = true;
divisor = lastProcessed;
return false;
}
divisorsExhausted = coveredRange;
divisor = 0UL;
return true;
}
@@ -935,4 +933,4 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester : IMersenneNumberDiv
}
IMersenneNumberDivisorByDivisorTester.IDivisorScanSession IMersenneNumberDivisorByDivisorTester.CreateDivisorSession() => CreateDivisorSession();
}
}
@@ -18,13 +18,16 @@ public static class Pow2MontgomeryGpuCalculator
Accelerator? accelerator = gpu.Accelerator;
MemoryBuffer1D<ulong, Stride1D.Dense> exponentBuffer = gpu.Input;
MemoryBuffer1D<ulong, Stride1D.Dense> resultBuffer = gpu.OutputUlong;
var kernel = gpu.KeepMontgomeryKernel;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
exponentBuffer.View.CopyFromCPU(stream, ref exponent, 1);
// We don't need to worry about any left-overs here.
// resultBuffer.MemSetToZero(stream);
var kernelLauncher = gpu.KeepMontgomeryKernelLauncher;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<ulong, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, 1, exponentBuffer.View, divisor, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, ref result, 1);
@@ -604,7 +604,7 @@ internal static partial class PrimeOrderGpuHeuristics
}
exponentBuffer.View.CopyFromCPU(stream, exponentSpan);
var kernelLauncher = gpu.Pow2ModWideKernelLauncher;
var kernelLauncher = gpu.Pow2ModWideKernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView1D<GpuUInt128, Stride1D.Dense>, GpuUInt128, ArrayView1D<GpuUInt128, Stride1D.Dense>>>();
kernelLauncher(stream, length, exponentBuffer.View, modulus, remainderBuffer.View);
remainderBuffer.View.CopyToCPU(stream, ref MemoryMarshal.GetReference(resultSpan), length);
@@ -3,6 +3,7 @@ using ILGPU.Runtime;
using System.Runtime.CompilerServices;
using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
using ILGPU;
namespace PerfectNumbers.Core;
@@ -235,12 +236,13 @@ public sealed class HeuristicCombinedPrimeTester
private static bool HeuristicTrialDivisionGpuDetectsDivisor(PrimeOrderCalculatorAccelerator gpu, ulong n, ulong maxDivisorSquare, byte nMod10)
{
var acceleratorIndex = gpu.AcceleratorIndex;
var flagView1D = gpu.OutputInt!.View;
bool compositeDetected;
Span<int> compositeFlag = stackalloc int[1];
// int compositeFlag = 0;
var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
var kernel = gpu.HeuristicCombinedTrialDivisionKernel;
var flagView1D = gpu.OutputInt!.View;
bool compositeDetected;
// int compositeFlag = 0;
Span<int> compositeFlag = stackalloc int[1];
flagView1D.MemSetToZero(stream);
var kernelLauncher = gpu.HeuristicCombinedTrialDivisionKernelLauncher;
@@ -264,10 +266,14 @@ public sealed class HeuristicCombinedPrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool EvaluateWithOpenNumericFallback(ulong n) => Prime.Numbers.IsPrime(n);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n) => n;
private static bool EvaluateWithOpenNumericFallback(ulong n)
{
return Prime.Numbers.IsPrime(n);
}
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n)
{
return n;
}
private static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10) => nMod10 switch
{
@@ -464,7 +470,9 @@ public sealed class HeuristicCombinedPrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer)
=> new(maxDivisorSquare, nMod10, groupBBuffer);
{
return new HeuristicDivisorEnumerator(maxDivisorSquare, nMod10, groupBBuffer);
}
internal struct HeuristicGroupBSequenceState
{
@@ -472,7 +480,9 @@ public sealed class HeuristicCombinedPrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static MersenneHeuristicDivisorEnumerator CreateMersenneDivisorEnumerator(ulong exponent, ulong maxDivisor)
=> new(exponent, maxDivisor);
{
return new MersenneHeuristicDivisorEnumerator(exponent, maxDivisor);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
@@ -480,7 +490,7 @@ public sealed class HeuristicCombinedPrimeTester
ulong divisor = candidate.Value;
MontgomeryDivisorData divisorData = MontgomeryDivisorData.FromModulus(divisor);
bool hasCycleHint = TryGetCycleLengthHint(divisor, out ulong cycleLength);
return new(candidate, divisorData, cycleLength, hasCycleHint);
return new HeuristicDivisorPreparation(candidate, divisorData, cycleLength, hasCycleHint);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -578,7 +588,7 @@ public sealed class HeuristicCombinedPrimeTester
ulong value = entry;
byte ending = (byte)(value % 10UL);
ushort residue = (ushort)(value % Wheel210);
candidate = new(value, group, ending, 0, residue);
candidate = new HeuristicDivisorCandidate(value, group, ending, 0, residue);
return true;
}
@@ -681,7 +691,7 @@ public sealed class HeuristicCombinedPrimeTester
}
ushort residue = (ushort)(value % Wheel210);
return new(value, group, ending, 0, residue);
return new HeuristicDivisorCandidate(value, group, ending, 0, residue);
}
}
}
+51 -30
View File
@@ -3,6 +3,7 @@ using System.Runtime.CompilerServices;
using ILGPU.Runtime;
using PerfectNumbers.Core.Gpu;
using PerfectNumbers.Core.Gpu.Accelerators;
using ILGPU;
namespace PerfectNumbers.Core;
@@ -67,8 +68,7 @@ public sealed class HeuristicPrimeTester
public static HeuristicPrimeTester Exclusive => _tester ??= new();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeCpu(ulong n)
public bool IsPrimeCpu(ulong n)
{
byte nMod10 = (byte)n.Mod10();
ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n);
@@ -82,18 +82,19 @@ public sealed class HeuristicPrimeTester
return HeuristicTrialDivisionCpu(n, maxDivisorSquare, nMod10, includeGroupB);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeGpu(ulong n)
public bool IsPrimeGpu(ulong n)
{
byte nMod10 = (byte)n.Mod10();
ulong maxDivisorSquare = ComputeHeuristicDivisorSquareLimit(n);
return IsPrimeGpu(n, maxDivisorSquare, nMod10);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeGpu(ulong n, ulong maxDivisorSquare, byte nMod10) => HeuristicIsPrimeGpuCore(n, maxDivisorSquare, nMod10);
public bool IsPrimeGpu(ulong n, ulong maxDivisorSquare, byte nMod10)
{
return HeuristicIsPrimeGpuCore(n, maxDivisorSquare, nMod10);
}
private static bool HeuristicIsPrimeGpuCore(ulong n, ulong maxDivisorSquare, byte nMod10)
private bool HeuristicIsPrimeGpuCore(ulong n, ulong maxDivisorSquare, byte nMod10)
{
// TODO: Is this condition ever met on the execution path in EvenPerfectBitScanner?
if (maxDivisorSquare < 9UL)
@@ -132,7 +133,7 @@ public sealed class HeuristicPrimeTester
break;
}
ulong divisor = groupADivisors[groupAIndex];
ulong divisor = (ulong)groupADivisors[groupAIndex];
if (n % divisor == 0UL)
{
return false;
@@ -185,7 +186,7 @@ public sealed class HeuristicPrimeTester
break;
}
ulong divisor = groupADivisors[groupAIndex];
ulong divisor = (ulong)groupADivisors[groupAIndex];
if (n % divisor == 0UL)
{
return false;
@@ -239,12 +240,13 @@ public sealed class HeuristicPrimeTester
}
private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
private bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
{
// GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
int acceleratorIndex = gpu.AcceleratorIndex;
var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
var kernel = gpu.HeuristicCombinedTrialDivisionKernel;
var flagView1D = gpu.OutputInt!.View;
bool compositeDetected;
@@ -259,7 +261,7 @@ public sealed class HeuristicPrimeTester
// HeuristicGpuDivisorTableKind tableKind,
// HeuristicGpuDivisorTables tables)
var kernelLauncher = gpu.HeuristicCombinedTrialDivisionKernelLauncher;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, byte, ArrayView<int>, ulong, ulong, HeuristicGpuDivisorTableKind, HeuristicCombinedGpuViews>>();
kernelLauncher(
stream,
1,
@@ -267,6 +269,7 @@ public sealed class HeuristicPrimeTester
flagView1D,
n,
maxDivisorSquare,
HeuristicGpuDivisorTableKind.GroupA,
gpu.DivisorTables);
flagView1D.CopyToCPU(stream, ref compositeFlag, 1);
@@ -318,11 +321,17 @@ public sealed class HeuristicPrimeTester
return compositeDetected;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool EvaluateWithOpenNumericFallback(ulong n) => Prime.Numbers.IsPrime(n);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n) => n;
private static bool EvaluateWithOpenNumericFallback(ulong n)
{
return Prime.Numbers.IsPrime(n);
}
internal static ulong ComputeHeuristicDivisorSquareLimit(ulong n)
{
return n;
}
private static ReadOnlySpan<byte> GetGroupBEndingOrder(byte nMod10) => nMod10 switch
{
@@ -330,7 +339,7 @@ public sealed class HeuristicPrimeTester
3 => GroupBEndingOrderMod3,
7 => GroupBEndingOrderMod7,
9 => GroupBEndingOrderMod9,
_ => [],
_ => ReadOnlySpan<byte>.Empty,
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -406,19 +415,19 @@ public sealed class HeuristicPrimeTester
private static ReadOnlySpan<uint> GetGroupBDivisors(byte ending) => ending switch
{
1 => DivisorGenerator.SmallPrimesLastOneWithoutLastThree,
3 => [],
3 => ReadOnlySpan<uint>.Empty,
7 => DivisorGenerator.SmallPrimesLastSevenWithoutLastThree,
9 => DivisorGenerator.SmallPrimesLastNineWithoutLastThree,
_ => [],
_ => ReadOnlySpan<uint>.Empty,
};
private static ReadOnlySpan<ulong> GetGroupBDivisorSquares(byte ending) => ending switch
{
1 => DivisorGenerator.SmallPrimesPow2LastOneWithoutLastThree,
3 => [],
3 => ReadOnlySpan<ulong>.Empty,
7 => DivisorGenerator.SmallPrimesPow2LastSevenWithoutLastThree,
9 => DivisorGenerator.SmallPrimesPow2LastNineWithoutLastThree,
_ => [],
_ => ReadOnlySpan<ulong>.Empty,
};
private static int InitializeGroupBStates(byte nMod10, Span<HeuristicGroupBSequenceState> buffer)
@@ -435,11 +444,16 @@ public sealed class HeuristicPrimeTester
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer) => new(maxDivisorSquare, nMod10, groupBBuffer);
internal static HeuristicDivisorEnumerator CreateHeuristicDivisorEnumerator(ulong maxDivisorSquare, byte nMod10, Span<HeuristicGroupBSequenceState> groupBBuffer)
{
return new HeuristicDivisorEnumerator(maxDivisorSquare, nMod10, groupBBuffer);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static MersenneHeuristicDivisorEnumerator CreateMersenneDivisorEnumerator(ulong exponent, ulong maxDivisor)
=> new(exponent, maxDivisor);
{
return new MersenneHeuristicDivisorEnumerator(exponent, maxDivisor);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static HeuristicDivisorPreparation PrepareHeuristicDivisor(in HeuristicDivisorCandidate candidate)
@@ -597,18 +611,25 @@ public sealed class HeuristicPrimeTester
internal struct HeuristicGroupBSequenceState(byte ending, byte priorityIndex)
internal struct HeuristicGroupBSequenceState
{
public byte Ending = ending;
public byte PriorityIndex = priorityIndex;
public int Index = 0;
public byte Ending;
public byte PriorityIndex;
public int Index;
public HeuristicGroupBSequenceState(byte ending, byte priorityIndex)
{
Ending = ending;
PriorityIndex = priorityIndex;
Index = 0;
}
public bool TryPeek(ulong maxDivisorSquare, out ulong divisor)
{
ReadOnlySpan<uint> divisors = GetGroupBDivisors(Ending);
ReadOnlySpan<ulong> squares = GetGroupBDivisorSquares(Ending);
int index = Index;
if (index >= divisors.Length)
if ((uint)index >= (uint)divisors.Length)
{
divisor = 0UL;
return false;
@@ -621,7 +642,7 @@ public sealed class HeuristicPrimeTester
return false;
}
divisor = divisors[index];
divisor = (ulong)divisors[index];
return true;
}
@@ -710,11 +731,11 @@ public sealed class HeuristicPrimeTester
residueStepper.Advance();
}
public readonly ulong ProcessedCount => processedCount;
public ulong ProcessedCount => processedCount;
public readonly ulong LastDivisor => lastDivisor;
public ulong LastDivisor => lastDivisor;
public readonly bool Exhausted => !active;
public bool Exhausted => !active;
private static HeuristicDivisorCandidate CreateCandidate(ulong value)
{
@@ -10,7 +10,7 @@ public interface IMersenneNumberDivisorByDivisorTester
ulong GetAllowedMaxDivisor(ulong prime);
bool IsPrime(ulong prime, out bool divisorsExhausted, out ulong divisor);
bool IsPrime(ulong prime, out bool divisorsExhausted);
IDivisorScanSession CreateDivisorSession();
@@ -14,7 +14,7 @@ public static class MersenneNumberDivisorByDivisorTester
ulong startPrime,
Action markComposite,
Action clearComposite,
Action<ulong, bool, bool, bool, ulong> printResult,
Action<ulong, bool, bool, bool> printResult,
int threadCount,
int primesPerTask)
{
@@ -242,18 +242,18 @@ public static class MersenneNumberDivisorByDivisorTester
void ProcessPrime(ulong prime)
{
Console.WriteLine($"Processing {prime}");
bool isPrime = tester.IsPrime(prime, out bool divisorsExhausted, out ulong divisor);
bool isPrime = tester.IsPrime(prime, out bool divisorsExhausted);
if (!isPrime)
{
markComposite();
printResult(prime, true, true, false, divisor);
printResult(prime, true, true, false);
Console.WriteLine($"Finished processing {prime}");
return;
}
clearComposite();
printResult(prime, true, divisorsExhausted, true, divisor);
printResult(prime, true, divisorsExhausted, true);
Console.WriteLine($"Finished processing {prime}");
}
@@ -8,13 +8,12 @@ public static class PerfectNumberConstants
public const int DefaultSmallPrimeFactorSlotCount = 64;
public const int DefaultSpecialMaxFactorCapacity = 1024;
public const ulong ExtraDivisorCycleSearchLimit = 64UL;
public const int GpuFrequency = 768 - 1;
public const int MaxQForDivisorCycles = 4_000_000;
public static readonly uint PrimesLimit = 1_000_000; //(ulong)Array.MaxLength;// 1_000_000;
public const int MaxOddPowersCount = 128;
public const int PooledArrayThreshold = 64;
public static readonly int RollingAccelerators = 298; //SharedGpuContext.Device.MaxNumThreadsPerGroup;
public const int ThreadsByAccelerator = 1;
public static readonly int RollingAccelerators = 100; //SharedGpuContext.Device.MaxNumThreadsPerGroup;
public const int ThreadsByAccelerator = 4096;
// TODO: Load these limits from the benchmark-driven configuration so CPU and GPU scans stay aligned with the optimal
// divisor-cycle datasets we generate offline.
// TODO: Promote these magic numbers into a runtime profile derived from EvenPerfectBitScanner.Benchmarks so we can retune
@@ -1375,19 +1375,20 @@ internal static partial class PrimeOrderCalculator
private static bool RunOnGpu()
{
// return true;
int cpuCount = Atomic.Add(ref _cpuCount, 1);
// return (cpuCount % GpuFrequency) == 0;
if (cpuCount == PerfectNumberConstants.GpuFrequency)
return true;
const int GpuFrequency = 1024 - 1;
int cpuCount = Atomic.Add(target: ref _cpuCount, 1);
if (cpuCount == GpuFrequency)
{
Atomic.Add(ref _cpuCount, -PerfectNumberConstants.GpuFrequency);
Atomic.Add(ref _cpuCount, -GpuFrequency);
}
else if (cpuCount > PerfectNumberConstants.GpuFrequency)
else if (cpuCount > GpuFrequency)
{
cpuCount -= PerfectNumberConstants.GpuFrequency;
cpuCount -= GpuFrequency;
}
return cpuCount == PerfectNumberConstants.GpuFrequency;
return cpuCount != GpuFrequency;
}
private static void PopulateSmallPrimeFactorsCpu(
@@ -36,13 +36,15 @@ internal static partial class PrimeOrderCalculator
ulong order = phi;
var acceleratorIndex = gpu.AcceleratorIndex;
var kernel = gpu.CheckFactorsKernel;
gpu.EnsureCapacity(entryCount, 1);
// GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
gpu.Pow2ModEntriesToTestOnDevice.View.CopyFromCPU(stream, entries);
var kernelLauncher = gpu.CheckFactorsKernelLauncher;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, int, ulong, ArrayView1D<KeyValuePair<ulong, int>, Stride1D.Dense>, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, entryCount, phi, gpu.Pow2ModEntriesToTestOnDevice.View, divisorData, gpu.OutputUlong.View);
gpu.OutputUlong.View.CopyToCPU(stream, ref order, 1);
@@ -65,16 +67,19 @@ internal static partial class PrimeOrderCalculator
int acceleratorIndex = gpu.AcceleratorIndex;
var accelerator = gpu.Accelerator;
var kernelLauncher = gpu.SmallPrimeFactorKernelLauncher;
// GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
var kernel = gpu.SmallPrimeFactorKernel;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, uint, ArrayView1D<uint, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<int, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorCountSlotView = gpu.SmallPrimeFactorCountSlot.View;
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorRemainingSlotView = gpu.Input.View;
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorPrimeSlotsView = gpu.OutputUlong.View;
ArrayView1D<int, Stride1D.Dense> smallPrimeFactorExponentSlotsView = gpu.OutputInt.View;
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorsSquaresView = gpu.SmallPrimeFactorSquares;
ArrayView1D<uint, Stride1D.Dense> smallPrimeFactorsPrimesView = gpu.SmallPrimeFactorPrimes;
ArrayView1D<ulong, Stride1D.Dense> smallPrimeFactorsSquaresView = gpu.SmallPrimeFactorSquares;
// GpuPrimeWorkLimiter.Acquire();
var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
kernelLauncher(
stream,
1,
@@ -131,14 +136,17 @@ internal static partial class PrimeOrderCalculator
int acceleratorIndex = gpu.AcceleratorIndex;
// GpuPrimeWorkLimiter.Acquire();
ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = gpu.Input.View;
var stream = AcceleratorStreamPool.Rent(acceleratorIndex);
ArrayView1D<ulong, Stride1D.Dense> specialMaxFactorsView = gpu.Input.View;
specialMaxFactorsView.SubView(0, factorCount).CopyFromCPU(stream, factors);
var kernel = gpu.SpecialMaxKernel;
ArrayView1D<ulong, Stride1D.Dense> specialMaxResultView = gpu.SpecialMaxResult.View;
var kernelLauncher = gpu.SpecialMaxKernelLauncher;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ArrayView1D<ulong, Stride1D.Dense>, int, MontgomeryDivisorData, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(
stream,
1,
@@ -170,7 +178,7 @@ internal static partial class PrimeOrderCalculator
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
gpu.Input.View.CopyFromCPU(stream, randomStateSpan);
var kernelLauncher = gpu.PollardRhoKernelLauncher;
var kernelLauncher = gpu.PollardRhoKernel.CreateLauncherDelegate<Action<AcceleratorStream, ulong, int, ArrayView1D<ulong, Stride1D.Dense>, ArrayView1D<byte, Stride1D.Dense>, ArrayView1D<ulong, Stride1D.Dense>>>();
kernelLauncher(stream, n, 1, gpu.Input.View, gpu.OutputByte.View, gpu.OutputUlong.View);
+46 -7
View File
@@ -90,17 +90,19 @@ public sealed class PrimeTester
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimeGpu(ulong n)
{
byte flag = 0;
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
int acceleratorIndex = gpu.AcceleratorIndex;
var inputView = gpu.Input.View;
var outputView = gpu.OutputByte.View;
var kernel = gpu.SmallPrimeSieveKernel!;
// GpuPrimeWorkLimiter.Acquire();
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
inputView.CopyFromCPU(stream, ref n, 1);
var kernelLauncher = gpu.SmallPrimeSieveKernelLauncher;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
kernelLauncher(
stream,
@@ -116,7 +118,6 @@ public sealed class PrimeTester
gpu.DevicePrimesPow2LastNine,
outputView);
byte flag = 0;
outputView.CopyToCPU(stream, ref flag, 1);
stream.Synchronize();
@@ -135,12 +136,13 @@ public sealed class PrimeTester
var inputView = input.View;
var output = gpu.OutputByte;
var outputView = output.View;
Kernel kernel = gpu.SmallPrimeSieveKernel!;
int acceleratorIndex = gpu.AcceleratorIndex;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
inputView.CopyFromCPU(stream, ref n, 1);
var kernelLauncher = gpu.SmallPrimeSieveKernelLauncher;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
kernelLauncher(
stream,
@@ -194,6 +196,7 @@ public sealed class PrimeTester
// GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeOrderCalculatorAccelerator.Rent(GpuBatchSize);
int acceleratorIndex = gpu.AcceleratorIndex;
var kernel = gpu.SmallPrimeSieveKernel!;
int totalLength = values.Length;
int batchSize = GpuBatchSize;
@@ -204,7 +207,7 @@ public sealed class PrimeTester
int pos = 0;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
var kernelLauncher = gpu.SmallPrimeSieveKernelLauncher;
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<uint>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<ulong>, ArrayView<byte>>>();
while (pos < totalLength)
{
@@ -262,7 +265,7 @@ public sealed class PrimeTester
// ResidueComputationBenchmarks so divisor-cycle metadata can short-circuit the test
// instead of recomputing binary GCD for every candidate.
ulong m = (ulong)BitOperations.Log2(n);
return n.BinaryGcd(m) != 1UL;
return BinaryGcd(n, m) != 1UL;
}
internal static void SharesFactorWithMaxExponentBatch(ReadOnlySpan<ulong> values, Span<byte> results)
@@ -277,14 +280,15 @@ public sealed class PrimeTester
var gpu = PrimeOrderCalculatorAccelerator.Rent(1);
int acceleratorIndex = gpu.AcceleratorIndex;
var kernel = gpu.SharesFactorKernel;
gpu.EnsureCapacity(0, length);
MemoryBuffer1D<ulong, Stride1D.Dense>? inputBuffer = gpu.Input;
MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer = gpu.OutputByte;
AcceleratorStream stream = AcceleratorStreamPool.Rent(acceleratorIndex);
inputBuffer.View.CopyFromCPU(stream, values);
var kernelLauncher = kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ArrayView<ulong>, ArrayView<byte>>>();
MemoryBuffer1D<byte, Stride1D.Dense>? resultBuffer = gpu.OutputByte;
var kernelLauncher = gpu.SharesFactorKernelLauncher;
kernelLauncher(stream, length, inputBuffer.View, resultBuffer.View);
resultBuffer.View.CopyToCPU(stream, in results);
@@ -294,4 +298,39 @@ public sealed class PrimeTester
PrimeOrderCalculatorAccelerator.Return(gpu);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong BinaryGcd(ulong u, ulong v)
{
// TODO: Swap this handwritten binary GCD for the optimized helper measured in
// GpuUInt128BinaryGcdBenchmarks so CPU callers share the faster subtract-less
// ladder once the common implementation is promoted into PerfectNumbers.Core.
// You have an example in the benchmarks and you already implemented it in
// GpuUInt128, iirc.
if (u == 0UL)
{
return v;
}
if (v == 0UL)
{
return u;
}
int shift = BitOperations.TrailingZeroCount(u | v);
u >>= BitOperations.TrailingZeroCount(u);
do
{
v >>= BitOperations.TrailingZeroCount(v);
if (u > v)
{
(u, v) = (v, u);
}
v -= u;
}
while (v != 0UL);
return u << shift;
}
}
BIN
View File
Binary file not shown.