Avoid pooling small buffers in CPU divisor pipeline

This commit is contained in:
Marek Lemańczyk committed 2025-10-11 21:17:18 +02:00
1 parent 8e9390bc5e
commit ad22329814
4 files changed
+102 -41

No files matched your search

+37 -24
View File
@@ -1,19 +1,26 @@
using System;
using System.Buffers;
namespace PerfectNumbers.Core
{
public sealed class PartialFactorResult
{
[ThreadStatic]
private static PartialFactorResult? s_poolHead;
[ThreadStatic]
private static PartialFactorResult? s_poolHead;
public static readonly PartialFactorResult Empty = new()
{
Cofactor = 1UL,
FullyFactored = true,
};
public FactorEntry[]? Factors;
private PartialFactorResult? _next;
public ulong Cofactor;
public bool FullyFactored;
public int Count;
private PartialFactorResult? _next;
private bool _factorsFromPool;
private PartialFactorResult()
{
}
@@ -30,52 +37,58 @@ namespace PerfectNumbers.Core
s_poolHead = instance._next;
}
FactorEntry[]? factorArray = factors;
instance._next = null;
instance.Factors = factors;
instance.Factors = factorArray;
instance.Cofactor = cofactor;
instance.FullyFactored = fullyFactored;
instance.Count = count;
instance._factorsFromPool = factorArray is not null && factorArray.Length >= PerfectNumberConstants.PooledArrayThreshold;
return instance;
}
public static readonly PartialFactorResult Empty = new()
{
Cofactor = 1UL,
FullyFactored = true,
};
public PartialFactorResult WithAdditionalPrime(ulong prime)
{
FactorEntry[]? source = Factors;
if (source is null || Count == 0)
{
FactorEntry[] local = ThreadLocalArrayPool<FactorEntry>.Shared.Rent(1);
local[0] = new FactorEntry(prime);
return Rent(local, 1UL, true, 1);
FactorEntry[] single = new FactorEntry[1];
single[0] = new FactorEntry(prime);
return Rent(single, 1UL, true, 1);
}
FactorEntry[] extended = ThreadLocalArrayPool<FactorEntry>.Shared.Rent(Count + 1);
int newCount = Count + 1;
FactorEntry[] extended = newCount >= PerfectNumberConstants.PooledArrayThreshold
? ThreadLocalArrayPool<FactorEntry>.Shared.Rent(newCount)
: new FactorEntry[newCount];
Array.Copy(source, 0, extended, 0, Count);
extended[Count] = new FactorEntry(prime);
Span<FactorEntry> span = extended.AsSpan(0, Count + 1);
Span<FactorEntry> span = extended.AsSpan(0, newCount);
span.Sort(static (a, b) => a.Value.CompareTo(b.Value));
return Rent(extended, 1UL, true, Count + 1);
return Rent(extended, 1UL, true, newCount);
}
public void Dispose()
{
if (this != Empty)
if (this == Empty)
{
FactorEntry[]? factors = Factors;
if (factors is not null)
return;
}
FactorEntry[]? factors = Factors;
if (factors is not null)
{
Factors = null;
if (_factorsFromPool)
{
Factors = null;
ThreadLocalArrayPool<FactorEntry>.Shared.Return(factors, clearArray: false);
}
_next = s_poolHead;
s_poolHead = this;
}
_factorsFromPool = false;
_next = s_poolHead;
s_poolHead = this;
}
}
}