Add timed test mode for prime candidate scans
This commit is contained in:
1 parent
9c474fc241
commit
03751c27be
1 file changed
+142
-1
@@ -1,5 +1,6 @@
|
|||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -45,6 +46,11 @@ internal static class Program
|
|||||||
private static readonly Optimized PrimeIterator = new();
|
private static readonly Optimized PrimeIterator = new();
|
||||||
private static ulong _byDivisorStartPrime;
|
private static ulong _byDivisorStartPrime;
|
||||||
|
|
||||||
|
private static bool _testMode;
|
||||||
|
private static int _testTargetPrimeCount;
|
||||||
|
private static int _testProcessedPrimeCount;
|
||||||
|
private const string TestTimeFileName = "even_perfect_test_time.txt";
|
||||||
|
|
||||||
[ThreadStatic]
|
[ThreadStatic]
|
||||||
private static bool _lastCompositeP;
|
private static bool _lastCompositeP;
|
||||||
|
|
||||||
@@ -95,6 +101,10 @@ internal static class Program
|
|||||||
ulong remainder = 0UL;
|
ulong remainder = 0UL;
|
||||||
bool startPrimeProvided = false;
|
bool startPrimeProvided = false;
|
||||||
|
|
||||||
|
_testMode = false;
|
||||||
|
_testTargetPrimeCount = 0;
|
||||||
|
_testProcessedPrimeCount = 0;
|
||||||
|
|
||||||
// NTT backend selection (GPU): reference vs staged
|
// NTT backend selection (GPU): reference vs staged
|
||||||
for (; argIndex < args.Length; argIndex++)
|
for (; argIndex < args.Length; argIndex++)
|
||||||
{
|
{
|
||||||
@@ -201,6 +211,10 @@ internal static class Program
|
|||||||
{
|
{
|
||||||
useModuloWorkaround = true;
|
useModuloWorkaround = true;
|
||||||
}
|
}
|
||||||
|
else if (arg.Equals("--test", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_testMode = true;
|
||||||
|
}
|
||||||
else if (arg.Equals("--use-order", StringComparison.OrdinalIgnoreCase))
|
else if (arg.Equals("--use-order", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
useOrder = true;
|
useOrder = true;
|
||||||
@@ -393,6 +407,20 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_testMode)
|
||||||
|
{
|
||||||
|
currentP = 31UL;
|
||||||
|
remainder = currentP % 6UL;
|
||||||
|
useDivisor = false;
|
||||||
|
useByDivisor = false;
|
||||||
|
useResidue = false;
|
||||||
|
useLucas = false;
|
||||||
|
filterFile = string.Empty;
|
||||||
|
maxPrimeLimit = UInt128.MaxValue;
|
||||||
|
maxPrimeConfigured = false;
|
||||||
|
startPrimeProvided = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (useByDivisor)
|
if (useByDivisor)
|
||||||
{
|
{
|
||||||
_byDivisorStartPrime = startPrimeProvided ? currentP : 0UL;
|
_byDivisorStartPrime = startPrimeProvided ? currentP : 0UL;
|
||||||
@@ -620,7 +648,7 @@ internal static class Program
|
|||||||
File.WriteAllText(ResultsFileName, $"p,searchedMersenne,detailedCheck,passedAllTests{Environment.NewLine}");
|
File.WriteAllText(ResultsFileName, $"p,searchedMersenne,detailedCheck,passedAllTests{Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool useFilter = !string.IsNullOrEmpty(filterFile);
|
bool useFilter = !_testMode && !string.IsNullOrEmpty(filterFile);
|
||||||
HashSet<ulong> filter = [];
|
HashSet<ulong> filter = [];
|
||||||
List<ulong> byDivisorCandidates = [];
|
List<ulong> byDivisorCandidates = [];
|
||||||
ulong maxP = 0UL;
|
ulong maxP = 0UL;
|
||||||
@@ -737,7 +765,19 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_testMode)
|
||||||
|
{
|
||||||
|
_testTargetPrimeCount = Math.Max(1, threadCount) * 3;
|
||||||
|
}
|
||||||
|
|
||||||
_state = ((long)currentP << 3) | (long)remainder;
|
_state = ((long)currentP << 3) | (long)remainder;
|
||||||
|
|
||||||
|
Stopwatch? stopwatch = null;
|
||||||
|
if (_testMode)
|
||||||
|
{
|
||||||
|
stopwatch = Stopwatch.StartNew();
|
||||||
|
}
|
||||||
|
|
||||||
Task[] tasks = new Task[threadCount];
|
Task[] tasks = new Task[threadCount];
|
||||||
|
|
||||||
int taskIndex = 0;
|
int taskIndex = 0;
|
||||||
@@ -807,8 +847,23 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
|
|
||||||
Task.WaitAll(tasks);
|
Task.WaitAll(tasks);
|
||||||
|
|
||||||
|
TimeSpan testElapsed = default;
|
||||||
|
bool reportTestTime = false;
|
||||||
|
if (stopwatch is not null)
|
||||||
|
{
|
||||||
|
stopwatch.Stop();
|
||||||
|
testElapsed = stopwatch.Elapsed;
|
||||||
|
reportTestTime = true;
|
||||||
|
}
|
||||||
|
|
||||||
FlushBuffer();
|
FlushBuffer();
|
||||||
StringBuilderPool.Return(_outputBuilder!);
|
StringBuilderPool.Return(_outputBuilder!);
|
||||||
|
|
||||||
|
if (reportTestTime)
|
||||||
|
{
|
||||||
|
ReportTestTime(testElapsed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<ulong> LoadByDivisorCandidates(string candidateFile, UInt128 maxPrimeLimit, bool maxPrimeConfigured, out int skippedByLimit)
|
private static List<ulong> LoadByDivisorCandidates(string candidateFile, UInt128 maxPrimeLimit, bool maxPrimeConfigured, out int skippedByLimit)
|
||||||
@@ -1053,6 +1108,21 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void OnPrimeCandidateConfirmed()
|
||||||
|
{
|
||||||
|
if (!_testMode)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int processed = Interlocked.Increment(ref _testProcessedPrimeCount);
|
||||||
|
if (processed == _testTargetPrimeCount)
|
||||||
|
{
|
||||||
|
Volatile.Write(ref _limitReached, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static bool TryAcquireConsoleSlot(bool primeCandidate, out bool primeFlag)
|
private static bool TryAcquireConsoleSlot(bool primeCandidate, out bool primeFlag)
|
||||||
{
|
{
|
||||||
@@ -1189,6 +1259,75 @@ internal static class Program
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ReportTestTime(TimeSpan elapsed)
|
||||||
|
{
|
||||||
|
double elapsedSeconds = elapsed.TotalSeconds;
|
||||||
|
double elapsedMilliseconds = elapsed.TotalMilliseconds;
|
||||||
|
Console.WriteLine($"Test elapsed time: {elapsedSeconds:F3} s");
|
||||||
|
|
||||||
|
string filePath = GetTestTimeFilePath();
|
||||||
|
bool hasPrevious = TryReadTestTime(filePath, out double previousMilliseconds);
|
||||||
|
string elapsedText = elapsedMilliseconds.ToString("F3", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
if (!hasPrevious)
|
||||||
|
{
|
||||||
|
WriteTestTime(filePath, elapsedMilliseconds);
|
||||||
|
Console.WriteLine($"FIRST TIME: {elapsedText} ms");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string previousText = previousMilliseconds.ToString("F3", CultureInfo.InvariantCulture);
|
||||||
|
if (elapsedMilliseconds < previousMilliseconds)
|
||||||
|
{
|
||||||
|
WriteTestTime(filePath, elapsedMilliseconds);
|
||||||
|
Console.WriteLine($"BETTER TIME: {elapsedText} ms (previous {previousText} ms)");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"WORSE TIME: {elapsedText} ms (best {previousText} ms)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetTestTimeFilePath()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_resultsDir))
|
||||||
|
{
|
||||||
|
return TestTimeFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Path.Combine(_resultsDir!, TestTimeFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryReadTestTime(string filePath, out double milliseconds)
|
||||||
|
{
|
||||||
|
if (!File.Exists(filePath))
|
||||||
|
{
|
||||||
|
milliseconds = 0.0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string content = File.ReadAllText(filePath).Trim();
|
||||||
|
if (content.Length == 0)
|
||||||
|
{
|
||||||
|
milliseconds = 0.0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return double.TryParse(content, NumberStyles.Float, CultureInfo.InvariantCulture, out milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteTestTime(string filePath, double milliseconds)
|
||||||
|
{
|
||||||
|
string? directory = Path.GetDirectoryName(filePath);
|
||||||
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
string formatted = milliseconds.ToString("F6", CultureInfo.InvariantCulture);
|
||||||
|
File.WriteAllText(filePath, formatted);
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal static ulong CountOnes(ulong value)
|
internal static ulong CountOnes(ulong value)
|
||||||
{
|
{
|
||||||
@@ -1419,6 +1558,8 @@ internal static class Program
|
|||||||
_lastCompositeP = true;
|
_lastCompositeP = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnPrimeCandidateConfirmed();
|
||||||
}
|
}
|
||||||
|
|
||||||
searchedMersenne = true;
|
searchedMersenne = true;
|
||||||
|
|||||||
Reference in new issue
Block a user