From 850efcfc315e6eed2bfca1562138ed18b2abbafc Mon Sep 17 00:00:00 2001 From: Dmitry Markhovskiy Date: Thu, 10 Jul 2025 20:42:20 +0200 Subject: [PATCH 1/3] Improve LRU performance 1. ``` class Pair``` replaced with ```struct Pair``` 2. `ValueRef` used instead of `Value` in the `LinkedListNode`. The performance gain is up to 5% (on small numbers no gain or a minor loss), memory gain is up to 23%. --- bench/algorithm/lru/2.cs | 98 ++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/bench/algorithm/lru/2.cs b/bench/algorithm/lru/2.cs index e57940d93..614af2451 100644 --- a/bench/algorithm/lru/2.cs +++ b/bench/algorithm/lru/2.cs @@ -32,65 +32,67 @@ public static void Main(string[] args) } } -public class Pair +public struct Pair { - public TK Key; + public TK Key; - public TV Value; + public TV Value; } public class LRU + where TK : notnull + where TV : notnull { - public int Size { get; private set; } + public int Size { get; private set; } - private readonly Dictionary>> _key_lookup; + private readonly Dictionary>> _key_lookup; - private readonly LinkedList> _entries; + private readonly LinkedList> _entries; - public LRU(int size) - { - Size = size; - _key_lookup = new Dictionary>>(size); - _entries = new LinkedList>(); - } + public LRU(int size) + { + Size = size; + _key_lookup = new Dictionary>>(size); + _entries = new LinkedList>(); + } - public bool TryGet(TK key, out TV value) - { - if (_key_lookup.TryGetValue(key, out var node)) - { - value = node.Value.Value; - _entries.Remove(node); - _entries.AddLast(node); - return true; - } - value = default; - return false; - } + public bool TryGet(TK key, out TV value) + { + if (_key_lookup.TryGetValue(key, out var node)) + { + value = node.ValueRef.Value; + _entries.Remove(node); + _entries.AddLast(node); + return true; + } + value = default; + return false; + } - public void Put(TK key, TV value) - { - if (_key_lookup.TryGetValue(key, out var node)) - { - node.Value.Value = value; - _entries.Remove(node); - _entries.AddLast(node); - } - else if (_entries.Count == Size) - { - var first = _entries.First; - _key_lookup.Remove(first.Value.Key); - _entries.RemoveFirst(); - first.Value.Key = key; - first.Value.Value = value; - _entries.AddLast(first); - _key_lookup[key] = first; - } - else - { - _entries.AddLast(new Pair { Key = key, Value = value }); - _key_lookup[key] = _entries.Last; - } - } + public void Put(TK key, TV value) + { + if (_key_lookup.TryGetValue(key, out var node)) + { + node.ValueRef.Value = value; + _entries.Remove(node); + _entries.AddLast(node); + } + else if (_entries.Count == Size) + { + var first = _entries.First; + _key_lookup.Remove(first!.Value.Key); + _entries.RemoveFirst(); + first.ValueRef.Key = key; + first.ValueRef.Value = value; + _entries.AddLast(first); + _key_lookup[key] = first; + } + else + { + _entries.AddLast(new Pair { Key = key, Value = value }); + _key_lookup[key] = _entries.Last; + } + } } public class LCG From 1d0da1c45af3c9a068de3a865d4c55a871d01b9d Mon Sep 17 00:00:00 2001 From: Dmitry Markhovskiy Date: Sun, 27 Jul 2025 19:37:22 +0200 Subject: [PATCH 2/3] Indentation fix Fixed indentation --- bench/algorithm/lru/2.cs | 101 +++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/bench/algorithm/lru/2.cs b/bench/algorithm/lru/2.cs index 614af2451..5d2d66716 100644 --- a/bench/algorithm/lru/2.cs +++ b/bench/algorithm/lru/2.cs @@ -33,66 +33,63 @@ public static void Main(string[] args) } public struct Pair -{ - public TK Key; - +{ + public TK Key; public TV Value; } public class LRU - where TK : notnull - where TV : notnull + where TK : notnull + where TV : notnull { - public int Size { get; private set; } - - private readonly Dictionary>> _key_lookup; + public int Size { get; private set; } + private readonly Dictionary>> _key_lookup; + private readonly LinkedList> _entries; - private readonly LinkedList> _entries; - - public LRU(int size) - { - Size = size; - _key_lookup = new Dictionary>>(size); - _entries = new LinkedList>(); - } + public LRU(int size) + { + Size = size; + _key_lookup = new Dictionary>>(size); + _entries = new LinkedList>(); + } - public bool TryGet(TK key, out TV value) - { - if (_key_lookup.TryGetValue(key, out var node)) - { - value = node.ValueRef.Value; - _entries.Remove(node); - _entries.AddLast(node); - return true; - } - value = default; - return false; - } + public bool TryGet(TK key, out TV value) + { + if (_key_lookup.TryGetValue(key, out var node)) + { + value = node.ValueRef.Value; + _entries.Remove(node); + _entries.AddLast(node); + return true; + } + value = default; + return false; + } - public void Put(TK key, TV value) - { - if (_key_lookup.TryGetValue(key, out var node)) - { - node.ValueRef.Value = value; - _entries.Remove(node); - _entries.AddLast(node); - } - else if (_entries.Count == Size) - { - var first = _entries.First; - _key_lookup.Remove(first!.Value.Key); - _entries.RemoveFirst(); - first.ValueRef.Key = key; - first.ValueRef.Value = value; - _entries.AddLast(first); - _key_lookup[key] = first; - } - else - { - _entries.AddLast(new Pair { Key = key, Value = value }); - _key_lookup[key] = _entries.Last; - } - } + public void Put(TK key, TV value) + { + if (_key_lookup.TryGetValue(key, out var node)) + { + node.ValueRef.Value = value; + _entries.Remove(node); + _entries.AddLast(node); + } + else if (_entries.Count == Size) + { + var first = _entries.First; + _key_lookup.Remove(first!.Value.Key); + _entries.RemoveFirst(); + first.ValueRef.Key = key; + first.ValueRef.Value = value; + _entries.AddLast(first); + _key_lookup[key] = first; + } + else + { + _entries.AddLast(new Pair { Key = key, Value = value }); + _key_lookup[key] = _entries.Last; + } + } } public class LCG From 6ba151a960f08f9b12c8e7bb088f40bee1adf118 Mon Sep 17 00:00:00 2001 From: Dmitry Markhovskiy Date: Mon, 28 Jul 2025 15:55:56 +0200 Subject: [PATCH 3/3] Fix build Avoid using ValueRef with older framework versions. --- bench/algorithm/lru/2.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bench/algorithm/lru/2.cs b/bench/algorithm/lru/2.cs index 5d2d66716..a2ca0afb0 100644 --- a/bench/algorithm/lru/2.cs +++ b/bench/algorithm/lru/2.cs @@ -57,7 +57,11 @@ public bool TryGet(TK key, out TV value) { if (_key_lookup.TryGetValue(key, out var node)) { +#if NET5_0_OR_GREATER value = node.ValueRef.Value; +#else + value = node.Value.Value; +#endif _entries.Remove(node); _entries.AddLast(node); return true;