Merge pull request #89 from mlemanczyk/codex/optimize-buildprimebuffer-method
Reduce synchronization when building divisor prime buffer
This commit is contained in:
1 file changed
+74
-59
@@ -1122,49 +1122,60 @@ internal static class Program
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int BuildPrimeBuffer(ulong divisor, in ulong[] primeValues, in ulong[] allowedMaxValues, int[] stateFlags, ulong[] primeBuffer, int[] indexBuffer, PendingResult[] completionsBuffer, ref int completionsCount, ref int remainingStates, long[] activeStateMask, ref int activeStartIndex)
|
private static int BuildPrimeBuffer(ulong divisor, in ulong[] primeValues, in ulong[] allowedMaxValues, int[] stateFlags, ulong[] primeBuffer, int[] indexBuffer, PendingResult[] completionsBuffer, ref int completionsCount, ref int remainingStates, long[] activeStateMask, ref int activeStartIndex)
|
||||||
{
|
{
|
||||||
int length = primeValues.Length;
|
int length = primeValues.Length;
|
||||||
int startIndex = Volatile.Read(ref activeStartIndex);
|
int startIndex;
|
||||||
int index = startIndex;
|
while (true)
|
||||||
|
{
|
||||||
|
startIndex = Volatile.Read(ref activeStartIndex);
|
||||||
|
if (startIndex >= length || allowedMaxValues[startIndex] >= divisor)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
while (index < length && allowedMaxValues[index] < divisor)
|
// Claim the prefix slot before finalizing to avoid double-counting the same candidate.
|
||||||
{
|
if (Interlocked.CompareExchange(ref activeStartIndex, startIndex + 1, startIndex) != startIndex)
|
||||||
if (Interlocked.CompareExchange(ref stateFlags[index], ByDivisorStateCompletedDetailed, ByDivisorStateActive) == ByDivisorStateActive)
|
{
|
||||||
{
|
continue;
|
||||||
ClearActiveMask(activeStateMask, index);
|
}
|
||||||
Interlocked.Decrement(ref remainingStates);
|
|
||||||
if (completionsCount == completionsBuffer.Length)
|
|
||||||
{
|
|
||||||
FlushPendingResults(completionsBuffer, ref completionsCount);
|
|
||||||
}
|
|
||||||
completionsBuffer[completionsCount++] = new PendingResult(primeValues[index], detailedCheck: true, passedAllTests: true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ClearActiveMask(activeStateMask, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
int state = Volatile.Read(ref stateFlags[startIndex]);
|
||||||
}
|
if (state == ByDivisorStateActive)
|
||||||
|
{
|
||||||
|
Volatile.Write(ref stateFlags[startIndex], ByDivisorStateCompletedDetailed);
|
||||||
|
ClearActiveMask(activeStateMask, startIndex);
|
||||||
|
Interlocked.Decrement(ref remainingStates);
|
||||||
|
if (completionsCount == completionsBuffer.Length)
|
||||||
|
{
|
||||||
|
FlushPendingResults(completionsBuffer, ref completionsCount);
|
||||||
|
}
|
||||||
|
completionsBuffer[completionsCount++] = new PendingResult(primeValues[startIndex], detailedCheck: true, passedAllTests: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ClearActiveMask(activeStateMask, startIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (index != startIndex)
|
int index = startIndex;
|
||||||
{
|
int activeCount = 0;
|
||||||
Volatile.Write(ref activeStartIndex, index);
|
while (index < length)
|
||||||
}
|
{
|
||||||
|
int wordIndex = index >> 6;
|
||||||
int activeCount = 0;
|
ulong word = unchecked((ulong)activeStateMask[wordIndex]);
|
||||||
while (index < length)
|
if (word == 0UL)
|
||||||
{
|
{
|
||||||
int wordIndex = index >> 6;
|
// Fallback to a volatile read only when the optimistic read reports no work to
|
||||||
ulong word = unchecked((ulong)Volatile.Read(ref activeStateMask[wordIndex]));
|
// minimize the number of costly fences on the hot path.
|
||||||
if (word == 0UL)
|
word = unchecked((ulong)Volatile.Read(ref activeStateMask[wordIndex]));
|
||||||
{
|
if (word == 0UL)
|
||||||
index = (wordIndex + 1) << 6;
|
{
|
||||||
continue;
|
index = (wordIndex + 1) << 6;
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
int bitOffset = index & 63;
|
}
|
||||||
|
int bitOffset = index & 63;
|
||||||
if (bitOffset != 0)
|
if (bitOffset != 0)
|
||||||
{
|
{
|
||||||
word &= ulong.MaxValue << bitOffset;
|
word &= ulong.MaxValue << bitOffset;
|
||||||
@@ -1183,16 +1194,19 @@ internal static class Program
|
|||||||
return activeCount;
|
return activeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Volatile.Read(ref stateFlags[candidateIndex]) == ByDivisorStateActive)
|
// Intentionally avoid Volatile.Read here; seeing a stale Active value only causes
|
||||||
{
|
// redundant work, while seeing a stale non-active value would require the mask bit
|
||||||
primeBuffer[activeCount] = primeValues[candidateIndex];
|
// to be set, which means another worker has not finished clearing it yet.
|
||||||
indexBuffer[activeCount] = candidateIndex;
|
if (stateFlags[candidateIndex] == ByDivisorStateActive)
|
||||||
activeCount++;
|
{
|
||||||
}
|
primeBuffer[activeCount] = primeValues[candidateIndex];
|
||||||
else
|
indexBuffer[activeCount] = candidateIndex;
|
||||||
{
|
activeCount++;
|
||||||
ClearActiveMask(activeStateMask, candidateIndex);
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
ClearActiveMask(activeStateMask, candidateIndex);
|
||||||
|
}
|
||||||
|
|
||||||
word &= word - 1UL;
|
word &= word - 1UL;
|
||||||
}
|
}
|
||||||
@@ -1209,17 +1223,18 @@ internal static class Program
|
|||||||
bool detailed = false;
|
bool detailed = false;
|
||||||
for (; finalizeIndex < primeValues.Length; finalizeIndex++)
|
for (; finalizeIndex < primeValues.Length; finalizeIndex++)
|
||||||
{
|
{
|
||||||
if (Volatile.Read(ref stateFlags[finalizeIndex]) != ByDivisorStateActive)
|
if (stateFlags[finalizeIndex] != ByDivisorStateActive)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
detailed = unchecked((ulong)Volatile.Read(ref finalDivisorBits)) > allowedMaxValues[finalizeIndex];
|
ulong finalDivisor = unchecked((ulong)Volatile.Read(ref finalDivisorBits));
|
||||||
|
detailed = finalDivisor > allowedMaxValues[finalizeIndex];
|
||||||
|
|
||||||
if (Interlocked.CompareExchange(ref stateFlags[finalizeIndex], detailed ? ByDivisorStateCompletedDetailed : ByDivisorStateCompleted, ByDivisorStateActive) != ByDivisorStateActive)
|
if (Interlocked.CompareExchange(ref stateFlags[finalizeIndex], detailed ? ByDivisorStateCompletedDetailed : ByDivisorStateCompleted, ByDivisorStateActive) != ByDivisorStateActive)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearActiveMask(activeStateMask, finalizeIndex);
|
ClearActiveMask(activeStateMask, finalizeIndex);
|
||||||
Interlocked.Decrement(ref remainingStates);
|
Interlocked.Decrement(ref remainingStates);
|
||||||
|
|||||||
Reference in new issue
Block a user