GpuContextPool removed, because we share context and accelerator between threads, using streams to separate.
This commit is contained in:
1 parent
7c035239b4
commit
f4e365194d
19 files changed
+285
-425
No files matched your search
@@ -15,126 +15,124 @@ public sealed class MersenneNumberDivisorGpuTester
|
||||
|
||||
private Action<AcceleratorStream, Index1D, ulong, ReadOnlyGpuUInt128, ArrayView<byte>> GetKernel(Accelerator accelerator) =>
|
||||
_kernelCache.GetOrAdd(accelerator, acc =>
|
||||
{
|
||||
var loaded = acc.LoadAutoGroupedStreamKernel<Index1D, ulong, ReadOnlyGpuUInt128, ArrayView<byte>>(DivisorKernels.Kernel);
|
||||
var kernel = KernelUtil.GetKernel(loaded);
|
||||
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ReadOnlyGpuUInt128, ArrayView<byte>>>();
|
||||
});
|
||||
{
|
||||
var loaded = acc.LoadAutoGroupedStreamKernel<Index1D, ulong, ReadOnlyGpuUInt128, ArrayView<byte>>(DivisorKernels.Kernel);
|
||||
var kernel = KernelUtil.GetKernel(loaded);
|
||||
return kernel.CreateLauncherDelegate<Action<AcceleratorStream, Index1D, ulong, ReadOnlyGpuUInt128, ArrayView<byte>>>();
|
||||
});
|
||||
|
||||
public static void BuildDivisorCandidates()
|
||||
{
|
||||
ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
|
||||
(ulong divisor, uint cycle)[] list = new (ulong divisor, uint cycle)[snapshot.Length / 2];
|
||||
ulong cycle;
|
||||
int count = 0, i, snapshotLength = snapshot.Length;
|
||||
for (i = 3; i < snapshotLength; i += 2)
|
||||
{
|
||||
cycle = snapshot[i];
|
||||
if (cycle == 0U)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
public static void BuildDivisorCandidates()
|
||||
{
|
||||
ulong[] snapshot = MersenneDivisorCycles.Shared.ExportSmallCyclesSnapshot();
|
||||
(ulong divisor, uint cycle)[] list = new (ulong divisor, uint cycle)[snapshot.Length / 2];
|
||||
ulong cycle;
|
||||
int count = 0, i, snapshotLength = snapshot.Length;
|
||||
for (i = 3; i < snapshotLength; i += 2)
|
||||
{
|
||||
cycle = snapshot[i];
|
||||
if (cycle == 0U)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
list[count++] = ((ulong)i, (uint)cycle);
|
||||
}
|
||||
list[count++] = ((ulong)i, (uint)cycle);
|
||||
}
|
||||
|
||||
_divisorCandidates = count == 0 ? [] : list[..count];
|
||||
}
|
||||
_divisorCandidates = count == 0 ? [] : list[..count];
|
||||
}
|
||||
|
||||
public bool IsDivisible(ulong exponent, in ReadOnlyGpuUInt128 divisor)
|
||||
{
|
||||
var gpu = GpuContextPool.Rent();
|
||||
var accelerator = gpu.Accelerator;
|
||||
public bool IsDivisible(ulong exponent, in ReadOnlyGpuUInt128 divisor)
|
||||
{
|
||||
var accelerator = SharedGpuContext.Accelerator;
|
||||
var stream = accelerator.CreateStream();
|
||||
var kernel = GetKernel(accelerator);
|
||||
var resultBuffer = _resultBuffers.GetOrAdd(accelerator, acc => acc.Allocate1D<byte>(1));
|
||||
var kernel = GetKernel(accelerator);
|
||||
var resultBuffer = _resultBuffers.GetOrAdd(accelerator, acc => acc.Allocate1D<byte>(1));
|
||||
// There is no point in clearing this buffer. We always override item [0] and never use it beyond item [0]
|
||||
// resultBuffer.MemSetToZero(stream);
|
||||
kernel(stream, 1, exponent, divisor, resultBuffer.View);
|
||||
Span<byte> result = stackalloc byte[1];
|
||||
resultBuffer.View.CopyToCPU(stream, ref result[0], 1);
|
||||
stream.Synchronize();
|
||||
bool divisible = result[0] != 0;
|
||||
// resultBuffer.MemSetToZero(stream);
|
||||
kernel(stream, 1, exponent, divisor, resultBuffer.View);
|
||||
Span<byte> result = stackalloc byte[1];
|
||||
resultBuffer.View.CopyToCPU(stream, ref result[0], 1);
|
||||
stream.Synchronize();
|
||||
bool divisible = result[0] != 0;
|
||||
stream.Dispose();
|
||||
gpu.Dispose();
|
||||
return divisible;
|
||||
}
|
||||
return divisible;
|
||||
}
|
||||
|
||||
private static (ulong divisor, uint cycle)[]? _divisorCandidates = Array.Empty<(ulong divisor, uint cycle)>();
|
||||
private static (ulong divisor, uint cycle)[]? _divisorCandidates = [];
|
||||
|
||||
public bool IsPrime(ulong p, UInt128 d, ulong divisorCyclesSearchLimit, out bool divisorsExhausted)
|
||||
{
|
||||
ReadOnlyGpuUInt128 readOnlyDivisor;
|
||||
public bool IsPrime(ulong p, UInt128 d, ulong divisorCyclesSearchLimit, out bool divisorsExhausted)
|
||||
{
|
||||
ReadOnlyGpuUInt128 readOnlyDivisor;
|
||||
|
||||
if (d != UInt128.Zero)
|
||||
{
|
||||
readOnlyDivisor = new ReadOnlyGpuUInt128(d);
|
||||
if (IsDivisible(p, in readOnlyDivisor))
|
||||
{
|
||||
divisorsExhausted = true;
|
||||
return false;
|
||||
}
|
||||
if (d != UInt128.Zero)
|
||||
{
|
||||
readOnlyDivisor = new ReadOnlyGpuUInt128(d);
|
||||
if (IsDivisible(p, in readOnlyDivisor))
|
||||
{
|
||||
divisorsExhausted = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
divisorsExhausted = false;
|
||||
return true;
|
||||
}
|
||||
divisorsExhausted = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_divisorCandidates is { Length: > 0 } candidates)
|
||||
{
|
||||
int candidateCount = candidates.Length;
|
||||
for (int index = 0; index < candidateCount; index++)
|
||||
{
|
||||
(ulong candidateDivisor, uint cycle) = candidates[index];
|
||||
if (p % cycle != 0UL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (_divisorCandidates is { Length: > 0 } candidates)
|
||||
{
|
||||
int candidateCount = candidates.Length;
|
||||
for (int index = 0; index < candidateCount; index++)
|
||||
{
|
||||
(ulong candidateDivisor, uint cycle) = candidates[index];
|
||||
if (p % cycle != 0UL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
readOnlyDivisor = new ReadOnlyGpuUInt128(candidateDivisor); // Reusing readOnlyDivisor for candidate divisors.
|
||||
if (IsDivisible(p, in readOnlyDivisor))
|
||||
{
|
||||
divisorsExhausted = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
readOnlyDivisor = new ReadOnlyGpuUInt128(candidateDivisor); // Reusing readOnlyDivisor for candidate divisors.
|
||||
if (IsDivisible(p, in readOnlyDivisor))
|
||||
{
|
||||
divisorsExhausted = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt128 kMul2;
|
||||
var divisorCycles = MersenneDivisorCycles.Shared;
|
||||
UInt128 maxK2 = UInt128.MaxValue / ((UInt128)p << 1);
|
||||
ulong limit = divisorCyclesSearchLimit;
|
||||
if ((UInt128)limit > maxK2)
|
||||
{
|
||||
limit = (ulong)maxK2;
|
||||
}
|
||||
UInt128 kMul2;
|
||||
var divisorCycles = MersenneDivisorCycles.Shared;
|
||||
UInt128 maxK2 = UInt128.MaxValue / ((UInt128)p << 1);
|
||||
ulong limit = divisorCyclesSearchLimit;
|
||||
if ((UInt128)limit > maxK2)
|
||||
{
|
||||
limit = (ulong)maxK2;
|
||||
}
|
||||
|
||||
for (ulong k2 = 1UL; k2 <= limit; k2++)
|
||||
{
|
||||
kMul2 = (UInt128)k2 << 1;
|
||||
UInt128 candidate = checked(kMul2 * p);
|
||||
d = checked(candidate + UInt128.One);
|
||||
if (p < 64UL && d == ((UInt128)1 << (int)p) - UInt128.One)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (ulong k2 = 1UL; k2 <= limit; k2++)
|
||||
{
|
||||
kMul2 = (UInt128)k2 << 1;
|
||||
UInt128 candidate = checked(kMul2 * p);
|
||||
d = checked(candidate + UInt128.One);
|
||||
if (p < 64UL && d == ((UInt128)1 << (int)p) - UInt128.One)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UInt128 cycle128 = MersenneDivisorCycles.GetCycle(d);
|
||||
if ((UInt128)p % cycle128 != UInt128.Zero)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
UInt128 cycle128 = MersenneDivisorCycles.GetCycle(d);
|
||||
if ((UInt128)p % cycle128 != UInt128.Zero)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
readOnlyDivisor = new ReadOnlyGpuUInt128(d); // Reusing readOnlyDivisor for generated divisors.
|
||||
if (IsDivisible(p, in readOnlyDivisor))
|
||||
{
|
||||
divisorsExhausted = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
readOnlyDivisor = new ReadOnlyGpuUInt128(d); // Reusing readOnlyDivisor for generated divisors.
|
||||
if (IsDivisible(p, in readOnlyDivisor))
|
||||
{
|
||||
divisorsExhausted = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
divisorsExhausted = (UInt128)divisorCyclesSearchLimit >= maxK2;
|
||||
return true;
|
||||
}
|
||||
divisorsExhausted = (UInt128)divisorCyclesSearchLimit >= maxK2;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user