Merge pull request #52 from mlemanczyk/codex/optimize-mersennenumberresiduegputester.scan-method

Restore struct residue args and add benchmarking project
This commit is contained in:
Marek Lemańczyk authored and GitHub committed 2025-09-21 05:29:28 +02:00
commit c7e1ac60d2
10 files changed
+326 -165

No files matched your search

+31 -3
View File
@@ -7,7 +7,8 @@
"description": "Select project to run", "description": "Select project to run",
"options": [ "options": [
"EvenPerfectBitScanner", "EvenPerfectBitScanner",
"EvenPerfectBitScanner.ResultsParser" "EvenPerfectBitScanner.ResultsParser",
"EvenPerfectBitScanner.Benchmarks"
], ],
"default": "EvenPerfectBitScanner" "default": "EvenPerfectBitScanner"
} }
@@ -20,7 +21,7 @@
"preLaunchTask": "Build Debug", "preLaunchTask": "Build Debug",
"program": "${workspaceFolder}/${input:projectName}/bin/Debug/net8.0/${input:projectName}.dll", "program": "${workspaceFolder}/${input:projectName}/bin/Debug/net8.0/${input:projectName}.dll",
"args": [ "args": [
"--increment=add --mersenne=residue --threads=128 --gpu-scan-batch=512000 --primes-device=gpu --mersenne-device=gpu --mod-reduction=barrett128 --block-size=10000000 --gpu-prime-threads=32 --write-batch-size=10000 --divisor-cycles-device=gpu" "--increment=add --mersenne=residue --threads=128 --gpu-scan-batch=512000 --primes-device=gpu --mersenne-device=gpu --mod-reduction=barrett128 --block-size=10000000 --gpu-prime-threads=32 --write-batch-size=10000 --divisor-cycles-device=gpu"
], ],
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"stopAtEntry": false, "stopAtEntry": false,
@@ -93,6 +94,33 @@
"console": "integratedTerminal", "console": "integratedTerminal",
"internalConsoleOptions": "neverOpen", "internalConsoleOptions": "neverOpen",
"justMyCode": false "justMyCode": false
},
{
"name": "Run EvenPerfectBitScanner.Benchmarks",
"type": "coreclr",
"request": "launch",
"noDebug": true,
"preLaunchTask": "Build EvenPerfectBitScanner.Benchmarks Release",
"program": "${workspaceFolder}/EvenPerfectBitScanner.Benchmarks/bin/Release/net8.0/EvenPerfectBitScanner.Benchmarks.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"justMyCode": false
},
{
"name": "Debug EvenPerfectBitScanner.Benchmarks",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "Build EvenPerfectBitScanner.Benchmarks Debug",
"program": "${workspaceFolder}/EvenPerfectBitScanner.Benchmarks/bin/Debug/net8.0/EvenPerfectBitScanner.Benchmarks.dll",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"justMyCode": false
} }
] ]
} }
+124 -79
View File
@@ -1,66 +1,66 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "tasks": [
{ {
"label": "Build Debug", "label": "Build Debug",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"build", "build",
"${workspaceFolder}/EvenPerfectScanner.sln", "${workspaceFolder}/EvenPerfectScanner.sln",
"--configuration", "--configuration",
"Debug", "Debug",
"--framework", "--framework",
"net8.0" "net8.0"
], ],
"group": { "group": {
"kind": "build", "kind": "build",
"isDefault": false "isDefault": false
}, },
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build Release", "label": "Build Release",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"build", "build",
"${workspaceFolder}/EvenPerfectScanner.sln", "${workspaceFolder}/EvenPerfectScanner.sln",
"--configuration", "--configuration",
"Release", "Release",
"--framework", "--framework",
"net8.0" "net8.0"
], ],
"group": "build", "group": "build",
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build EvenPerfectBitScanner Debug", "label": "Build EvenPerfectBitScanner Debug",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"build", "build",
"${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj", "${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj",
"--configuration", "--configuration",
"Debug", "Debug",
"--framework", "--framework",
"net8.0" "net8.0"
], ],
"group": "build", "group": "build",
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
{ {
"label": "Build EvenPerfectBitScanner Release", "label": "Build EvenPerfectBitScanner Release",
"command": "dotnet", "command": "dotnet",
"type": "process", "type": "process",
"args": [ "args": [
"build", "build",
"${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj", "${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj",
"--configuration", "--configuration",
"Release", "Release",
"--framework", "--framework",
"net8.0" "net8.0"
], ],
"group": "build", "group": "build",
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },
@@ -97,16 +97,16 @@
{ {
"label": "Run EvenPerfectBitScanner", "label": "Run EvenPerfectBitScanner",
"type": "process", "type": "process",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
"run", "run",
"--project", "--project",
"${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj", "${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj",
"--configuration", "--configuration",
"Release", "Release",
"--framework", "--framework",
"net8.0" "net8.0"
], ],
"problemMatcher": [] "problemMatcher": []
}, },
{ {
@@ -124,18 +124,63 @@
], ],
"problemMatcher": [] "problemMatcher": []
}, },
{ {
"label": "Run Release (no debug)", "label": "Run Release (no debug)",
"type": "process", "type": "process",
"command": "dotnet", "command": "dotnet",
"args": [ "args": [
"run", "run",
"--configuration", "--configuration",
"Release", "Release",
"--framework", "--framework",
"net8.0" "net8.0"
], ],
"problemMatcher": [] "problemMatcher": []
} },
] {
} "label": "Build EvenPerfectBitScanner.Benchmarks Debug",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/EvenPerfectBitScanner.Benchmarks/EvenPerfectBitScanner.Benchmarks.csproj",
"--configuration",
"Debug",
"--framework",
"net8.0"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Build EvenPerfectBitScanner.Benchmarks Release",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/EvenPerfectBitScanner.Benchmarks/EvenPerfectBitScanner.Benchmarks.csproj",
"--configuration",
"Release",
"--framework",
"net8.0"
],
"group": "build",
"problemMatcher": "$msCompile"
},
{
"label": "Run EvenPerfectBitScanner.Benchmarks",
"type": "process",
"command": "dotnet",
"args": [
"run",
"--project",
"${workspaceFolder}/EvenPerfectBitScanner.Benchmarks/EvenPerfectBitScanner.Benchmarks.csproj",
"--configuration",
"Release",
"--framework",
"net8.0"
],
"problemMatcher": []
}
]
}
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../PerfectNumbers.Core/PerfectNumbers.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
</ItemGroup>
</Project>
@@ -0,0 +1,12 @@
using BenchmarkDotNet.Running;
namespace EvenPerfectBitScanner.Benchmarks;
public static class Program
{
public static void Main(string[] args)
{
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
}
@@ -0,0 +1,36 @@
using System.Numerics;
using BenchmarkDotNet.Attributes;
using PerfectNumbers.Core;
namespace EvenPerfectBitScanner.Benchmarks;
[MemoryDiagnoser]
public class ResidueComputationBenchmarks
{
[Params(3UL, 8191UL, 131071UL, 2147483647UL)]
public ulong Exponent { get; set; }
[Benchmark(Baseline = true)]
public (ulong Step10, ulong Step8, ulong Step3, ulong Step5) LegacyModulo()
{
ulong exponent = Exponent;
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
return (step10, step8, step3, step5);
}
[Benchmark]
public (ulong Step10, ulong Step8, ulong Step3, ulong Step5) ModMethodModulo()
{
UInt128 exponent128 = Exponent;
exponent128.Mod10_8_5_3(out ulong mod10, out ulong mod8, out ulong mod5, out ulong mod3);
ulong step10 = (mod10 << 1) % 10UL;
ulong step8 = (mod8 << 1) & 7UL;
ulong step3 = (mod3 << 1) % 3UL;
ulong step5 = (mod5 << 1) % 5UL;
return (step10, step8, step3, step5);
}
}
+6
View File
@@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Tests
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.ResultsParser", "EvenPerfectBitScanner.ResultsParser\EvenPerfectBitScanner.ResultsParser.csproj", "{B07A718C-A71C-410D-A0D7-FA1674CEB38F}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.ResultsParser", "EvenPerfectBitScanner.ResultsParser\EvenPerfectBitScanner.ResultsParser.csproj", "{B07A718C-A71C-410D-A0D7-FA1674CEB38F}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Benchmarks", "EvenPerfectBitScanner.Benchmarks\EvenPerfectBitScanner.Benchmarks.csproj", "{83551FCC-41FA-4162-B541-AFCB5666A29F}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -41,5 +43,9 @@ Global
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|Any CPU.Build.0 = Debug|Any CPU {B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|Any CPU.ActiveCfg = Release|Any CPU {B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|Any CPU.Build.0 = Release|Any CPU {B07A718C-A71C-410D-A0D7-FA1674CEB38F}.Release|Any CPU.Build.0 = Release|Any CPU
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83551FCC-41FA-4162-B541-AFCB5666A29F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
+4 -4
View File
@@ -158,7 +158,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
} }
} }
public readonly Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<uint, Stride1D.Dense>> IncrementalOrderKernel public readonly Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<uint, Stride1D.Dense>> IncrementalOrderKernel
{ {
get get
{ {
@@ -175,7 +175,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
} }
} }
public readonly Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<uint, Stride1D.Dense>> Pow2ModOrderKernel public readonly Action<AcceleratorStream, Index1D, ulong, GpuUInt128, GpuUInt128, byte, ulong, ResidueAutomatonArgs, ArrayView<int>, ArrayView1D<uint, Stride1D.Dense>> Pow2ModOrderKernel
{ {
get get
{ {
@@ -486,7 +486,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
} }
private static void IncrementalOrderKernelScan(Index1D index, ulong exponent, GpuUInt128 twoP, GpuUInt128 kStart, byte lastIsSeven, ulong divMul, private static void IncrementalOrderKernelScan(Index1D index, ulong exponent, GpuUInt128 twoP, GpuUInt128 kStart, byte lastIsSeven, ulong divMul,
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles) ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
{ {
ulong idx = (ulong)index.X; ulong idx = (ulong)index.X;
ulong r10 = ra.Q0M10 + (ra.Step10 * idx) % 10UL; r10 -= (r10 >= 10UL) ? 10UL : 0UL; ulong r10 = ra.Q0M10 + (ra.Step10 * idx) % 10UL; r10 -= (r10 >= 10UL) ? 10UL : 0UL;
@@ -570,7 +570,7 @@ public ref struct GpuKernelLease(IDisposable limiter, GpuContextLease gpu, Kerne
} }
private static void Pow2ModOrderKernelScan(Index1D index, ulong exponent, GpuUInt128 twoP, GpuUInt128 kStart, byte lastIsSeven, ulong _, private static void Pow2ModOrderKernelScan(Index1D index, ulong exponent, GpuUInt128 twoP, GpuUInt128 kStart, byte lastIsSeven, ulong _,
ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles) ResidueAutomatonArgs ra, ArrayView<int> found, ArrayView1D<uint, Stride1D.Dense> smallCycles)
{ {
ulong idx = (ulong)index.X; ulong idx = (ulong)index.X;
ulong r10 = ra.Q0M10 + (ra.Step10 * idx) % 10UL; r10 -= (r10 >= 10UL) ? 10UL : 0UL; ulong r10 = ra.Q0M10 + (ra.Step10 * idx) % 10UL; r10 -= (r10 >= 10UL) ? 10UL : 0UL;
@@ -23,10 +23,12 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
var pow2Kernel = gpuLease.Pow2ModKernel; var pow2Kernel = gpuLease.Pow2ModKernel;
var incKernel = gpuLease.IncrementalKernel; var incKernel = gpuLease.IncrementalKernel;
ulong step10 = ((exponent % 10UL) << 1) % 10UL; UInt128 exponent128 = exponent;
ulong step8 = ((exponent & 7UL) << 1) & 7UL; exponent128.Mod10_8_5_3(out ulong exponentMod10, out ulong exponentMod8, out ulong exponentMod5, out ulong exponentMod3);
ulong step3 = ((exponent % 3UL) << 1) % 3UL; ulong step10 = (exponentMod10 << 1) % 10UL;
ulong step5 = ((exponent % 5UL) << 1) % 5UL; ulong step8 = (exponentMod8 << 1) & 7UL;
ulong step3 = (exponentMod3 << 1) % 3UL;
ulong step5 = (exponentMod5 << 1) % 5UL;
GpuUInt128 twoPGpu = (GpuUInt128)twoP; GpuUInt128 twoPGpu = (GpuUInt128)twoP;
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator); var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
ResiduePrimeViews primeViews = default; ResiduePrimeViews primeViews = default;
@@ -55,9 +57,9 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
if (_kernelType == GpuKernelType.Pow2Mod) if (_kernelType == GpuKernelType.Pow2Mod)
{ {
q0.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3); q0.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
var ra = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5); var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
pow2Kernel(stream, currentSize, exponent, twoPGpu, (GpuUInt128)kStart, last, divMul, pow2Kernel(stream, currentSize, exponent, twoPGpu, (GpuUInt128)kStart, last, divMul,
ra, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven, kernelArgs, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven,
primeViews.LastOnePow2, primeViews.LastSevenPow2); primeViews.LastOnePow2, primeViews.LastSevenPow2);
} }
else else
@@ -25,6 +25,12 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
}; };
var foundBuffer = accelerator.Allocate1D<int>(1); var foundBuffer = accelerator.Allocate1D<int>(1);
UInt128 exponent128 = exponent;
exponent128.Mod10_8_5_3(out ulong exponentMod10, out ulong exponentMod8, out ulong exponentMod5, out ulong exponentMod3);
ulong step10 = (exponentMod10 << 1) % 10UL;
ulong step8 = (exponentMod8 << 1) & 7UL;
ulong step3 = (exponentMod3 << 1) % 3UL;
ulong step5 = (exponentMod5 << 1) % 5UL;
try try
{ {
UInt128 remaining; UInt128 remaining;
@@ -37,21 +43,14 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
foundBuffer.MemSetToZero(); foundBuffer.MemSetToZero();
// Precompute residue automaton bases for this batch // Precompute residue automaton bases for this batch
UInt128 q0 = twoP * kStart + 1UL; UInt128 q0 = twoP * kStart + 1UL;
ulong q0m10 = q0.Mod10(); q0.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
ulong q0m8 = q0.Mod8(); var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
ulong q0m3 = q0.Mod3();
ulong q0m5 = q0.Mod5();
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
var ra = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
// Ensure device has small cycles table for early rejections in order kernels // Ensure device has small cycles table for early rejections in order kernels
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator); var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
kernel(stream, currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul, kernel(stream, currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
ra, foundBuffer.View, smallCyclesView); kernelArgs, foundBuffer.View, smallCyclesView);
stream.Synchronize(); stream.Synchronize();
foundBuffer.View.CopyToCPU(ref found, 1); foundBuffer.View.CopyToCPU(ref found, 1);
@@ -20,74 +20,89 @@ public class MersenneNumberResidueGpuTester(bool useGpuOrder)
// Ensure device has small cycles and primes tables for in-kernel lookup // Ensure device has small cycles and primes tables for in-kernel lookup
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator); var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
ResiduePrimeViews primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(accelerator); ResiduePrimeViews primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(accelerator);
int batchSize = GpuConstants.ScanBatchSize; int batchSize = GpuConstants.ScanBatchSize;
UInt128 kStart = 1UL; UInt128 kStart = 1UL;
byte last = lastIsSeven ? (byte)1 : (byte)0; byte last = lastIsSeven ? (byte)1 : (byte)0;
var kernel = gpuLease.Pow2ModKernel; var kernel = gpuLease.Pow2ModKernel;
ulong step10 = ((exponent % 10UL) << 1) % 10UL; UInt128 exponent128 = exponent;
ulong step8 = ((exponent & 7UL) << 1) & 7UL; exponent128.Mod10_8_5_3(out ulong exponentMod10, out ulong exponentMod8, out ulong exponentMod5, out ulong exponentMod3);
ulong step3 = ((exponent % 3UL) << 1) % 3UL; ulong step10 = (exponentMod10 << 1) % 10UL;
ulong step5 = ((exponent % 5UL) << 1) % 5UL; ulong step8 = (exponentMod8 << 1) & 7UL;
GpuUInt128 twoPGpu = (GpuUInt128)twoP; ulong step3 = (exponentMod3 << 1) % 3UL;
ulong step5 = (exponentMod5 << 1) % 5UL;
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize); var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
// Device memory returned by Allocate1D is not guaranteed to be zeroed. // Device memory returned by Allocate1D is not guaranteed to be zeroed.
// Ensure the buffer starts with a known state so that lanes skipped by the // Ensure the buffer starts with a known state so that lanes skipped by the
// kernel (for example due to early rejections) do not leave stale garbage // kernel (for example due to early rejections) do not leave stale garbage
// values that would be interpreted as composite witnesses when copied back // values that would be interpreted as composite witnesses when copied back
// to the host. This mirrors the explicit zeroing performed by other GPU // to the host. This mirrors the explicit zeroing performed by other GPU
// testers such as the order kernels. // testers such as the order kernels.
orderBuffer.MemSetToZero(); orderBuffer.MemSetToZero();
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize); ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
UInt128 remaining; UInt128 batchSize128 = (UInt128)batchSize;
int currentSize; UInt128 fullBatchStep = twoP * batchSize128;
int i; UInt128 q = twoP * kStart + UInt128.One;
UInt128 batchSize128 = (UInt128)batchSize, q;
Span<ulong> orders = orderArray.AsSpan(0, batchSize);
ref var ordersRef = ref MemoryMarshal.GetReference(orders);
while (kStart < maxK && Volatile.Read(ref isPrime))
{
remaining = maxK - kStart;
if (remaining > batchSize128)
{
currentSize = batchSize;
}
else
{
currentSize = (int)remaining;
orders = orderArray.AsSpan(0, currentSize);
ordersRef = ref MemoryMarshal.GetReference(orders);
}
q = twoP * kStart + UInt128.One; try
q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3); {
var ra = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5); while (kStart < maxK && Volatile.Read(ref isPrime))
{
UInt128 remaining = maxK - kStart;
int currentSize = remaining > batchSize128 ? batchSize : (int)remaining;
Span<ulong> orders = orderArray.AsSpan(0, currentSize);
ref ulong ordersRef = ref MemoryMarshal.GetReference(orders);
kernel(stream, currentSize, exponent, twoPGpu, (GpuUInt128)kStart, last, 0UL, q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
ra, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven, primeViews.LastOnePow2, primeViews.LastSevenPow2); var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
accelerator.Synchronize(); kernel(stream, currentSize, exponent, twoPGpu, (GpuUInt128)kStart, last, 0UL,
orderBuffer.View.CopyToCPU(ref ordersRef, currentSize); kernelArgs, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven, primeViews.LastOnePow2, primeViews.LastSevenPow2);
if (!Volatile.Read(ref isPrime))
{
break;
}
for (i = 0; i < currentSize; i++) accelerator.Synchronize();
{ orderBuffer.View.CopyToCPU(ref ordersRef, currentSize);
if (orders[i] != 0UL) if (!Volatile.Read(ref isPrime))
{ {
Volatile.Write(ref isPrime, false); break;
goto cleanup; }
}
}
kStart += batchSize128; bool compositeFound = false;
} for (int i = 0; i < currentSize; i++)
{
if (orders[i] != 0UL)
{
Volatile.Write(ref isPrime, false);
compositeFound = true;
break;
}
}
cleanup: if (compositeFound)
ArrayPool<ulong>.Shared.Return(orderArray); {
orderBuffer.Dispose(); break;
gpuLease.Dispose(); }
}
UInt128 processed = (UInt128)currentSize;
kStart += processed;
if (kStart < maxK)
{
if (processed == batchSize128)
{
q += fullBatchStep;
}
else
{
q += twoP * processed;
}
}
}
}
finally
{
ArrayPool<ulong>.Shared.Return(orderArray);
orderBuffer.Dispose();
gpuLease.Dispose();
}
}
} }