Minimize PrintResult critical section

This commit is contained in:
Marek Lemańczyk committed 2025-09-22 20:16:10 +02:00
1 parent 9a4162d33e
commit abe160c53e
1 file changed
+121 -67
+121 -67
View File
@@ -22,7 +22,8 @@ internal static class Program
private static string ResultsFileName = "even_perfect_bit_scan_results.csv"; private static string ResultsFileName = "even_perfect_bit_scan_results.csv";
private const string PrimeFoundSuffix = " (FOUND VALID CANDIDATES)"; private const string PrimeFoundSuffix = " (FOUND VALID CANDIDATES)";
private static StringBuilder? _outputBuilder; private static StringBuilder? _outputBuilder;
private static readonly object Sync = new(); private static readonly object Sync = new();
private static readonly object FileWriteSync = new();
private static int _consoleCounter; private static int _consoleCounter;
private static int _writeIndex; private static int _writeIndex;
private static int _primeCount; private static int _primeCount;
@@ -1349,84 +1350,137 @@ internal static class Program
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool passedAllTests) private static bool TryAcquireConsoleSlot(bool primeCandidate, out bool primeFlag)
{ {
if (passedAllTests) int consoleInterval = PerfectNumberConstants.ConsoleInterval;
{ int counterValue = Interlocked.Increment(ref _consoleCounter);
int newCount = Interlocked.Increment(ref _primeCount); if (counterValue >= consoleInterval)
if (newCount >= 2) {
{ int previous = Interlocked.Exchange(ref _consoleCounter, 0);
Volatile.Write(ref _primeFoundAfterInit, true); if (previous >= consoleInterval)
} {
} primeFlag = primeCandidate;
return true;
}
}
bool lastWasComposite = _lastCompositeP; primeFlag = false;
bool primeFlag = false, printToConsole = false; return false;
}
StringBuilder localBuilder = StringBuilderPool.Rent(); [MethodImpl(MethodImplOptions.AggressiveInlining)]
_ = localBuilder private static StringBuilder? AppendToOutputBuffer(StringBuilder source)
.Append(currentP).Append(',') {
.Append(searchedMersenne).Append(',') StringBuilder? builderToFlush = null;
.Append(detailedCheck).Append(',')
.Append(passedAllTests).Append('\n');
lock (Sync) lock (Sync)
{ {
if (_consoleCounter >= PerfectNumberConstants.ConsoleInterval) StringBuilder outputBuilder = _outputBuilder!;
{ _ = outputBuilder.Append(source);
printToConsole = true;
primeFlag = passedAllTests && !lastWasComposite && _primeFoundAfterInit;
_consoleCounter = 0;
}
else
{
_consoleCounter++;
}
_ = _outputBuilder!.Append(localBuilder); int nextIndex = _writeIndex + 1;
if (nextIndex >= _writeBatchSize)
{
builderToFlush = outputBuilder;
_outputBuilder = StringBuilderPool.Rent();
_writeIndex = 0;
}
else
{
_writeIndex = nextIndex;
}
}
_writeIndex++; return builderToFlush;
if (_writeIndex >= _writeBatchSize) }
{
FlushBuffer();
}
}
if (printToConsole) [MethodImpl(MethodImplOptions.AggressiveInlining)]
{ private static void PrintResult(ulong currentP, bool searchedMersenne, bool detailedCheck, bool passedAllTests)
if (primeFlag) {
{ if (passedAllTests)
_ = localBuilder {
.Remove(localBuilder.Length - 1, 1) int newCount = Interlocked.Increment(ref _primeCount);
.Append(PrimeFoundSuffix) if (newCount >= 2)
.Append('\n'); {
} Volatile.Write(ref _primeFoundAfterInit, true);
}
}
Console.WriteLine(localBuilder.Remove(localBuilder.Length - 1, 1).ToString()); bool lastWasComposite = _lastCompositeP;
} bool primeCandidate = passedAllTests && !lastWasComposite && Volatile.Read(ref _primeFoundAfterInit);
localBuilder.Clear(); StringBuilder localBuilder = StringBuilderPool.Rent();
StringBuilderPool.Return(localBuilder); _ = localBuilder
} .Append(currentP).Append(',')
.Append(searchedMersenne).Append(',')
.Append(detailedCheck).Append(',')
.Append(passedAllTests).Append('\n');
bool printToConsole = TryAcquireConsoleSlot(primeCandidate, out bool primeFlag);
StringBuilder? builderToFlush = AppendToOutputBuffer(localBuilder);
if (builderToFlush is not null)
{
FlushBuffer(builderToFlush);
}
if (printToConsole)
{
if (primeFlag)
{
_ = localBuilder
.Remove(localBuilder.Length - 1, 1)
.Append(PrimeFoundSuffix)
.Append('\n');
}
Console.WriteLine(localBuilder.Remove(localBuilder.Length - 1, 1).ToString());
}
localBuilder.Clear();
StringBuilderPool.Return(localBuilder);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void FlushBuffer() private static void FlushBuffer()
{ {
var stream = new FileStream(ResultsFileName, FileMode.Append, FileAccess.Write, FileShare.Read); StringBuilder? builderToFlush = null;
var writer = new StreamWriter(stream) { AutoFlush = false };
if (_writeIndex > 0) lock (Sync)
{ {
writer.Write(_outputBuilder); if (_writeIndex == 0 || _outputBuilder is null || _outputBuilder.Length == 0)
writer.Flush(); {
_outputBuilder!.Clear(); return;
_writeIndex = 0; }
}
writer.Dispose(); builderToFlush = _outputBuilder;
stream.Dispose(); _outputBuilder = StringBuilderPool.Rent();
} _writeIndex = 0;
}
FlushBuffer(builderToFlush!);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void FlushBuffer(StringBuilder builderToFlush)
{
try
{
lock (FileWriteSync)
{
using FileStream stream = new(ResultsFileName, FileMode.Append, FileAccess.Write, FileShare.Read);
using StreamWriter writer = new(stream) { AutoFlush = false };
writer.Write(builderToFlush);
writer.Flush();
}
}
finally
{
builderToFlush.Clear();
StringBuilderPool.Return(builderToFlush);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong CountOnes(ulong value) internal static ulong CountOnes(ulong value)