Warm GPU resources before thread startup

This commit is contained in:
Marek Lemańczyk authored and mlemanczyk committed 2025-11-02 11:22:28 +01:00
1 parent 2281d9535e
commit ab6a416de2
9 files changed
+822 -403

No files matched your search

@@ -1,6 +1,7 @@
using Open.Numeric.Primes;
using System.Runtime.CompilerServices;
using System;
using ILGPU.Runtime;
using System.Runtime.CompilerServices;
using PerfectNumbers.Core.Gpu;
namespace PerfectNumbers.Core;
@@ -40,32 +41,48 @@ public sealed class HeuristicCombinedPrimeTester
CombinedDivisorsEnding9Squares = CombinedDivisorsEnding9OneAOneBSquares;
}
public static void EnsureInitialized()
{
// Intentionally left blank. Accessing this method forces the static constructor to run.
}
internal static ReadOnlySpan<ulong> CombinedDivisorsEnding1Span => CombinedDivisorsEnding1;
internal static ReadOnlySpan<ulong> CombinedDivisorsEnding3Span => CombinedDivisorsEnding3;
internal static ReadOnlySpan<ulong> CombinedDivisorsEnding7Span => CombinedDivisorsEnding7;
internal static ReadOnlySpan<ulong> CombinedDivisorsEnding9Span => CombinedDivisorsEnding9;
internal static ReadOnlySpan<ulong> CombinedDivisorsEnding1SquaresSpan => CombinedDivisorsEnding1Squares;
internal static ReadOnlySpan<ulong> CombinedDivisorsEnding3SquaresSpan => CombinedDivisorsEnding3Squares;
internal static ReadOnlySpan<ulong> CombinedDivisorsEnding7SquaresSpan => CombinedDivisorsEnding7Squares;
internal static ReadOnlySpan<ulong> CombinedDivisorsEnding9SquaresSpan => CombinedDivisorsEnding9Squares;
private const ulong Wheel210 = 210UL;
private static readonly uint[] CombinedDivisorsEnding1TwoAOneB;
private static readonly uint[] CombinedDivisorsEnding3TwoAOneB;
private static readonly uint[] CombinedDivisorsEnding7TwoAOneB;
private static readonly uint[] CombinedDivisorsEnding9TwoAOneB;
private static readonly ulong[] CombinedDivisorsEnding1TwoAOneB;
private static readonly ulong[] CombinedDivisorsEnding3TwoAOneB;
private static readonly ulong[] CombinedDivisorsEnding7TwoAOneB;
private static readonly ulong[] CombinedDivisorsEnding9TwoAOneB;
private static readonly uint[] CombinedDivisorsEnding1OneAOneB;
private static readonly uint[] CombinedDivisorsEnding3OneAOneB;
private static readonly uint[] CombinedDivisorsEnding7OneAOneB;
private static readonly uint[] CombinedDivisorsEnding9OneAOneB;
private static readonly ulong[] CombinedDivisorsEnding1OneAOneB;
private static readonly ulong[] CombinedDivisorsEnding3OneAOneB;
private static readonly ulong[] CombinedDivisorsEnding7OneAOneB;
private static readonly ulong[] CombinedDivisorsEnding9OneAOneB;
private static readonly uint[] CombinedDivisorsEnding1ThreeAOneB;
private static readonly uint[] CombinedDivisorsEnding3ThreeAOneB;
private static readonly uint[] CombinedDivisorsEnding7ThreeAOneB;
private static readonly uint[] CombinedDivisorsEnding9ThreeAOneB;
private static readonly ulong[] CombinedDivisorsEnding1ThreeAOneB;
private static readonly ulong[] CombinedDivisorsEnding3ThreeAOneB;
private static readonly ulong[] CombinedDivisorsEnding7ThreeAOneB;
private static readonly ulong[] CombinedDivisorsEnding9ThreeAOneB;
private static readonly uint[] CombinedDivisorsEnding1ThreeATwoB;
private static readonly uint[] CombinedDivisorsEnding3ThreeATwoB;
private static readonly uint[] CombinedDivisorsEnding7ThreeATwoB;
private static readonly uint[] CombinedDivisorsEnding9ThreeATwoB;
private static readonly ulong[] CombinedDivisorsEnding1ThreeATwoB;
private static readonly ulong[] CombinedDivisorsEnding3ThreeATwoB;
private static readonly ulong[] CombinedDivisorsEnding7ThreeATwoB;
private static readonly ulong[] CombinedDivisorsEnding9ThreeATwoB;
private static readonly uint[] CombinedDivisorsEnding1;
private static readonly uint[] CombinedDivisorsEnding3;
private static readonly uint[] CombinedDivisorsEnding7;
private static readonly uint[] CombinedDivisorsEnding9;
private static readonly ulong[] CombinedDivisorsEnding1;
private static readonly ulong[] CombinedDivisorsEnding3;
private static readonly ulong[] CombinedDivisorsEnding7;
private static readonly ulong[] CombinedDivisorsEnding9;
private static readonly ulong[] CombinedDivisorsEnding1TwoAOneBSquares;
private static readonly ulong[] CombinedDivisorsEnding3TwoAOneBSquares;
@@ -173,7 +190,7 @@ public sealed class HeuristicCombinedPrimeTester
private static bool HeuristicTrialDivisionCpu(ulong n, ulong maxDivisorSquare, byte nMod10)
{
ReadOnlySpan<uint> combinedDivisors = GetCombinedDivisors(nMod10);
ReadOnlySpan<ulong> combinedDivisors = GetCombinedDivisors(nMod10);
ReadOnlySpan<ulong> combinedDivisorSquares = GetCombinedDivisorSquares(nMod10);
int length = combinedDivisors.Length;
@@ -205,78 +222,43 @@ public sealed class HeuristicCombinedPrimeTester
_ => 256,
};
private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
{
int batchCapacity = GetBatchSize(n);
private static bool HeuristicTrialDivisionGpuDetectsDivisor(ulong n, ulong maxDivisorSquare, byte nMod10)
{
var limiter = GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeTester.PrimeTesterGpuContextPool.Rent(1);
var accelerator = gpu.Accelerator;
var kernel = gpu.HeuristicTrialDivisionKernel;
var flagView1D = gpu.HeuristicFlag.View;
var flagView = flagView1D.AsContiguous();
bool compositeDetected = false;
int divisorLength = GetCombinedDivisors(nMod10).Length;
if (divisorLength > 0)
{
int compositeFlag = 0;
flagView1D.CopyFromCPU(ref compositeFlag, 1);
kernel(
divisorLength,
flagView,
n,
maxDivisorSquare,
HeuristicGpuDivisorTableKind.Combined,
gpu.HeuristicGpuTables);
accelerator.Synchronize();
flagView1D.CopyToCPU(ref compositeFlag, 1);
compositeDetected = compositeFlag != 0;
}
gpu.Dispose();
limiter.Dispose();
return compositeDetected;
}
var limiter = GpuPrimeWorkLimiter.Acquire();
var gpu = PrimeTester.PrimeTesterGpuContextPool.Rent(batchCapacity);
var accelerator = gpu.Accelerator;
var kernel = gpu.HeuristicTrialDivisionKernel;
bool compositeDetected = false;
int count = 0;
var inputView = gpu.Input.View;
var flagView = gpu.HeuristicFlag.View;
ulong[] divisorArray = gpu.DivisorArray;
bool ProcessBatch(int length)
{
inputView.CopyFromCPU(ref divisorArray[0], length);
int compositeFlag = 0;
flagView.CopyFromCPU(ref compositeFlag, 1);
kernel(length, inputView, n, flagView);
accelerator.Synchronize();
flagView.CopyToCPU(ref compositeFlag, 1);
return compositeFlag != 0;
}
ReadOnlySpan<uint> combinedDivisors = GetCombinedDivisors(nMod10);
ReadOnlySpan<ulong> combinedDivisorSquares = GetCombinedDivisorSquares(nMod10);
int length = combinedDivisors.Length;
for (int i = 0; i < length; i++)
{
ulong divisorSquare = combinedDivisorSquares[i];
if (divisorSquare > maxDivisorSquare)
{
break;
}
divisorArray[count] = combinedDivisors[i];
count++;
if (count == batchCapacity)
{
if (ProcessBatch(count))
{
compositeDetected = true;
goto Cleanup;
}
count = 0;
}
}
if (count > 0 && ProcessBatch(count))
{
compositeDetected = true;
goto Cleanup;
}
Cleanup:
gpu.Dispose();
limiter.Dispose();
return compositeDetected;
}
private static bool EvaluateWithOpenNumericFallback(ulong n)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool EvaluateWithOpenNumericFallback(ulong n)
{
return Prime.Numbers.IsPrime(n);
}
@@ -285,7 +267,7 @@ public sealed class HeuristicCombinedPrimeTester
return n;
}
private static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10)
private static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10)
{
return nMod10 switch
{
@@ -309,7 +291,7 @@ public sealed class HeuristicCombinedPrimeTester
};
}
internal static ReadOnlySpan<uint> GetCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern)
internal static ReadOnlySpan<ulong> GetCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern)
{
return pattern switch
{
@@ -389,17 +371,17 @@ public sealed class HeuristicCombinedPrimeTester
};
}
private static uint[] BuildCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern, out ulong[] squares)
private static ulong[] BuildCombinedDivisors(byte nMod10, CombinedDivisorPattern pattern, out ulong[] squares)
{
ReadOnlySpan<int> groupA = HeuristicPrimeSieves.GroupADivisors;
ReadOnlySpan<ulong> groupA = HeuristicPrimeSieves.GroupADivisors;
ReadOnlySpan<uint> groupB = GetGroupBDivisors(nMod10);
var combined = new List<uint>(groupA.Length + groupB.Length);
var combined = new List<ulong>(groupA.Length + groupB.Length);
int groupAIndex = 0;
while (groupAIndex < groupA.Length && groupA[groupAIndex] <= 19)
{
combined.Add((uint)groupA[groupAIndex]);
combined.Add(groupA[groupAIndex]);
groupAIndex++;
}
@@ -435,7 +417,7 @@ public sealed class HeuristicCombinedPrimeTester
int addedA = 0;
while (addedA < groupAInterleaveCount && groupAIndex < groupA.Length)
{
combined.Add((uint)groupA[groupAIndex]);
combined.Add(groupA[groupAIndex]);
groupAIndex++;
addedA++;
}
@@ -449,7 +431,7 @@ public sealed class HeuristicCombinedPrimeTester
}
}
uint[] result = [.. combined];
ulong[] result = [.. combined];
ulong[] resultSquares = new ulong[result.Length];
for (int i = 0; i < result.Length; i++)
{
@@ -474,12 +456,12 @@ public sealed class HeuristicCombinedPrimeTester
return index;
}
private static bool IsGroupAPrefixValue(uint value) => value is 3U or 7U or 11U or 13U;
private static bool IsGroupAPrefixValue(ulong value) => value is 3UL or 7UL or 11UL or 13UL;
private static HeuristicDivisorGroup ResolveGroup(uint value) => value switch
private static HeuristicDivisorGroup ResolveGroup(ulong value) => value switch
{
3U or 7U or 11U or 13U => HeuristicDivisorGroup.GroupAConstant,
_ when value % 10U == 3U => HeuristicDivisorGroup.GroupAWheel,
3UL or 7UL or 11UL or 13UL => HeuristicDivisorGroup.GroupAConstant,
_ when value % 10UL == 3UL => HeuristicDivisorGroup.GroupAWheel,
_ => HeuristicDivisorGroup.GroupB,
};
@@ -578,7 +560,7 @@ public sealed class HeuristicCombinedPrimeTester
internal ref struct HeuristicDivisorEnumerator
{
private readonly ulong maxDivisorSquare;
private readonly ReadOnlySpan<uint> combinedDivisors;
private readonly ReadOnlySpan<ulong> combinedDivisors;
private readonly ReadOnlySpan<ulong> combinedDivisorSquares;
private int index;
@@ -603,7 +585,7 @@ public sealed class HeuristicCombinedPrimeTester
break;
}
uint entry = combinedDivisors[currentIndex];
ulong entry = combinedDivisors[currentIndex];
index = currentIndex + 1;
HeuristicDivisorGroup group = ResolveGroup(entry);