Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize cache validation in pow extension. #4

Merged
merged 1 commit into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 31 additions & 42 deletions TheSquid.Numerics.Extensions/PowCachedExtension.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;

Expand All @@ -15,26 +14,31 @@ public static partial class PowCachedExtension
/// <summary>
/// Cach with format: basement, exponent, power, counter.
/// </summary>
private static Dictionary<BigInteger, Dictionary<int, ValueTuple<BigInteger, long>>> powCache;
private static Dictionary<ValueTuple<BigInteger, int>, ValueTuple<BigInteger, long>> powCache;

/// <summary>
/// Cache access synchronization object.
/// </summary>
private static Object syncObject;

/// <summary>
/// Life time counter for shrink data when it is needed.
/// Life time counter for sort items by age.
/// </summary>
public static long ItemsLifetime { get; private set; }
private static long itemsLifetime;

/// <summary>
/// Number of items in the cache.
/// </summary>
public static long ItemsInCache => powCache.LongCount();

/// <summary>
/// Static constuctor.
/// </summary>
static PowCachedExtension()
{
powCache = new Dictionary<BigInteger, Dictionary<int, ValueTuple<BigInteger, long>>>();
powCache = new Dictionary<ValueTuple<BigInteger, int>, ValueTuple<BigInteger, long>>();
syncObject = new Object();
ItemsLifetime = 0;
itemsLifetime = 0;
}

/// <summary>
Expand Down Expand Up @@ -72,12 +76,12 @@ public static BigInteger PowCached(this ref BigInteger basement, int exponent)
{
try
{
if (ItemsLifetime >= int.MaxValue) ShrinkCacheData(ItemsLifetime / 2);
if (itemsLifetime >= int.MaxValue) ShrinkCacheData(powCache.LongCount() / 2);
return CalculateNewValue(ref basement, exponent);
}
catch (OutOfMemoryException)
{
if (powCache.Count > 0) ShrinkCacheData(0);
if (powCache.LongCount() > 0) ShrinkCacheData(0);
return CalculateNewValue(ref basement, exponent);
}
}
Expand All @@ -88,9 +92,10 @@ public static BigInteger PowCached(this ref BigInteger basement, int exponent)
/// </summary>
private static bool TryGetValue(ref BigInteger basement, int exponent, out BigInteger power)
{
if (!powCache.TryGetValue(basement, out var termCache)) return false;
if (!termCache.TryGetValue(exponent, out var itemCache)) return false;
power = itemCache.Item1;
var key = new ValueTuple<BigInteger, int>(basement, exponent);
if (!powCache.TryGetValue(key, out var value)) return false;
value.Item2 = ++itemsLifetime;
power = value.Item1;
return true;
}

Expand All @@ -99,17 +104,9 @@ private static bool TryGetValue(ref BigInteger basement, int exponent, out BigIn
/// </summary>
private static void CacheNewValue(ref BigInteger basement, int exponent, BigInteger power)
{
if (!powCache.TryGetValue(basement, out var termCache))
{
termCache = new Dictionary<int, ValueTuple<BigInteger, long>>();
powCache.Add(basement, termCache);
}
if (!termCache.TryGetValue(exponent, out var itemCache))
{
itemCache = new ValueTuple<BigInteger, long>(power, ++ItemsLifetime);
termCache.Add(exponent, itemCache);
}
else itemCache.Item2 = ++ItemsLifetime;
var key = new ValueTuple<BigInteger, int>(basement, exponent);
var value = new ValueTuple<BigInteger, long>(power, ++itemsLifetime);
powCache.Add(key, value);
}

/// <summary>
Expand All @@ -133,39 +130,31 @@ private static BigInteger CalculateNewValue(ref BigInteger basement, int exponen
/// <summary>
/// Shrink the dataset of cached power values.
/// </summary>
/// <param name="lifetimeLimit">
/// Input lifetime value, all elements less than which will be considered obsolete
/// and removed. Or input a zero to clear the cache completely.
/// <param name="itemsInCache">
/// The number of newest elements left in the cache. Input zero to clear the cache completely.
/// </param>
/// <remarks>
/// Associated lifetime values in the ItemsLifetime property.
/// Associated items count value in the ItemsCount property.
/// </remarks>
public static void ShrinkCacheData(long lifetimeLimit)
public static void ShrinkCacheData(long itemsInCache)
{
lock (syncObject)
{
if (lifetimeLimit == 0)
if (itemsInCache == 0)
{
if (ItemsLifetime == 0) return;
ItemsLifetime = 0;
if (powCache.LongCount() == 0) return;
itemsLifetime = 0;
powCache.Clear();
GC.Collect();
GC.WaitForPendingFinalizers();
Debug.WriteLine($"{nameof(TheSquid.Numerics)}.{nameof(PowCachedExtension)}.{nameof(ShrinkCacheData)}");
}
else
{
var newPowCache = new Dictionary<BigInteger, Dictionary<int, ValueTuple<BigInteger, long>>>();
ItemsLifetime = 0;
foreach (var p in powCache)
{
var newTermCache = p.Value
.Where(t => t.Value.Item2 > lifetimeLimit)
.Select(t => new KeyValuePair<int, ValueTuple<BigInteger, long>>(t.Key, new ValueTuple<BigInteger, long>(t.Value.Item1, ++ItemsLifetime)))
.ToDictionary(t => t.Key, t => t.Value);
if (newTermCache.Count > 0) newPowCache.Add(p.Key, newTermCache);
}
powCache = newPowCache;
itemsLifetime = 0;
powCache = powCache
.OrderBy(p => p.Value.Item2)
.Skip((int)Math.Min(powCache.LongCount() - itemsInCache, int.MaxValue))
.ToDictionary(p => p.Key, p => new ValueTuple<BigInteger, long>(p.Value.Item1, ++itemsLifetime));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<LangVersion>7.3</LangVersion>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageTags>BigInteger;Nth;Root;Random;Cache;Numerics;Extension;Math</PackageTags>
<PackageTags>BigInteger;Nth;Root;Random;Power;Cache;Numerics;Extension;Math</PackageTags>
</PropertyGroup>

<PropertyGroup>
Expand Down