Optimizations. Unnecessary variables removed.

This commit is contained in:
Marek Lemańczyk committed 2025-09-24 01:41:54 +02:00
1 parent 15bc2686cc
commit 01bb731220
1 file changed
+140 -149
@@ -98,6 +98,7 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
private bool CheckDivisors(ulong prime, ulong allowedMax, out ulong lastProcessed, out bool coveredRange) private bool CheckDivisors(ulong prime, ulong allowedMax, out ulong lastProcessed, out bool coveredRange)
{ {
// TODO: We should be able to calculate allowedMax outside in the parent method, unless it depends from some changing value.
allowedMax = Math.Min(allowedMax, _divisorLimit); allowedMax = Math.Min(allowedMax, _divisorLimit);
lastProcessed = 0UL; lastProcessed = 0UL;
@@ -107,126 +108,126 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
return false; return false;
} }
// TODO: Rent these in the parent method before the loops - batch size doesn't change
var gpuLease = GpuContextPool.RentPreferred(preferCpu: false); var gpuLease = GpuContextPool.RentPreferred(preferCpu: false);
var accelerator = gpuLease.Accelerator; var accelerator = gpuLease.Accelerator;
var kernel = GetKernel(accelerator); var kernel = GetKernel(accelerator);
int batchCapacity = _gpuBatchSize; int batchCapacity = _gpuBatchSize;
// TODO: Rent buffers in the parent method before the loops - batch size doesn't change
var divisorsBuffer = accelerator.Allocate1D<MontgomeryDivisorData>(batchCapacity); var divisorsBuffer = accelerator.Allocate1D<MontgomeryDivisorData>(batchCapacity);
var hitsBuffer = accelerator.Allocate1D<byte>(batchCapacity); var hitsBuffer = accelerator.Allocate1D<byte>(batchCapacity);
ulong[] divisors = ArrayPool<ulong>.Shared.Rent(batchCapacity); ulong[] divisors = ArrayPool<ulong>.Shared.Rent(batchCapacity);
byte[] hits = ArrayPool<byte>.Shared.Rent(batchCapacity); byte[] hits = ArrayPool<byte>.Shared.Rent(batchCapacity);
MontgomeryDivisorData[] divisorData = ArrayPool<MontgomeryDivisorData>.Shared.Rent(batchCapacity); MontgomeryDivisorData[] divisorData = ArrayPool<MontgomeryDivisorData>.Shared.Rent(batchCapacity);
bool composite = false; bool composite = false;
bool processedAll = false; bool processedAll = false;
ulong divisor = 3UL; ulong cycle, divisor = 3UL, next;
int batchSize, i;
bool reachedEndInBatch, useCycles = _useDivisorCycles;
try Span<MontgomeryDivisorData> divisorDataSpan;
Span<ulong> divisorSpan;
Span<byte> hitsSpan;
MersenneDivisorCycles divisorCycles = MersenneDivisorCycles.Shared;
ArrayView1D<MontgomeryDivisorData, Stride1D.Dense> divisorView;
ArrayView1D<byte, Stride1D.Dense> hitsView;
while (divisor <= allowedMax)
{ {
bool useCycles = _useDivisorCycles; batchSize = 0;
MersenneDivisorCycles? divisorCycles = useCycles ? MersenneDivisorCycles.Shared : null; reachedEndInBatch = false;
while (divisor <= allowedMax)
while (batchSize < batchCapacity && divisor <= allowedMax)
{ {
int batchSize = 0; if (useCycles)
bool reachedEndInBatch = false;
while (batchSize < batchCapacity && divisor <= allowedMax)
{ {
ulong current = divisor; cycle = divisorCycles!.GetCycle(divisor);
ulong next = current + 2UL; if (cycle == 0UL || prime % cycle != 0UL)
bool include = true;
if (useCycles)
{ {
ulong cycle = divisorCycles!.GetCycle(current); ReportStatus(divisor);
if (cycle == 0UL || prime % cycle != 0UL)
{
include = false;
lastProcessed = current;
ReportStatus(lastProcessed);
}
} }
else
if (include)
{ {
divisors[batchSize++] = current; divisors[batchSize++] = divisor;
} }
}
else
{
divisors[batchSize++] = divisor;
}
if (next <= current) next = divisor + 2UL;
{ if (next <= divisor)
reachedEndInBatch = true; {
break; reachedEndInBatch = true;
} break;
}
if (next > allowedMax)
{
divisor = next;
reachedEndInBatch = true;
break;
}
if (next > allowedMax)
{
divisor = next; divisor = next;
} reachedEndInBatch = true;
if (batchSize == 0)
{
break; break;
} }
Span<MontgomeryDivisorData> divisorDataSpan = divisorData.AsSpan(0, batchSize); divisor = next;
var divisorView = divisorsBuffer.View.SubView(0, batchSize); }
var hitsView = hitsBuffer.View.SubView(0, batchSize);
Span<ulong> divisorSpan = divisors.AsSpan(0, batchSize); if (batchSize == 0)
Span<byte> hitsSpan = hits.AsSpan(0, batchSize); {
break;
}
for (int i = 0; i < batchSize; i++) divisorDataSpan = divisorData.AsSpan(0, batchSize);
divisorView = divisorsBuffer.View.SubView(0, batchSize);
hitsView = hitsBuffer.View.SubView(0, batchSize);
divisorSpan = divisors.AsSpan(0, batchSize);
hitsSpan = hits.AsSpan(0, batchSize);
for (i = 0; i < batchSize; i++)
{
divisorDataSpan[i] = CreateMontgomeryDivisorData(divisorSpan[i]);
}
divisorView.CopyFromCPU(ref MemoryMarshal.GetReference(divisorDataSpan), batchSize);
kernel(batchSize, prime, divisorView, hitsView);
accelerator.Synchronize();
hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitsSpan), batchSize);
for (i = 0; i < batchSize; i++)
{
if (hitsSpan[i] != 0)
{ {
divisorDataSpan[i] = CreateMontgomeryDivisorData(divisorSpan[i]); composite = true;
}
divisorView.CopyFromCPU(ref MemoryMarshal.GetReference(divisorDataSpan), batchSize);
kernel(batchSize, prime, divisorView, hitsView);
accelerator.Synchronize();
hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitsSpan), batchSize);
for (int i = 0; i < batchSize; i++)
{
lastProcessed = divisorSpan[i];
if (hitsSpan[i] != 0)
{
composite = true;
break;
}
}
ReportStatus(lastProcessed);
if (composite)
{
break;
}
if (reachedEndInBatch)
{
processedAll = true;
break; break;
} }
} }
coveredRange = composite || processedAll || divisor > allowedMax; ReportStatus(divisorSpan[i < batchSize ? i : i - 1]);
} if (composite)
finally {
{ break;
ArrayPool<byte>.Shared.Return(hits, clearArray: true); }
ArrayPool<ulong>.Shared.Return(divisors, clearArray: true);
ArrayPool<MontgomeryDivisorData>.Shared.Return(divisorData, clearArray: true); if (reachedEndInBatch)
hitsBuffer.Dispose(); {
divisorsBuffer.Dispose(); processedAll = true;
gpuLease.Dispose(); break;
}
} }
coveredRange = composite || processedAll || divisor > allowedMax;
ArrayPool<byte>.Shared.Return(hits, clearArray: true);
ArrayPool<ulong>.Shared.Return(divisors, clearArray: true);
ArrayPool<MontgomeryDivisorData>.Shared.Return(divisorData, clearArray: true);
hitsBuffer.Dispose();
divisorsBuffer.Dispose();
gpuLease.Dispose();
return composite; return composite;
} }
@@ -317,7 +318,6 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
} }
int offset = 0; int offset = 0;
int consoleStatus = 0;
MersenneNumberDivisorByDivisorGpuTester owner = _owner; MersenneNumberDivisorByDivisorGpuTester owner = _owner;
int gpuBatchSize = owner._gpuBatchSize; int gpuBatchSize = owner._gpuBatchSize;
bool useCycles = owner._useDivisorCycles; bool useCycles = owner._useDivisorCycles;
@@ -335,83 +335,74 @@ public sealed class MersenneNumberDivisorByDivisorGpuTester
MersenneDivisorCycles? divisorCycles = useCycles ? MersenneDivisorCycles.Shared : null; MersenneDivisorCycles? divisorCycles = useCycles ? MersenneDivisorCycles.Shared : null;
ulong cycle = useCycles ? divisorCycles!.GetCycle(divisor) : 0UL, primeValue; ulong cycle = useCycles ? divisorCycles!.GetCycle(divisor) : 0UL, primeValue;
MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor); MontgomeryDivisorData divisorData = CreateMontgomeryDivisorData(divisor);
Span<ulong> primeSpan = Span<ulong>.Empty; Span<ulong> primeSpan = [];
Span<int> indexSpan = Span<int>.Empty; ReadOnlySpan<ulong> primesSlice;
Span<byte> hitSpan = Span<byte>.Empty; Span<int> indexSpan = [];
Span<byte> hitsSlice; Span<byte> hitSpan = [];
int batchSize, currentSpanSize = -1, gpuCount, i, primesLength = primes.Length; Span<byte> hitsSlice;
int batchSize, currentSpanSize = -1, gpuCount, i, primesLength = primes.Length;
while (offset < primesLength) while (offset < primesLength)
{ {
batchSize = Math.Min(gpuBatchSize, primesLength - offset); batchSize = Math.Min(gpuBatchSize, primesLength - offset);
ReadOnlySpan<ulong> primesSlice = primes.Slice(offset, batchSize); primesSlice = primes.Slice(offset, batchSize);
hitsSlice = hits.Slice(offset, batchSize);
if (++consoleStatus == PerfectNumberConstants.ConsoleInterval) if (useCycles)
{ {
Console.WriteLine($"...processed by-divisor candidate = {primesSlice[0]}"); if (batchSize != currentSpanSize)
consoleStatus = 0; {
} primeSpan = primesHost.AsSpan(0, batchSize);
indexSpan = indexHost.AsSpan(0, batchSize);
hitSpan = hitsHost.AsSpan(0, batchSize);
currentSpanSize = batchSize;
}
hitsSlice = hits.Slice(offset, batchSize); gpuCount = 0;
if (useCycles) for (i = 0; i < batchSize; i++)
{ {
if (batchSize != currentSpanSize) primeValue = primesSlice[i];
{ if (cycle == 0UL || primeValue % cycle != 0UL)
primeSpan = primesHost.AsSpan(0, batchSize); {
indexSpan = indexHost.AsSpan(0, batchSize); hitsSlice[i] = 0;
hitSpan = hitsHost.AsSpan(0, batchSize); continue;
currentSpanSize = batchSize; }
}
ref ulong primesSpanRef = ref MemoryMarshal.GetReference(primeSpan); indexSpan[gpuCount] = i;
ref byte hitSpanRef = ref MemoryMarshal.GetReference(hitSpan); primeSpan[gpuCount] = primeValue;
gpuCount = 0; gpuCount++;
}
for (i = 0; i < batchSize; i++) if (gpuCount > 0)
{ {
primeValue = primesSlice[i]; primesView = primesBufferView.SubView(0, gpuCount);
if (cycle == 0UL || primeValue % cycle != 0UL) hitsView = hitsBufferView.SubView(0, gpuCount);
{
hitsSlice[i] = 0;
continue;
}
indexSpan[gpuCount] = i; primesView.CopyFromCPU(ref MemoryMarshal.GetReference(primeSpan), gpuCount);
primeSpan[gpuCount] = primeValue; kernel(gpuCount, divisorData, primesView, hitsView);
gpuCount++; accelerator.Synchronize();
}
if (gpuCount > 0) hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitSpan), gpuCount);
{ for (i = 0; i < gpuCount; i++)
primesView = primesBufferView.SubView(0, gpuCount); {
hitsView = hitsBufferView.SubView(0, gpuCount); hitsSlice[indexSpan[i]] = hitSpan[i];
}
}
}
else
{
primesView = primesBufferView.SubView(0, batchSize);
hitsView = hitsBufferView.SubView(0, batchSize);
primesView.CopyFromCPU(ref primesSpanRef, gpuCount); primesView.CopyFromCPU(ref MemoryMarshal.GetReference(primesSlice), batchSize);
kernel(gpuCount, divisorData, primesView, hitsView); kernel(batchSize, divisorData, primesView, hitsView);
accelerator.Synchronize(); accelerator.Synchronize();
hitsView.CopyToCPU(ref hitSpanRef, gpuCount); hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitsSlice), batchSize);
for (i = 0; i < gpuCount; i++) }
{
hitsSlice[indexSpan[i]] = hitSpan[i];
}
}
}
else
{
primesView = primesBufferView.SubView(0, batchSize);
hitsView = hitsBufferView.SubView(0, batchSize);
ref ulong primesSliceRef = ref MemoryMarshal.GetReference(primesSlice); offset += batchSize;
primesView.CopyFromCPU(ref primesSliceRef, batchSize);
kernel(batchSize, divisorData, primesView, hitsView);
accelerator.Synchronize();
hitsView.CopyToCPU(ref MemoryMarshal.GetReference(hitsSlice), batchSize);
}
offset += batchSize;
} }
} }