From a7ed762428e0a31ecaa4cfa9b7b6b9b476d880c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Lema=C5=84czyk?= Date: Mon, 20 Oct 2025 01:07:02 +0200 Subject: [PATCH] Simplify scheduler configuration and pending composite caching --- .../PrimeOrderCalculator.Cpu.cs | 4 +- PerfectNumbers.Core/PrimeOrderCalculator.cs | 8 +-- PerfectNumbers.Core/UnboundedTaskScheduler.cs | 59 ++++++------------- 3 files changed, 23 insertions(+), 48 deletions(-) diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs index 8f61221..5148dc0 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.Cpu.cs @@ -858,13 +858,13 @@ internal static partial class PrimeOrderCalculator if (currentTimestamp > deadlineTimestamp) { pollardRhoDeadlineReached = true; - pending.Add(new PendingEntry(composite, knownComposite: false).WithPrimality(false)); + pending.Add(new PendingEntry(composite, knownComposite: true)); continue; } if (!TryPollardRho(composite, deadlineTimestamp, out ulong factor)) { - pending.Add(new PendingEntry(composite, knownComposite: false).WithPrimality(false)); + pending.Add(new PendingEntry(composite, knownComposite: true)); continue; } diff --git a/PerfectNumbers.Core/PrimeOrderCalculator.cs b/PerfectNumbers.Core/PrimeOrderCalculator.cs index 75c9cd3..d3fd7e6 100644 --- a/PerfectNumbers.Core/PrimeOrderCalculator.cs +++ b/PerfectNumbers.Core/PrimeOrderCalculator.cs @@ -1,3 +1,5 @@ +using System.Runtime.CompilerServices; + namespace PerfectNumbers.Core; internal static partial class PrimeOrderCalculator @@ -14,10 +16,8 @@ internal static partial class PrimeOrderCalculator public static PrimeOrderSearchConfig HeuristicDefault { - get - { - return _heuristicDefault; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _heuristicDefault; } public static readonly PrimeOrderSearchConfig StrictDefault = new(smallFactorLimit: 1_000_000, pollardRhoMilliseconds: 0, maxPowChecks: 0, PrimeOrderMode.Strict); diff --git a/PerfectNumbers.Core/UnboundedTaskScheduler.cs b/PerfectNumbers.Core/UnboundedTaskScheduler.cs index cbfe5fd..b552fa9 100644 --- a/PerfectNumbers.Core/UnboundedTaskScheduler.cs +++ b/PerfectNumbers.Core/UnboundedTaskScheduler.cs @@ -1,31 +1,18 @@ using System; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; namespace PerfectNumbers.Core; public sealed class UnboundedTaskScheduler : TaskScheduler { - private static readonly object InstanceLock = new(); private static UnboundedTaskScheduler? _instance; private static int _configuredThreadCount = Environment.ProcessorCount; - public static UnboundedTaskScheduler Instance - { - get - { - lock (InstanceLock) - { - _instance ??= new UnboundedTaskScheduler(GetNormalizedThreadCount(_configuredThreadCount)); - return _instance; - } - } - } + public static UnboundedTaskScheduler Instance => _instance ??= new UnboundedTaskScheduler(_configuredThreadCount); - public static int ConfiguredThreadCount => GetNormalizedThreadCount(Volatile.Read(ref _configuredThreadCount)); + public static int ConfiguredThreadCount => _configuredThreadCount; - private readonly object _poolLock = new(); private TaskThreadPool _threadPool; private UnboundedTaskScheduler(int threadCount) @@ -35,20 +22,15 @@ public sealed class UnboundedTaskScheduler : TaskScheduler public static void ConfigureThreadCount(int threadCount) { - int normalizedThreadCount = GetNormalizedThreadCount(threadCount); + _configuredThreadCount = threadCount; + PrimeOrderCalculator.PrimeOrderSearchConfig.ConfigureHeuristicDefault(threadCount); - lock (InstanceLock) - { - Volatile.Write(ref _configuredThreadCount, normalizedThreadCount); - PrimeOrderCalculator.PrimeOrderSearchConfig.ConfigureHeuristicDefault(normalizedThreadCount); - - if (_instance is null) - { - return; - } - - _instance.UpdateThreadPool(normalizedThreadCount); - } + // On EvenPerfectBitScanner's execution path the scheduler instance is created after configuration, + // so updating an existing pool would never run. Leave the update path disabled for now. + // if (_instance is not null) + // { + // _instance.UpdateThreadPool(threadCount); + // } } public override int MaximumConcurrencyLevel => int.MaxValue; @@ -60,18 +42,15 @@ public sealed class UnboundedTaskScheduler : TaskScheduler private void UpdateThreadPool(int threadCount) { - lock (_poolLock) + if (_threadPool.ThreadCount == threadCount) { - if (_threadPool.ThreadCount == threadCount) - { - return; - } - - TaskThreadPool newPool = new(threadCount, ExecuteTask); - TaskThreadPool oldPool = _threadPool; - _threadPool = newPool; - oldPool.Dispose(); + return; } + + TaskThreadPool newPool = new(threadCount, ExecuteTask); + TaskThreadPool oldPool = _threadPool; + _threadPool = newPool; + oldPool.Dispose(); } private void ExecuteTask(Task task) @@ -89,8 +68,4 @@ public sealed class UnboundedTaskScheduler : TaskScheduler return _threadPool.GetScheduledTasks(); } - private static int GetNormalizedThreadCount(int threadCount) - { - return threadCount < 1 ? 1 : threadCount; - } }