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",
"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
}
]
}
}
+124 -79
View File
@@ -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);
}
}
+6
View File
@@ -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
+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
{
@@ -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();
}
}
}