Reuse GPU context for nested partial factoring

This commit is contained in:
Marek Lemańczyk committed 2025-10-26 20:58:21 +01:00
1 parent 6458f6740d
commit ba439f0f0f
4 files changed
+236 -112

No files matched your search

+14 -2
View File
@@ -46,6 +46,7 @@ public sealed class KernelContainer
public MemoryBuffer1D<int, Stride1D.Dense>? SmallPrimeFactorExponentSlots; public MemoryBuffer1D<int, Stride1D.Dense>? SmallPrimeFactorExponentSlots;
public MemoryBuffer1D<int, Stride1D.Dense>? SmallPrimeFactorCountSlot; public MemoryBuffer1D<int, Stride1D.Dense>? SmallPrimeFactorCountSlot;
public MemoryBuffer1D<ulong, Stride1D.Dense>? SmallPrimeFactorRemainingSlot; public MemoryBuffer1D<ulong, Stride1D.Dense>? SmallPrimeFactorRemainingSlot;
public MemoryBuffer1D<byte, Stride1D.Dense>? SmallPrimeFactorFullyFactoredSlot;
public MemoryBuffer1D<uint, Stride1D.Dense>? SmallPrimesLastOne; public MemoryBuffer1D<uint, Stride1D.Dense>? SmallPrimesLastOne;
public MemoryBuffer1D<ulong, Stride1D.Dense>? SmallPrimesPow2LastOne; public MemoryBuffer1D<ulong, Stride1D.Dense>? SmallPrimesPow2LastOne;
public MemoryBuffer1D<uint, Stride1D.Dense>? SmallPrimesLastSeven; public MemoryBuffer1D<uint, Stride1D.Dense>? SmallPrimesLastSeven;
@@ -107,17 +108,20 @@ public readonly struct SmallPrimeFactorScratch
public readonly MemoryBuffer1D<int, Stride1D.Dense> ExponentSlots; public readonly MemoryBuffer1D<int, Stride1D.Dense> ExponentSlots;
public readonly MemoryBuffer1D<int, Stride1D.Dense> CountSlot; public readonly MemoryBuffer1D<int, Stride1D.Dense> CountSlot;
public readonly MemoryBuffer1D<ulong, Stride1D.Dense> RemainingSlot; public readonly MemoryBuffer1D<ulong, Stride1D.Dense> RemainingSlot;
public readonly MemoryBuffer1D<byte, Stride1D.Dense> FullyFactoredSlot;
public SmallPrimeFactorScratch( public SmallPrimeFactorScratch(
MemoryBuffer1D<ulong, Stride1D.Dense> primeSlots, MemoryBuffer1D<ulong, Stride1D.Dense> primeSlots,
MemoryBuffer1D<int, Stride1D.Dense> exponentSlots, MemoryBuffer1D<int, Stride1D.Dense> exponentSlots,
MemoryBuffer1D<int, Stride1D.Dense> countSlot, MemoryBuffer1D<int, Stride1D.Dense> countSlot,
MemoryBuffer1D<ulong, Stride1D.Dense> remainingSlot) MemoryBuffer1D<ulong, Stride1D.Dense> remainingSlot,
MemoryBuffer1D<byte, Stride1D.Dense> fullyFactoredSlot)
{ {
PrimeSlots = primeSlots; PrimeSlots = primeSlots;
ExponentSlots = exponentSlots; ExponentSlots = exponentSlots;
CountSlot = countSlot; CountSlot = countSlot;
RemainingSlot = remainingSlot; RemainingSlot = remainingSlot;
FullyFactoredSlot = fullyFactoredSlot;
} }
public void Clear() public void Clear()
@@ -126,6 +130,7 @@ public readonly struct SmallPrimeFactorScratch
ExponentSlots.MemSetToZero(); ExponentSlots.MemSetToZero();
CountSlot.MemSetToZero(); CountSlot.MemSetToZero();
RemainingSlot.MemSetToZero(); RemainingSlot.MemSetToZero();
FullyFactoredSlot.MemSetToZero();
} }
} }
@@ -273,7 +278,14 @@ public class GpuKernelPool
kernels.SmallPrimeFactorRemainingSlot = remainingSlot; kernels.SmallPrimeFactorRemainingSlot = remainingSlot;
} }
return new SmallPrimeFactorScratch(primeSlots!, exponentSlots!, countSlot!, remainingSlot!); MemoryBuffer1D<byte, Stride1D.Dense>? fullyFactoredSlot = kernels.SmallPrimeFactorFullyFactoredSlot;
if (fullyFactoredSlot is null)
{
fullyFactoredSlot = accelerator.Allocate1D<byte>(1);
kernels.SmallPrimeFactorFullyFactoredSlot = fullyFactoredSlot;
}
return new SmallPrimeFactorScratch(primeSlots!, exponentSlots!, countSlot!, remainingSlot!, fullyFactoredSlot!);
} }
} }
@@ -151,34 +151,52 @@ internal static partial class PrimeOrderGpuHeuristics
primeTargets.Clear(); primeTargets.Clear();
exponentTargets.Clear(); exponentTargets.Clear();
if (!TryLaunchPartialFactorKernel( try
{
var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
var execution = lease.EnterExecutionScope();
try
{
Accelerator accelerator = lease.Accelerator;
AcceleratorStream stream = lease.Stream;
SmallPrimeFactorScratch scratch = GpuKernelPool.EnsureSmallPrimeFactorScratch(accelerator, primeTargets.Length);
return TryPartialFactor(
accelerator,
stream,
scratch,
value, value,
limit, limit,
primeTargets, primeTargets,
exponentTargets, exponentTargets,
out int extracted, out factorCount,
out ulong leftover, out remaining,
out bool kernelFullyFactored)) out fullyFactored);
}
finally
{ {
return false; execution.Dispose();
lease.Dispose();
}
}
catch (CLException ex)
{
Console.WriteLine($"GPU ERROR ({ex.Error}): {ex.Message}");
}
catch (Exception ex) when (ex is AcceleratorException or InternalCompilerException or NotSupportedException or InvalidOperationException or AggregateException)
{
Console.WriteLine($"GPU ERROR: {ex.Message}");
} }
int capacity = Math.Min(primeTargets.Length, exponentTargets.Length);
if (extracted > capacity)
{
factorCount = 0; factorCount = 0;
remaining = value; remaining = value;
fullyFactored = false; fullyFactored = false;
return false; return false;
} }
factorCount = extracted; public static bool TryPartialFactor(
remaining = leftover; Accelerator accelerator,
fullyFactored = kernelFullyFactored && leftover == 1UL; AcceleratorStream stream,
return true; SmallPrimeFactorScratch scratch,
}
private static bool TryLaunchPartialFactorKernel(
ulong value, ulong value,
uint limit, uint limit,
Span<ulong> primeTargets, Span<ulong> primeTargets,
@@ -191,30 +209,59 @@ internal static partial class PrimeOrderGpuHeuristics
remaining = value; remaining = value;
fullyFactored = false; fullyFactored = false;
primeTargets.Clear();
exponentTargets.Clear();
try try
{ {
var lease = GpuKernelPool.GetKernel(useGpuOrder: true); return TryPartialFactorCore(
var execution = lease.EnterExecutionScope(); accelerator,
Accelerator accelerator = lease.Accelerator; stream,
AcceleratorStream stream = lease.Stream; scratch,
value,
limit,
primeTargets,
exponentTargets,
out factorCount,
out remaining,
out fullyFactored);
}
catch (CLException ex)
{
Console.WriteLine($"GPU ERROR ({ex.Error}): {ex.Message}");
}
catch (Exception ex) when (ex is AcceleratorException or InternalCompilerException or NotSupportedException or InvalidOperationException or AggregateException)
{
Console.WriteLine($"GPU ERROR: {ex.Message}");
}
factorCount = 0;
remaining = value;
fullyFactored = false;
return false;
}
private static bool TryPartialFactorCore(
Accelerator accelerator,
AcceleratorStream stream,
SmallPrimeFactorScratch scratch,
ulong value,
uint limit,
Span<ulong> primeTargets,
Span<int> exponentTargets,
out int factorCount,
out ulong remaining,
out bool fullyFactored)
{
factorCount = 0;
remaining = value;
fullyFactored = false;
scratch.Clear();
var kernel = GetPartialFactorKernel(accelerator); var kernel = GetPartialFactorKernel(accelerator);
SmallPrimeDeviceCache cache = GetSmallPrimeDeviceCache(accelerator); SmallPrimeDeviceCache cache = GetSmallPrimeDeviceCache(accelerator);
// TODO: We should create / reallocate these buffer only once or if the new required length is bigger than capacity.
var factorBuffer = accelerator.Allocate1D<ulong>(primeTargets.Length);
var exponentBuffer = accelerator.Allocate1D<int>(exponentTargets.Length);
var countBuffer = accelerator.Allocate1D<int>(1);
var remainingBuffer = accelerator.Allocate1D<ulong>(1);
var fullyFactoredBuffer = accelerator.Allocate1D<byte>(1);
// TODO: There is no need to clear these buffers because the kernel will always assign values within the required bounds.
// factorBuffer.MemSetToZero();
// exponentBuffer.MemSetToZero();
// countBuffer.MemSetToZero();
// remainingBuffer.MemSetToZero();
// fullyFactoredBuffer.MemSetToZero();
kernel( kernel(
stream, stream,
1, 1,
@@ -224,51 +271,38 @@ internal static partial class PrimeOrderGpuHeuristics
primeTargets.Length, primeTargets.Length,
value, value,
limit, limit,
factorBuffer.View, scratch.PrimeSlots.View,
exponentBuffer.View, scratch.ExponentSlots.View,
countBuffer.View, scratch.CountSlot.View,
remainingBuffer.View, scratch.RemainingSlot.View,
fullyFactoredBuffer.View); scratch.FullyFactoredSlot.View);
stream.Synchronize(); stream.Synchronize();
countBuffer.View.CopyToCPU(ref factorCount, 1); scratch.CountSlot.View.CopyToCPU(ref factorCount, 1);
factorCount = Math.Min(factorCount, primeTargets.Length); int capacity = Math.Min(primeTargets.Length, exponentTargets.Length);
factorBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(primeTargets), primeTargets.Length); if (factorCount > capacity)
exponentBuffer.View.CopyToCPU(ref MemoryMarshal.GetReference(exponentTargets), exponentTargets.Length); {
remainingBuffer.View.CopyToCPU(ref remaining, 1); factorCount = 0;
remaining = value;
fullyFactored = false;
return false;
}
if (factorCount > 0)
{
scratch.PrimeSlots.View.CopyToCPU(ref MemoryMarshal.GetReference(primeTargets), factorCount);
scratch.ExponentSlots.View.CopyToCPU(ref MemoryMarshal.GetReference(exponentTargets), factorCount);
}
scratch.RemainingSlot.View.CopyToCPU(ref remaining, 1);
byte fullyFactoredFlag = 0; byte fullyFactoredFlag = 0;
fullyFactoredBuffer.View.CopyToCPU(ref fullyFactoredFlag, 1); scratch.FullyFactoredSlot.View.CopyToCPU(ref fullyFactoredFlag, 1);
fullyFactored = fullyFactoredFlag != 0; bool kernelFullyFactored = fullyFactoredFlag != 0;
fullyFactored = kernelFullyFactored && remaining == 1UL;
// TODO: These buffers shouldn't be disposed but rather reused accross call with the assigned accelerator.
factorBuffer.Dispose();
exponentBuffer.Dispose();
countBuffer.Dispose();
remainingBuffer.Dispose();
fullyFactoredBuffer.Dispose();
execution.Dispose();
lease.Dispose();
return true; return true;
} }
catch (CLException ex)
{
Console.WriteLine($"GPU ERROR ({ex.Error}): {ex.Message}");
factorCount = 0;
remaining = value;
fullyFactored = false;
return false;
}
catch (Exception ex) when (ex is AcceleratorException or InternalCompilerException or NotSupportedException or InvalidOperationException or AggregateException)
{
Console.WriteLine($"GPU ERROR: {ex.Message}");
factorCount = 0;
remaining = value;
fullyFactored = false;
return false;
}
}
public static GpuPow2ModStatus TryPow2Mod(ulong exponent, ulong prime, out ulong remainder, in MontgomeryDivisorData divisorData) public static GpuPow2ModStatus TryPow2Mod(ulong exponent, ulong prime, out ulong remainder, in MontgomeryDivisorData divisorData)
{ {
+107 -15
View File
@@ -3,9 +3,10 @@ using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ILGPU; using ILGPU;
using ILGPU.Runtime;
using PerfectNumbers.Core.Gpu; using PerfectNumbers.Core.Gpu;
using System.Runtime.InteropServices;
namespace PerfectNumbers.Core; namespace PerfectNumbers.Core;
@@ -43,6 +44,43 @@ internal static partial class PrimeOrderCalculator
} }
} }
private sealed class PartialFactorGpuContext : IDisposable
{
private readonly GpuKernelLease _lease;
private readonly GpuKernelLease.ExecutionScope _executionScope;
private PartialFactorGpuContext(GpuKernelLease lease, GpuKernelLease.ExecutionScope executionScope, Accelerator accelerator, AcceleratorStream stream, SmallPrimeFactorScratch scratch)
{
_lease = lease;
_executionScope = executionScope;
Accelerator = accelerator;
Stream = stream;
Scratch = scratch;
}
public Accelerator Accelerator { get; }
public AcceleratorStream Stream { get; }
public SmallPrimeFactorScratch Scratch { get; }
public static PartialFactorGpuContext Rent()
{
var lease = GpuKernelPool.GetKernel(useGpuOrder: true);
var execution = lease.EnterExecutionScope();
Accelerator accelerator = lease.Accelerator;
AcceleratorStream stream = lease.Stream;
SmallPrimeFactorScratch scratch = GpuKernelPool.EnsureSmallPrimeFactorScratch(accelerator, GpuSmallPrimeFactorSlots);
return new PartialFactorGpuContext(lease, execution, accelerator, stream, scratch);
}
public void Dispose()
{
_executionScope.Dispose();
_lease.Dispose();
}
}
private static ulong CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config) private static ulong CalculateInternal(ulong prime, ulong? previousOrder, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config)
{ {
// TODO: Is this condition ever met on EvenPerfectBitScanner's execution path? If not, we can add a clarification comment and comment out the entire block. We want to support p candidates at least greater or equal to 31. // TODO: Is this condition ever met on EvenPerfectBitScanner's execution path? If not, we can add a clarification comment and comment out the entire block. We want to support p candidates at least greater or equal to 31.
@@ -58,7 +96,18 @@ internal static partial class PrimeOrderCalculator
return gpuOrder; return gpuOrder;
} }
PartialFactorResult phiFactors = PartialFactor(phi, config); PartialFactorGpuContext? gpuContext = null;
bool disposeContext = false;
if (IsGpuHeuristicDevice)
{
gpuContext = PartialFactorGpuContext.Rent();
disposeContext = true;
}
try
{
PartialFactorResult phiFactors = PartialFactor(phi, config, gpuContext);
ulong result; ulong result;
if (phiFactors.Factors is null) if (phiFactors.Factors is null)
@@ -68,10 +117,18 @@ internal static partial class PrimeOrderCalculator
return result; return result;
} }
result = RunHeuristicPipelineCpu(prime, previousOrder, config, divisorData, phi, phiFactors); result = RunHeuristicPipelineCpu(prime, previousOrder, config, divisorData, phi, phiFactors, gpuContext);
phiFactors.Dispose(); phiFactors.Dispose();
return result; return result;
} }
finally
{
if (disposeContext && gpuContext is not null)
{
gpuContext.Dispose();
}
}
}
private static ulong RunHeuristicPipelineCpu( private static ulong RunHeuristicPipelineCpu(
ulong prime, ulong prime,
@@ -79,7 +136,8 @@ internal static partial class PrimeOrderCalculator
in PrimeOrderSearchConfig config, in PrimeOrderSearchConfig config,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
ulong phi, ulong phi,
PartialFactorResult phiFactors) PartialFactorResult phiFactors,
PartialFactorGpuContext? gpuContext)
{ {
if (phiFactors.FullyFactored && TrySpecialMaxCpu(phi, prime, phiFactors, divisorData)) if (phiFactors.FullyFactored && TrySpecialMaxCpu(phi, prime, phiFactors, divisorData))
{ {
@@ -89,7 +147,7 @@ internal static partial class PrimeOrderCalculator
ulong candidateOrder = InitializeStartingOrderCpu(prime, phi, divisorData); ulong candidateOrder = InitializeStartingOrderCpu(prime, phi, divisorData);
candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData); candidateOrder = ExponentLoweringCpu(candidateOrder, prime, phiFactors, divisorData);
if (TryConfirmOrderCpu(prime, candidateOrder, divisorData, config, out PartialFactorResult? orderFactors)) if (TryConfirmOrderCpu(prime, candidateOrder, divisorData, config, gpuContext, out PartialFactorResult? orderFactors))
{ {
return candidateOrder; return candidateOrder;
} }
@@ -100,7 +158,7 @@ internal static partial class PrimeOrderCalculator
return CalculateByFactorizationCpu(prime, divisorData); return CalculateByFactorizationCpu(prime, divisorData);
} }
if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, out ulong order)) if (TryHeuristicFinishCpu(prime, candidateOrder, previousOrder, divisorData, config, phiFactors, orderFactors, gpuContext, out ulong order))
{ {
return order; return order;
} }
@@ -330,6 +388,7 @@ internal static partial class PrimeOrderCalculator
ulong order, ulong order,
in MontgomeryDivisorData divisorData, in MontgomeryDivisorData divisorData,
in PrimeOrderSearchConfig config, in PrimeOrderSearchConfig config,
PartialFactorGpuContext? gpuContext,
out PartialFactorResult? reusableFactorization) out PartialFactorResult? reusableFactorization)
{ {
reusableFactorization = null; reusableFactorization = null;
@@ -344,7 +403,7 @@ internal static partial class PrimeOrderCalculator
return false; return false;
} }
PartialFactorResult factorization = PartialFactor(order, config); PartialFactorResult factorization = PartialFactor(order, config, gpuContext);
if (factorization.Factors is null) if (factorization.Factors is null)
{ {
factorization.Dispose(); factorization.Dispose();
@@ -492,6 +551,7 @@ internal static partial class PrimeOrderCalculator
in PrimeOrderSearchConfig config, in PrimeOrderSearchConfig config,
PartialFactorResult phiFactors, PartialFactorResult phiFactors,
PartialFactorResult? cachedOrderFactors, PartialFactorResult? cachedOrderFactors,
PartialFactorGpuContext? gpuContext,
out ulong result) out ulong result)
{ {
result = 0UL; result = 0UL;
@@ -502,7 +562,7 @@ internal static partial class PrimeOrderCalculator
} }
// Reuse the partial factorization from TryConfirmOrderCpu when available. // Reuse the partial factorization from TryConfirmOrderCpu when available.
PartialFactorResult orderFactors = cachedOrderFactors ?? PartialFactor(order, config); PartialFactorResult orderFactors = cachedOrderFactors ?? PartialFactor(order, config, gpuContext);
try try
{ {
if (orderFactors.Factors is null) if (orderFactors.Factors is null)
@@ -618,7 +678,7 @@ internal static partial class PrimeOrderCalculator
bool equalsOne = powStepper.InitializeCpuIsUnity(candidate); bool equalsOne = powStepper.InitializeCpuIsUnity(candidate);
powStepperInitialized = true; powStepperInitialized = true;
if (equalsOne && TryConfirmCandidateCpu(prime, candidate, divisorData, config, ref powUsed, powBudget)) if (equalsOne && TryConfirmCandidateCpu(prime, candidate, divisorData, config, gpuContext, ref powUsed, powBudget))
{ {
if (gpuPool is not null) if (gpuPool is not null)
{ {
@@ -655,7 +715,7 @@ internal static partial class PrimeOrderCalculator
continue; continue;
} }
if (!TryConfirmCandidateCpu(prime, candidate, divisorData, config, ref powUsed, powBudget)) if (!TryConfirmCandidateCpu(prime, candidate, divisorData, config, gpuContext, ref powUsed, powBudget))
{ {
continue; continue;
} }
@@ -858,9 +918,9 @@ internal static partial class PrimeOrderCalculator
} }
} }
private static bool TryConfirmCandidateCpu(ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config, ref int powUsed, int powBudget) private static bool TryConfirmCandidateCpu(ulong prime, ulong candidate, in MontgomeryDivisorData divisorData, in PrimeOrderSearchConfig config, PartialFactorGpuContext? gpuContext, ref int powUsed, int powBudget)
{ {
PartialFactorResult factorization = PartialFactor(candidate, config); PartialFactorResult factorization = PartialFactor(candidate, config, gpuContext);
try try
{ {
if (factorization.Factors is null) if (factorization.Factors is null)
@@ -1024,7 +1084,7 @@ internal static partial class PrimeOrderCalculator
// private static ulong _partialFactorPendingHits; // private static ulong _partialFactorPendingHits;
// private static ulong _partialFactorCofactorHits; // private static ulong _partialFactorCofactorHits;
private static PartialFactorResult PartialFactor(ulong value, in PrimeOrderSearchConfig config) private static PartialFactorResult PartialFactor(ulong value, in PrimeOrderSearchConfig config, PartialFactorGpuContext? gpuContext = null)
{ {
if (value <= 1UL) if (value <= 1UL)
{ {
@@ -1033,6 +1093,17 @@ internal static partial class PrimeOrderCalculator
const int FactorSlotCount = GpuSmallPrimeFactorSlots; const int FactorSlotCount = GpuSmallPrimeFactorSlots;
PartialFactorGpuContext? localContext = gpuContext;
bool disposeContext = false;
if (IsGpuHeuristicDevice && localContext is null)
{
localContext = PartialFactorGpuContext.Rent();
disposeContext = true;
}
try
{
// stackalloc is faster than pooling // stackalloc is faster than pooling
// ulong[] primeSlotsArray = ThreadStaticPools.UlongPool.Rent(FactorSlotCount); // ulong[] primeSlotsArray = ThreadStaticPools.UlongPool.Rent(FactorSlotCount);
// int[] exponentSlotsArray = ThreadStaticPools.IntPool.Rent(FactorSlotCount); // int[] exponentSlotsArray = ThreadStaticPools.IntPool.Rent(FactorSlotCount);
@@ -1052,7 +1123,21 @@ internal static partial class PrimeOrderCalculator
ulong remaining = value; ulong remaining = value;
bool gpuFactored = false; bool gpuFactored = false;
if (IsGpuHeuristicDevice) if (IsGpuHeuristicDevice && localContext is not null)
{
gpuFactored = PrimeOrderGpuHeuristics.TryPartialFactor(
localContext.Accelerator,
localContext.Stream,
localContext.Scratch,
value,
limit,
primeSlots,
exponentSlots,
out factorCount,
out remaining,
out _);
}
else if (IsGpuHeuristicDevice)
{ {
gpuFactored = PrimeOrderGpuHeuristics.TryPartialFactor(value, limit, primeSlots, exponentSlots, out factorCount, out remaining, out _); gpuFactored = PrimeOrderGpuHeuristics.TryPartialFactor(value, limit, primeSlots, exponentSlots, out factorCount, out remaining, out _);
} }
@@ -1329,7 +1414,14 @@ internal static partial class PrimeOrderCalculator
ThreadStaticPools.ReturnPrimeOrderPendingEntryList(pending); ThreadStaticPools.ReturnPrimeOrderPendingEntryList(pending);
return result; return result;
} }
finally
{
if (disposeContext && localContext is not null)
{
localContext.Dispose();
}
}
}
private static bool TryPopulateSmallPrimeFactorsCpu( private static bool TryPopulateSmallPrimeFactorsCpu(
ulong value, ulong value,
+10 -24
View File
@@ -1,5 +1,4 @@
using System; using System;
using System.Runtime.InteropServices;
using ILGPU; using ILGPU;
using ILGPU.Runtime; using ILGPU.Runtime;
using ILGPU.Runtime.OpenCL; using ILGPU.Runtime.OpenCL;
@@ -32,38 +31,25 @@ internal static partial class PrimeOrderCalculator
Accelerator accelerator = lease.Accelerator; Accelerator accelerator = lease.Accelerator;
AcceleratorStream stream = lease.Stream; AcceleratorStream stream = lease.Stream;
SmallPrimeFactorTables tables = GpuKernelPool.EnsureSmallPrimeFactorTables(accelerator);
SmallPrimeFactorScratch scratch = GpuKernelPool.EnsureSmallPrimeFactorScratch(accelerator, GpuSmallPrimeFactorSlots); SmallPrimeFactorScratch scratch = GpuKernelPool.EnsureSmallPrimeFactorScratch(accelerator, GpuSmallPrimeFactorSlots);
// scratch.Clear();
var kernel = lease.SmallPrimeFactorKernel; bool success = PrimeOrderGpuHeuristics.TryPartialFactor(
kernel( accelerator,
stream, stream,
1, scratch,
value, value,
limit, limit,
tables.PrimesView, primeBuffer,
tables.SquaresView, exponentBuffer,
tables.Count, out factorCount,
scratch.PrimeSlots.View, out remaining,
scratch.ExponentSlots.View, out _);
scratch.CountSlot.View,
scratch.RemainingSlot.View);
stream.Synchronize(); if (!success)
factorCount = 0;
scratch.CountSlot.View.CopyToCPU(ref factorCount, 1);
factorCount = Math.Min(factorCount, GpuSmallPrimeFactorSlots);
if (factorCount > 0)
{ {
scratch.PrimeSlots.View.CopyToCPU(ref MemoryMarshal.GetReference(primeBuffer), factorCount); return false;
scratch.ExponentSlots.View.CopyToCPU(ref MemoryMarshal.GetReference(exponentBuffer), factorCount);
} }
scratch.RemainingSlot.View.CopyToCPU(ref remaining, 1);
for (int i = 0; i < factorCount; i++) for (int i = 0; i < factorCount; i++)
{ {
ulong primeValue = primeBuffer[i]; ulong primeValue = primeBuffer[i];