Merge pull request #52 from mlemanczyk/codex/optimize-mersennenumberresiduegputester.scan-method
Restore struct residue args and add benchmarking project
This commit is contained in:
10 files changed
+326
-165
No files matched your search
Vendored
+31
-3
@@ -7,7 +7,8 @@
|
||||
"description": "Select project to run",
|
||||
"options": [
|
||||
"EvenPerfectBitScanner",
|
||||
"EvenPerfectBitScanner.ResultsParser"
|
||||
"EvenPerfectBitScanner.ResultsParser",
|
||||
"EvenPerfectBitScanner.Benchmarks"
|
||||
],
|
||||
"default": "EvenPerfectBitScanner"
|
||||
}
|
||||
@@ -20,7 +21,7 @@
|
||||
"preLaunchTask": "Build Debug",
|
||||
"program": "${workspaceFolder}/${input:projectName}/bin/Debug/net8.0/${input:projectName}.dll",
|
||||
"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}",
|
||||
"stopAtEntry": false,
|
||||
@@ -93,6 +94,33 @@
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+124
-79
@@ -1,66 +1,66 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build Debug",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/EvenPerfectScanner.sln",
|
||||
"--configuration",
|
||||
"Debug",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build Release",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/EvenPerfectScanner.sln",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build EvenPerfectBitScanner Debug",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj",
|
||||
"--configuration",
|
||||
"Debug",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build Debug",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/EvenPerfectScanner.sln",
|
||||
"--configuration",
|
||||
"Debug",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": false
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build Release",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/EvenPerfectScanner.sln",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build EvenPerfectBitScanner Debug",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj",
|
||||
"--configuration",
|
||||
"Debug",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Build EvenPerfectBitScanner Release",
|
||||
"command": "dotnet",
|
||||
"type": "process",
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"args": [
|
||||
"build",
|
||||
"${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
@@ -97,16 +97,16 @@
|
||||
{
|
||||
"label": "Run EvenPerfectBitScanner",
|
||||
"type": "process",
|
||||
"command": "dotnet",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"run",
|
||||
"--project",
|
||||
"${workspaceFolder}/EvenPerfectBitScanner/EvenPerfectBitScanner.csproj",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"--configuration",
|
||||
"Release",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
@@ -124,18 +124,63 @@
|
||||
],
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Run Release (no debug)",
|
||||
"type": "process",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"run",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"label": "Run Release (no debug)",
|
||||
"type": "process",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"run",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"--framework",
|
||||
"net8.0"
|
||||
],
|
||||
"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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Tests
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.ResultsParser", "EvenPerfectBitScanner.ResultsParser\EvenPerfectBitScanner.ResultsParser.csproj", "{B07A718C-A71C-410D-A0D7-FA1674CEB38F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenPerfectBitScanner.Benchmarks", "EvenPerfectBitScanner.Benchmarks\EvenPerfectBitScanner.Benchmarks.csproj", "{83551FCC-41FA-4162-B541-AFCB5666A29F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
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}.Release|Any CPU.ActiveCfg = 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
|
||||
EndGlobal
|
||||
@@ -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
|
||||
{
|
||||
@@ -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
|
||||
{
|
||||
@@ -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,
|
||||
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 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 _,
|
||||
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 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 incKernel = gpuLease.IncrementalKernel;
|
||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||
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;
|
||||
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||
ResiduePrimeViews primeViews = default;
|
||||
@@ -55,9 +57,9 @@ public class MersenneNumberIncrementalGpuTester(GpuKernelType kernelType, bool u
|
||||
if (_kernelType == GpuKernelType.Pow2Mod)
|
||||
{
|
||||
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,
|
||||
ra, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven,
|
||||
kernelArgs, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven,
|
||||
primeViews.LastOnePow2, primeViews.LastSevenPow2);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -25,6 +25,12 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
UInt128 remaining;
|
||||
@@ -37,21 +43,14 @@ public class MersenneNumberOrderGpuTester(GpuKernelType kernelType, bool useGpuO
|
||||
foundBuffer.MemSetToZero();
|
||||
// Precompute residue automaton bases for this batch
|
||||
UInt128 q0 = twoP * kStart + 1UL;
|
||||
ulong q0m10 = q0.Mod10();
|
||||
ulong q0m8 = q0.Mod8();
|
||||
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);
|
||||
q0.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
||||
var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
||||
|
||||
|
||||
// Ensure device has small cycles table for early rejections in order kernels
|
||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||
kernel(stream, currentSize, exponent, (GpuUInt128)twoP, (GpuUInt128)kStart, last, divMul,
|
||||
ra, foundBuffer.View, smallCyclesView);
|
||||
kernelArgs, foundBuffer.View, smallCyclesView);
|
||||
|
||||
stream.Synchronize();
|
||||
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
|
||||
var smallCyclesView = GpuKernelPool.EnsureSmallCyclesOnDevice(accelerator);
|
||||
ResiduePrimeViews primeViews = GpuKernelPool.EnsureSmallPrimesOnDevice(accelerator);
|
||||
int batchSize = GpuConstants.ScanBatchSize;
|
||||
UInt128 kStart = 1UL;
|
||||
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
||||
var kernel = gpuLease.Pow2ModKernel;
|
||||
ulong step10 = ((exponent % 10UL) << 1) % 10UL;
|
||||
ulong step8 = ((exponent & 7UL) << 1) & 7UL;
|
||||
ulong step3 = ((exponent % 3UL) << 1) % 3UL;
|
||||
ulong step5 = ((exponent % 5UL) << 1) % 5UL;
|
||||
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
||||
int batchSize = GpuConstants.ScanBatchSize;
|
||||
UInt128 kStart = 1UL;
|
||||
byte last = lastIsSeven ? (byte)1 : (byte)0;
|
||||
var kernel = gpuLease.Pow2ModKernel;
|
||||
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;
|
||||
GpuUInt128 twoPGpu = (GpuUInt128)twoP;
|
||||
|
||||
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||
// 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
|
||||
// kernel (for example due to early rejections) do not leave stale garbage
|
||||
// values that would be interpreted as composite witnesses when copied back
|
||||
// to the host. This mirrors the explicit zeroing performed by other GPU
|
||||
// testers such as the order kernels.
|
||||
orderBuffer.MemSetToZero();
|
||||
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
||||
UInt128 remaining;
|
||||
int currentSize;
|
||||
int i;
|
||||
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);
|
||||
}
|
||||
var orderBuffer = accelerator.Allocate1D<ulong>(batchSize);
|
||||
// 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
|
||||
// kernel (for example due to early rejections) do not leave stale garbage
|
||||
// values that would be interpreted as composite witnesses when copied back
|
||||
// to the host. This mirrors the explicit zeroing performed by other GPU
|
||||
// testers such as the order kernels.
|
||||
orderBuffer.MemSetToZero();
|
||||
ulong[] orderArray = ArrayPool<ulong>.Shared.Rent(batchSize);
|
||||
UInt128 batchSize128 = (UInt128)batchSize;
|
||||
UInt128 fullBatchStep = twoP * batchSize128;
|
||||
UInt128 q = twoP * kStart + UInt128.One;
|
||||
|
||||
q = twoP * kStart + UInt128.One;
|
||||
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);
|
||||
try
|
||||
{
|
||||
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,
|
||||
ra, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven, primeViews.LastOnePow2, primeViews.LastSevenPow2);
|
||||
q.Mod10_8_5_3(out ulong q0m10, out ulong q0m8, out ulong q0m5, out ulong q0m3);
|
||||
var kernelArgs = new ResidueAutomatonArgs(q0m10, step10, q0m8, step8, q0m3, step3, q0m5, step5);
|
||||
|
||||
accelerator.Synchronize();
|
||||
orderBuffer.View.CopyToCPU(ref ordersRef, currentSize);
|
||||
if (!Volatile.Read(ref isPrime))
|
||||
{
|
||||
break;
|
||||
}
|
||||
kernel(stream, currentSize, exponent, twoPGpu, (GpuUInt128)kStart, last, 0UL,
|
||||
kernelArgs, orderBuffer.View, smallCyclesView, primeViews.LastOne, primeViews.LastSeven, primeViews.LastOnePow2, primeViews.LastSevenPow2);
|
||||
|
||||
for (i = 0; i < currentSize; i++)
|
||||
{
|
||||
if (orders[i] != 0UL)
|
||||
{
|
||||
Volatile.Write(ref isPrime, false);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
accelerator.Synchronize();
|
||||
orderBuffer.View.CopyToCPU(ref ordersRef, currentSize);
|
||||
if (!Volatile.Read(ref isPrime))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
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:
|
||||
ArrayPool<ulong>.Shared.Return(orderArray);
|
||||
orderBuffer.Dispose();
|
||||
gpuLease.Dispose();
|
||||
}
|
||||
if (compositeFound)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user