/// <summary> /// Run a specific sieve using the provided parameters. /// </summary> /// <param name="sieve">The sieve to run, as determined by a combination of properties.</param> /// <param name="settings">The running parameters to use.</param> /// <exception cref="ArgumentException">If no sieve class matching the requested sieve can be found, an exception will be thrown.</exception> private static void Run(SieveProperty sieve, SettingsV2 settings) { Func <ISieveRunner> createSieve = GetSieveCreator(sieve, settings) ?? throw new ArgumentException($"Unable to run sieve: {sieve}", nameof(sieve)); var demo = createSieve(); Console.WriteLine($"@Kinematics: Starting ({demo.Description}{(settings.MultiThreaded ? " (multithreaded)" : "")})..."); long millisecondsToRun = settings.SecondsToRun * MillisecondsPerSecond; Stopwatch watch = new(); var(completedSieve, passes) = settings.MultiThreaded switch { false => RunSingleThread(createSieve, watch, millisecondsToRun, settings), true => RunMultiThread(createSieve, watch, millisecondsToRun, settings), }; if (completedSieve is null) { Console.WriteLine("Invalid state after run."); return; } PrintResults(completedSieve, passes, watch, settings); }
/// <summary> /// Run all requested sieves based on the provided settings. /// </summary> /// <param name="settings">Collection of options used to determine which sieves to run, and parameters thereof.</param> public static void Run(SettingsV2 settings) { List <SieveProperty> sievesToRun = settings.GetSieves(); foreach (var sieve in sievesToRun) { try { Run(sieve, settings); } catch (ArgumentException e) { Console.WriteLine(e.Message); } } }
/// <summary> /// Function to translate sieve property presets into functions to create a sieve object. /// </summary> /// <param name="sieve">The sieve requested.</param> /// <param name="settings">The settings to be used during the sieve's run.</param> /// <returns>Returns a function to create an instance of the requested sieve.</returns> private static Func <ISieveRunner>?GetSieveCreator(SieveProperty sieve, SettingsV2 settings) { return(sieve switch { SievePropertyCombinations.Bit2 => () => new Bit2Sieve(settings.SieveSize), SievePropertyCombinations.Bit2While => () => new Bit2WhileSieve(settings.SieveSize), SievePropertyCombinations.Bit6 => () => new Bit6Sieve(settings.SieveSize), SievePropertyCombinations.Bit30 => () => new Bit30Sieve(settings.SieveSize), SievePropertyCombinations.Bool2 => () => new Bool2Sieve(settings.SieveSize), SievePropertyCombinations.Bool2While => () => new Bool2WhileSieve(settings.SieveSize), SievePropertyCombinations.Bool6 => () => new Bool6Sieve(settings.SieveSize), SievePropertyCombinations.Bool30 => () => new Bool30Sieve(settings.SieveSize), SievePropertyCombinations.InvBool2 => () => new InvBool2Sieve(settings.SieveSize), SievePropertyCombinations.InvBool2While => () => new InvBool2WhileSieve(settings.SieveSize), SievePropertyCombinations.InvBool6 => () => new InvBool6Sieve(settings.SieveSize), SievePropertyCombinations.InvBool30 => () => new InvBool30Sieve(settings.SieveSize), SievePropertyCombinations.PoolB2 => () => new PoolB2Sieve(settings.SieveSize), SievePropertyCombinations.PoolD2 => () => new PoolD2Sieve(settings.SieveSize), SievePropertyCombinations.PoolQ2 => () => new PoolQ2Sieve(settings.SieveSize), SievePropertyCombinations.PoolB6 => () => new PoolB6Sieve(settings.SieveSize), SievePropertyCombinations.PoolD6 => () => new PoolD6Sieve(settings.SieveSize), SievePropertyCombinations.PoolQ6 => () => new PoolQ6Sieve(settings.SieveSize), SievePropertyCombinations.PoolB30 => () => new PoolB30Sieve(settings.SieveSize), SievePropertyCombinations.PoolD30 => () => new PoolD30Sieve(settings.SieveSize), SievePropertyCombinations.PoolQ30 => () => new PoolQ30Sieve(settings.SieveSize), SievePropertyCombinations.PoolQ30M => () => new PoolQ30MSieve(settings.SieveSize), SievePropertyCombinations.PoolQ2M => () => new PoolQ2MSieve(settings.SieveSize), SievePropertyCombinations.RawB2 => () => new RawB2Sieve(settings.SieveSize), SievePropertyCombinations.RawD2 => () => new RawD2Sieve(settings.SieveSize), SievePropertyCombinations.RawQ2 => () => new RawQ2Sieve(settings.SieveSize), SievePropertyCombinations.RawB6 => () => new RawB6Sieve(settings.SieveSize), SievePropertyCombinations.RawD6 => () => new RawD6Sieve(settings.SieveSize), SievePropertyCombinations.RawQ6 => () => new RawQ6Sieve(settings.SieveSize), SievePropertyCombinations.RawB30 => () => new RawB30Sieve(settings.SieveSize), SievePropertyCombinations.RawD30 => () => new RawD30Sieve(settings.SieveSize), SievePropertyCombinations.RawQ30 => () => new RawQ30Sieve(settings.SieveSize), SievePropertyCombinations.RawQ30M => () => new RawQ30MSieve(settings.SieveSize), _ => null });
/// <summary> /// Run a provided sieve on a single thread, repeatedly, for as long as specified. /// </summary> /// <param name="createSieve">The function that creates a sieve.</param> /// <param name="watch">The time tracking watch.</param> /// <param name="millisecondsToRun">How long to run.</param> /// <param name="settings">Settings that may affect how the sieves are run.</param> /// <returns>Returns the last sieve, and how many times the sieve was run.</returns> private static (ISieveRunner?, int) RunSingleThread( Func <ISieveRunner> createSieve, Stopwatch watch, long millisecondsToRun, SettingsV2 settings) { ISieveRunner?sieve = null; int passes = 0; Warmup(createSieve); watch.Start(); while (watch.ElapsedMilliseconds < millisecondsToRun) { sieve = createSieve(); sieve.Run(); passes++; } watch.Stop(); return(sieve, passes); }
/// <summary> /// Calculate the number of threads used when running a sieve. /// </summary> /// <param name="sieve">The sieve that was run.</param> /// <param name="settings">The run settings.</param> /// <returns>Returns a tuple of external threads used (each one running one sieve) and internal threads used (how many threads each sieve uses).</returns> private static (int thraeds, int pThreads) GetThreadCount(ISieveRunner sieve, SettingsV2 settings) { int threads = 1; if (settings.MultiThreaded) { threads = settings.ThreadCount == 0 ? Environment.ProcessorCount : settings.ThreadCount; } int pThreads = 1; if (sieve.IsParallel) { pThreads = settings.PThreadCount == 0 ? Environment.ProcessorCount : settings.PThreadCount; } return(threads, pThreads); }
/// <summary> /// Print the final output to the console. /// </summary> /// <param name="sieve">The sieve that was run.</param> /// <param name="passes">How many times it was run.</param> /// <param name="watch">The stopwatch used to time it.</param> /// <param name="settings">The settings that were in effect.</param> private static void PrintResults(ISieveRunner sieve, int passes, Stopwatch watch, SettingsV2 settings) { if (settings.Verbose) { string listing = sieve.GetFoundPrimes() .Select(a => a.ToString()) .Aggregate((a, b) => $"{a}, {b}"); Console.WriteLine(listing); Console.WriteLine(); } (int threads, int pThreads) = GetThreadCount(sieve, settings); Console.WriteLine(GetLongOutputDescription(sieve, passes, watch, threads, pThreads)); Console.WriteLine(GetCompactOutputDescription(sieve, passes, watch, threads, pThreads)); }
/// <summary> /// Run a provided sieve on multiple threads, for as long as specified. /// </summary> /// <param name="createSieve">The function that creates a sieve.</param> /// <param name="watch">The time tracking watch.</param> /// <param name="millisecondsToRun">How long to run.</param> /// <param name="settings">Settings that may affect how the sieves are run.</param> /// <returns>Returns the first sieve, and how many times the sieve was run.</returns> private static (ISieveRunner?, int) RunMultiThread( Func <ISieveRunner> createSieve, Stopwatch watch, long millisecondsToRun, SettingsV2 settings) { ISieveRunner?sieve; ISieveRunner?firstSieve = null; int passes = 0; int threadCount = settings.ThreadCount; if (threadCount <= 0) { threadCount = Environment.ProcessorCount; } Warmup(createSieve); watch.Start(); while (watch.ElapsedMilliseconds < millisecondsToRun) { Parallel.For(0, threadCount, i => { sieve = createSieve(); firstSieve ??= sieve; sieve.Run(); if (watch.ElapsedMilliseconds < millisecondsToRun) { Interlocked.Increment(ref passes); } }); } watch.Stop(); return(firstSieve, passes); }