diff --git a/PerfectNumbers.Core.Tests/Gpu/PrimeOrderGpuHeuristicsTests.cs b/PerfectNumbers.Core.Tests/Gpu/PrimeOrderGpuHeuristicsTests.cs index 0d0ac41..9b0a40c 100644 --- a/PerfectNumbers.Core.Tests/Gpu/PrimeOrderGpuHeuristicsTests.cs +++ b/PerfectNumbers.Core.Tests/Gpu/PrimeOrderGpuHeuristicsTests.cs @@ -11,7 +11,7 @@ public class PrimeOrderGpuHeuristicsTests { public PrimeOrderGpuHeuristicsTests() { - PrimeOrderGpuHeuristics.ClearAllOverflowForTesting(); + PrimeOrderGpuHeuristics.OverflowRegistry.Clear(); PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting(); } @@ -21,7 +21,7 @@ public class PrimeOrderGpuHeuristicsTests const ulong prime = 97UL; try { - PrimeOrderGpuHeuristics.MarkOverflow(prime); + PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0; GpuPow2ModStatus status = PrimeOrderGpuHeuristics.TryPow2Mod(1UL, prime, out ulong remainder); @@ -30,7 +30,7 @@ public class PrimeOrderGpuHeuristicsTests } finally { - PrimeOrderGpuHeuristics.ClearOverflow(prime); + PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); } } @@ -59,7 +59,7 @@ public class PrimeOrderGpuHeuristicsTests finally { PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting(); - PrimeOrderGpuHeuristics.ClearOverflow(prime); + PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); } } @@ -91,7 +91,7 @@ public class PrimeOrderGpuHeuristicsTests const ulong prime = 193UL; try { - PrimeOrderGpuHeuristics.MarkOverflow(prime); + PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0; ulong[] remainders = new ulong[2]; ulong[] exponents = { 1UL, 2UL }; @@ -103,7 +103,7 @@ public class PrimeOrderGpuHeuristicsTests } finally { - PrimeOrderGpuHeuristics.ClearOverflow(prime); + PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); } } @@ -139,7 +139,7 @@ public class PrimeOrderGpuHeuristicsTests finally { PrimeOrderGpuHeuristics.ResetCapabilitiesForTesting(); - PrimeOrderGpuHeuristics.ClearOverflow(prime); + PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); } } @@ -182,7 +182,7 @@ public class PrimeOrderGpuHeuristicsTests const ulong prime = 7UL; try { - PrimeOrderGpuHeuristics.MarkOverflow(prime); + PrimeOrderGpuHeuristics.OverflowRegistry[prime] = 0; PrimeOrderCalculator.PrimeOrderResult result = PrimeOrderCalculator.Calculate(prime, null, PrimeOrderCalculator.PrimeOrderSearchConfig.HeuristicDefault); @@ -191,7 +191,7 @@ public class PrimeOrderGpuHeuristicsTests } finally { - PrimeOrderGpuHeuristics.ClearOverflow(prime); + PrimeOrderGpuHeuristics.OverflowRegistry.TryRemove(prime, out _); } } } diff --git a/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs b/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs index 9138697..8a5643a 100644 --- a/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs +++ b/PerfectNumbers.Core/Gpu/PrimeOrderGpuHeuristics.cs @@ -16,6 +16,8 @@ internal static class PrimeOrderGpuHeuristics private static readonly ConcurrentDictionary OverflowedPrimes = new(); private static PrimeOrderGpuCapability s_capability = PrimeOrderGpuCapability.Default; + internal static ConcurrentDictionary OverflowRegistry => OverflowedPrimes; + internal static void OverrideCapabilitiesForTesting(PrimeOrderGpuCapability capability) { s_capability = capability; @@ -26,12 +28,6 @@ internal static class PrimeOrderGpuHeuristics s_capability = PrimeOrderGpuCapability.Default; } - internal static void MarkOverflow(ulong prime) => OverflowedPrimes[prime] = 0; - - internal static void ClearOverflow(ulong prime) => OverflowedPrimes.TryRemove(prime, out _); - - internal static void ClearAllOverflowForTesting() => OverflowedPrimes.Clear(); - public static GpuPow2ModStatus TryPow2Mod(ulong exponent, ulong prime, out ulong remainder) { remainder = 0UL; @@ -40,7 +36,9 @@ internal static class PrimeOrderGpuHeuristics return GpuPow2ModStatus.Unavailable; } - if (OverflowedPrimes.ContainsKey(prime)) + ConcurrentDictionary overflowRegistry = OverflowedPrimes; + + if (overflowRegistry.ContainsKey(prime)) { return GpuPow2ModStatus.Overflow; } @@ -49,7 +47,7 @@ internal static class PrimeOrderGpuHeuristics if (!SupportsPrime(prime, capability)) { - MarkOverflow(prime); + overflowRegistry[prime] = 0; return GpuPow2ModStatus.Overflow; } @@ -81,7 +79,9 @@ internal static class PrimeOrderGpuHeuristics return GpuPow2ModStatus.Unavailable; } - if (OverflowedPrimes.ContainsKey(prime)) + ConcurrentDictionary overflowRegistry = OverflowedPrimes; + + if (overflowRegistry.ContainsKey(prime)) { return GpuPow2ModStatus.Overflow; } @@ -90,7 +90,7 @@ internal static class PrimeOrderGpuHeuristics if (!SupportsPrime(prime, capability)) { - MarkOverflow(prime); + overflowRegistry[prime] = 0; return GpuPow2ModStatus.Overflow; } diff --git a/todo.txt b/todo.txt index c898b2f..ca5be75 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,3 @@ -- Inline the overflow tracking helpers in PrimeOrderGpuHeuristics so call sites can cache the dictionary locally and reduce delegate indirection. - Move the ulong bit-length helper into ULongExtensions and update PrimeOrderGpuHeuristics (and any other callers) to reuse it. - Implement the GPU heuristics for PrimeOrderCalculator using ILGPU. Reuse the numeric type compatibility probe results to select between EInteger, ERational, GpuUInt128, or any new GPU-specific big-integer representations, guarantee parity with the CPU heuristic algorithm (including 128-bit primes), prefer the shift-first multiply/shift variant to stay within device ranges, and wire the calculator through the accelerator path. - Extend the GPU numeric type probe to cover proposed custom types such as GpuUInt256 and GpuUInt512 once their definitions are available so we can plan the wide-order heuristics on the device.