Wsm2110 / Faster.Map

Faster.Map is a high-performance, thread-safe key-value store designed to outperform the standard Dictionary and ConcurrentDictionary
MIT License
75 stars 7 forks source link

Another optimization suggestion for Resize() #16

Closed miroslavp closed 1 year ago

miroslavp commented 1 year ago

This is a bit bold, but works nice for your algorithm. It is up to you if you want to amend it or not. I have noticed that after the allocation of the new metadata array, you immediately initialize it with the emptyBucket value (-127). So basically the array is initialized twice - once with zeros (using new) and then with -127. Also, the entries array is never used in the code without first checking the metadata array (well, except for the IndexOf() method which is for testing purposes, but it also can be amended to make metadata lookups first)

https://github.com/Wsm2110/Faster.Map/blob/9c60000c53e0bad32b9130a5b3297ec9f259e4d2/src/DenseMapSIMD.cs#L762-L765

So basically we can safely allocate both arrays without initializing them to zero (you don't rely on those zeros in the code anyway) using GC.AllocateUninitializedArray. I have tested it and allocation of array of 1_000_000 ints without initialization is about 11 times faster.

 _metadata = GC.AllocateUninitializedArray<sbyte>((int)_length + 16);
 _entries = GC.AllocateUninitializedArray<Entry<TKey, TValue>>((int)_length + 16);

This brings also slight improvement to the final AddAndResize benchmark. Let me know what you think!

P.S. If you don't like that the following line starts with new new Span<sbyte>(_metadata).Fill(_emptyBucket); the following is equivalent _metadata.AsSpan().Fill(_emptyBucket);

miroslavp commented 1 year ago

LOL, I just realized that we don't need to copy/clone those arrays at all https://github.com/Wsm2110/Faster.Map/blob/9c60000c53e0bad32b9130a5b3297ec9f259e4d2/src/DenseMapSIMD.cs#L759-L763 We don't use them anymore. Right on the next line we erase the variables. So we can just copy the references

 var oldEntries = _entries; 
 var oldMetadata = _metadata; 

 _metadata = new sbyte[_length + 16];          
 _entries = new Entry<TKey, TValue>[_length + 16]; 

My suggestion in the previous comment still stands though :)

Wsm2110 commented 1 year ago

hi mate, love these suggestions. Keep'em coming