make sure standardstrategy is inlined

huge performance benefits. no seriously.  quite spectacular
This commit is contained in:
Linus Björnstam 2026-04-24 19:42:53 +02:00
parent a54b17167e
commit c363cae136
2 changed files with 34 additions and 12 deletions

View file

@ -35,3 +35,19 @@ public readonly struct StandardStrategy<K> : IKeyStrategy<K>
return _comparer.Compare(x, y); return _comparer.Compare(x, y);
} }
} }
public readonly struct StandardStrategy2<K, TComparer> : IKeyStrategy<K>
where TComparer : struct, IComparer<K>
{
private readonly TComparer _comparer;
public StandardStrategy2(TComparer comparer) => _comparer = comparer;
public bool UsesPrefixes => false;
public bool UseBinarySearch => true;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Compare(K x, K y) => _comparer.Compare(x, y);
public long GetPrefix(K key) => 0;
}

View file

@ -5,9 +5,15 @@ using System.Linq;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using LanguageExt; using LanguageExt;
using PersistentMap; using PersistentMap;
using System.Runtime.CompilerServices;
namespace MapBenchmarks; namespace MapBenchmarks;
public readonly struct OrdinalComparer : IComparer<string>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Compare(string? x, string? y) => string.CompareOrdinal(x, y);
}
[MemoryDiagnoser] [MemoryDiagnoser]
public class StringMapBenchmarks public class StringMapBenchmarks
{ {
@ -28,10 +34,10 @@ public class StringMapBenchmarks
private LanguageExt.Map<string, int> _extMap; private LanguageExt.Map<string, int> _extMap;
private LanguageExt.HashMap<string, int> _extHashMap; private LanguageExt.HashMap<string, int> _extHashMap;
private PersistentMap<string, int, StandardStrategy<string>> _persistentMapStandard; private PersistentMap<string, int, StandardStrategy2<string, OrdinalComparer>> _persistentMapStandard;
private PersistentMap<string, int, UnicodeStrategy> _persistentMapUnicode; private PersistentMap<string, int, UnicodeStrategy> _persistentMapUnicode;
private readonly StandardStrategy<string> _stdStrategy = new StandardStrategy<string>(); private readonly StandardStrategy2<string, OrdinalComparer> _stdStrategy = new StandardStrategy2<string, OrdinalComparer>(new OrdinalComparer());
private readonly UnicodeStrategy _uniStrategy = new UnicodeStrategy(); private readonly UnicodeStrategy _uniStrategy = new UnicodeStrategy();
[GlobalSetup] [GlobalSetup]
@ -71,7 +77,7 @@ public class StringMapBenchmarks
_extHashMap = _extHashMap.AddOrUpdate(_allKeys[i], i); _extHashMap = _extHashMap.AddOrUpdate(_allKeys[i], i);
} }
var transStd = BaseOrderedMap<string, int, StandardStrategy<string>>.CreateTransient(_stdStrategy); var transStd = BaseOrderedMap<string, int, StandardStrategy2<string,OrdinalComparer>>.CreateTransient(_stdStrategy);
var transUni = BaseOrderedMap<string, int, UnicodeStrategy>.CreateTransient(_uniStrategy); var transUni = BaseOrderedMap<string, int, UnicodeStrategy>.CreateTransient(_uniStrategy);
for (int i = 0; i < _allKeys.Length; i++) for (int i = 0; i < _allKeys.Length; i++)
{ {
@ -91,9 +97,9 @@ public class StringMapBenchmarks
// --- 1. BUILD --- // --- 1. BUILD ---
[Benchmark] [Benchmark]
public PersistentMap<string, int, StandardStrategy<string>> Build_TransientMap_Standard() public PersistentMap<string, int, StandardStrategy2<string,OrdinalComparer>> Build_TransientMap_Standard()
{ {
var map = BaseOrderedMap<string, int, StandardStrategy<string>>.CreateTransient(_stdStrategy); var map = BaseOrderedMap<string, int, StandardStrategy2<string,OrdinalComparer>>.CreateTransient(_stdStrategy);
for (int i = 0; i < _allKeys.Length; i++) map.Set(_allKeys[i], i); for (int i = 0; i < _allKeys.Length; i++) map.Set(_allKeys[i], i);
return map.ToPersistent(); return map.ToPersistent();
} }
@ -207,7 +213,7 @@ public class StringMapBenchmarks
} }
[Benchmark] [Benchmark]
public PersistentMap<string, int, StandardStrategy<string>> Update_PersistentMap_Standard() public PersistentMap<string, int, StandardStrategy2<string, OrdinalComparer>> Update_PersistentMap_Standard()
{ {
var map = _persistentMapStandard; var map = _persistentMapStandard;
foreach (var k in _updateKeys) map = map.Set(k, 999); foreach (var k in _updateKeys) map = map.Set(k, 999);
@ -222,7 +228,7 @@ public class StringMapBenchmarks
} }
[Benchmark] [Benchmark]
public PersistentMap<string, int, StandardStrategy<string>> Update_TransientMap_Standard() public PersistentMap<string, int, StandardStrategy2<string, OrdinalComparer>> Update_TransientMap_Standard()
{ {
var transient = _persistentMapStandard.ToTransient(); var transient = _persistentMapStandard.ToTransient();
foreach (var k in _updateKeys) transient.Set(k, 999); foreach (var k in _updateKeys) transient.Set(k, 999);
@ -272,7 +278,7 @@ public class StringMapBenchmarks
} }
[Benchmark] [Benchmark]
public PersistentMap<string, int, StandardStrategy<string>> UpdateSet_PersistentMap_Standard() public PersistentMap<string, int, StandardStrategy2<string, OrdinalComparer>> UpdateSet_PersistentMap_Standard()
{ {
var map = _persistentMapStandard; var map = _persistentMapStandard;
foreach (var k in _mixedKeys) map = map.Set(k, 999); foreach (var k in _mixedKeys) map = map.Set(k, 999);
@ -288,7 +294,7 @@ public class StringMapBenchmarks
} }
[Benchmark] [Benchmark]
public PersistentMap<string, int, StandardStrategy<string>> UpdateSet_TransientMap_Standard() public PersistentMap<string, int, StandardStrategy2<string, OrdinalComparer>> UpdateSet_TransientMap_Standard()
{ {
var transient = _persistentMapStandard.ToTransient(); var transient = _persistentMapStandard.ToTransient();
foreach (var k in _mixedKeys) transient.Set(k, 999); foreach (var k in _mixedKeys) transient.Set(k, 999);
@ -388,7 +394,7 @@ public class StringMapBenchmarks
} }
[Benchmark] [Benchmark]
public PersistentMap<string, int, StandardStrategy<string>> Remove_PersistentMap_Standard() public PersistentMap<string, int, StandardStrategy2<string, OrdinalComparer>> Remove_PersistentMap_Standard()
{ {
var map = _persistentMapStandard; var map = _persistentMapStandard;
foreach (var k in _removeKeys) map = map.Remove(k); foreach (var k in _removeKeys) map = map.Remove(k);
@ -404,7 +410,7 @@ public class StringMapBenchmarks
} }
[Benchmark] [Benchmark]
public PersistentMap<string, int, StandardStrategy<string>> Remove_TransientMap_Standard() public PersistentMap<string, int, StandardStrategy2<string, OrdinalComparer>> Remove_TransientMap_Standard()
{ {
var transient = _persistentMapStandard.ToTransient(); var transient = _persistentMapStandard.ToTransient();
foreach (var k in _removeKeys) transient.Remove(k); foreach (var k in _removeKeys) transient.Remove(k);