-
Notifications
You must be signed in to change notification settings - Fork 431
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
255 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
src/Nethermind/Nethermind.Benchmark/Core/PreviousLruCache.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.CompilerServices; | ||
|
||
using Nethermind.Core.Caching; | ||
using Nethermind.Core; | ||
|
||
namespace Nethermind.Benchmarks.Core; | ||
|
||
public class PreviousLruCache<TKey, TValue> : ICache<TKey, TValue> where TKey : notnull | ||
{ | ||
private readonly int _maxCapacity; | ||
private readonly Dictionary<TKey, LinkedListNode<LruCacheItem>> _cacheMap; | ||
private readonly LinkedList<LruCacheItem> _lruList; | ||
|
||
public PreviousLruCache(int maxCapacity, int startCapacity, string name) | ||
{ | ||
if (maxCapacity < 1) | ||
{ | ||
throw new ArgumentOutOfRangeException(); | ||
} | ||
|
||
_maxCapacity = maxCapacity; | ||
_cacheMap = typeof(TKey) == typeof(byte[]) | ||
? new Dictionary<TKey, LinkedListNode<LruCacheItem>>((IEqualityComparer<TKey>)Nethermind.Core.Extensions.Bytes.EqualityComparer) | ||
: new Dictionary<TKey, LinkedListNode<LruCacheItem>>(startCapacity); // do not initialize it at the full capacity | ||
_lruList = new LinkedList<LruCacheItem>(); | ||
} | ||
|
||
public PreviousLruCache(int maxCapacity, string name) | ||
: this(maxCapacity, 0, name) | ||
{ | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.Synchronized)] | ||
public void Clear() | ||
{ | ||
_cacheMap.Clear(); | ||
_lruList.Clear(); | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.Synchronized)] | ||
public TValue Get(TKey key) | ||
{ | ||
if (_cacheMap.TryGetValue(key, out LinkedListNode<LruCacheItem>? node)) | ||
{ | ||
TValue value = node.Value.Value; | ||
_lruList.Remove(node); | ||
_lruList.AddLast(node); | ||
return value; | ||
} | ||
|
||
#pragma warning disable 8603 | ||
// fixed C# 9 | ||
return default; | ||
#pragma warning restore 8603 | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.Synchronized)] | ||
public bool TryGet(TKey key, out TValue value) | ||
{ | ||
if (_cacheMap.TryGetValue(key, out LinkedListNode<LruCacheItem>? node)) | ||
{ | ||
value = node.Value.Value; | ||
_lruList.Remove(node); | ||
_lruList.AddLast(node); | ||
return true; | ||
} | ||
|
||
#pragma warning disable 8601 | ||
// fixed C# 9 | ||
value = default; | ||
#pragma warning restore 8601 | ||
return false; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.Synchronized)] | ||
public bool Set(TKey key, TValue val) | ||
{ | ||
if (val is null) | ||
{ | ||
return Delete(key); | ||
} | ||
|
||
if (_cacheMap.TryGetValue(key, out LinkedListNode<LruCacheItem>? node)) | ||
{ | ||
node.Value.Value = val; | ||
_lruList.Remove(node); | ||
_lruList.AddLast(node); | ||
return false; | ||
} | ||
else | ||
{ | ||
if (_cacheMap.Count >= _maxCapacity) | ||
{ | ||
Replace(key, val); | ||
} | ||
else | ||
{ | ||
LruCacheItem cacheItem = new LruCacheItem(key, val); | ||
LinkedListNode<LruCacheItem> newNode = new LinkedListNode<LruCacheItem>(cacheItem); | ||
_lruList.AddLast(newNode); | ||
_cacheMap.Add(key, newNode); | ||
} | ||
|
||
return true; | ||
} | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.Synchronized)] | ||
public bool Delete(TKey key) | ||
{ | ||
if (_cacheMap.TryGetValue(key, out LinkedListNode<LruCacheItem>? node)) | ||
{ | ||
_lruList.Remove(node); | ||
_cacheMap.Remove(key); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
[MethodImpl(MethodImplOptions.Synchronized)] | ||
public bool Contains(TKey key) => _cacheMap.ContainsKey(key); | ||
|
||
[MethodImpl(MethodImplOptions.Synchronized)] | ||
public IDictionary<TKey, TValue> Clone() => _lruList.ToDictionary(i => i.Key, i => i.Value); | ||
|
||
private void Replace(TKey key, TValue value) | ||
{ | ||
LinkedListNode<LruCacheItem>? node = _lruList.First; | ||
_lruList.RemoveFirst(); | ||
_cacheMap.Remove(node!.Value.Key); | ||
|
||
node.Value.Value = value; | ||
node.Value.Key = key; | ||
_lruList.AddLast(node); | ||
_cacheMap.Add(key, node); | ||
} | ||
|
||
private class LruCacheItem | ||
{ | ||
public LruCacheItem(TKey k, TValue v) | ||
{ | ||
Key = k; | ||
Value = v; | ||
} | ||
|
||
public TKey Key; | ||
public TValue Value; | ||
} | ||
|
||
public long MemorySize => CalculateMemorySize(0, _cacheMap.Count); | ||
|
||
public static long CalculateMemorySize(int keyPlusValueSize, int currentItemsCount) | ||
{ | ||
// it may actually be different if the initial capacity not equal to max (depending on the dictionary growth path) | ||
|
||
const int preInit = 48 /* LinkedList */ + 80 /* Dictionary */ + 24; | ||
int postInit = 52 /* lazy init of two internal dictionary arrays + dictionary size times (entry size + int) */ + MemorySizes.FindNextPrime(currentItemsCount) * 28 + currentItemsCount * 80 /* LinkedListNode and CacheItem times items count */; | ||
return MemorySizes.Align(preInit + postInit + keyPlusValueSize * currentItemsCount); | ||
} | ||
} |