Skip to content

Commit

Permalink
Use TryGetValue to halve Dictionary lookups (#6352)
Browse files Browse the repository at this point in the history
* Use TryGetValue to halve Dictionary lookups

* fixes

* Use CollectionsMarshal.GetValueRefOrAddDefault when appropriate

* Re add comment

* Missed one

* Fix weird check
  • Loading branch information
benaadams committed Dec 14, 2023
1 parent 2749c16 commit f62468e
Show file tree
Hide file tree
Showing 15 changed files with 102 additions and 82 deletions.
13 changes: 6 additions & 7 deletions src/Nethermind/Nethermind.Cli/Modules/CliModuleLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using Jint.Native;
using Jint.Native.Object;
Expand Down Expand Up @@ -89,16 +90,14 @@ private void LoadModule(CliModuleBase module)
throw new InvalidDataException($"Method {methodInfo.Name} of {module.GetType().Name} should be decorated with one of {nameof(CliPropertyAttribute)} or {nameof(CliFunctionAttribute)}");
}

ObjectInstance instance;
if (!_objects.ContainsKey(objectName))
ref ObjectInstance? instance = ref CollectionsMarshal.GetValueRefOrAddDefault(_objects, objectName, out bool exists);
if (!exists)
{
instance = _engine.JintEngine.Object.Construct(Arguments.Empty);
_engine.JintEngine.SetValue(objectName, instance);
_objects[objectName] = instance;
}

instance = _objects[objectName];
var @delegate = CreateDelegate(methodInfo, module);
Delegate @delegate = CreateDelegate(methodInfo, module);
DelegateWrapper nativeDelegate = new DelegateWrapper(_engine.JintEngine, @delegate);

if (itemName is not null)
Expand All @@ -109,15 +108,15 @@ private void LoadModule(CliModuleBase module)
_cliConsole.WriteLine($".{itemName}");

MethodsByModules[objectName].Add(itemName);
AddProperty(instance, itemName, nativeDelegate);
AddProperty(instance!, itemName, nativeDelegate);
}
else
{
_cliConsole.WriteKeyword($" {objectName}");
_cliConsole.WriteLine($".{itemName}({string.Join(", ", methodInfo.GetParameters().Select(p => p.Name))})");

MethodsByModules[objectName].Add(itemName + "(");
AddMethod(instance, itemName, nativeDelegate);
AddMethod(instance!, itemName, nativeDelegate);
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/Nethermind/Nethermind.Cli/NodeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Jint.Native;
using Jint.Native.Json;
Expand Down Expand Up @@ -44,12 +45,13 @@ public NodeManager(ICliEngine cliEngine, IJsonSerializer serializer, ICliConsole
public void SwitchUri(Uri uri)
{
CurrentUri = uri.ToString();
if (!_clients.ContainsKey(uri))
ref IJsonRpcClient? value = ref CollectionsMarshal.GetValueRefOrAddDefault(_clients, uri, out bool exists);
if (!exists)
{
_clients[uri] = new BasicJsonRpcClient(uri, _serializer, _logManager);
value = new BasicJsonRpcClient(uri, _serializer, _logManager);
}

_currentClient = _clients[uri];
_currentClient = value;
}

public void SwitchClient(IJsonRpcClient client)
Expand Down
18 changes: 10 additions & 8 deletions src/Nethermind/Nethermind.Consensus.Clique/SnapshotManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Nethermind.Blockchain;
using Nethermind.Core;
Expand Down Expand Up @@ -274,8 +275,8 @@ private Snapshot Apply(Snapshot original, List<BlockHeader> headers, ulong epoch

// Resolve the authorization key and check against signers
Address signer = header.Author;
if (!snapshot.Signers.ContainsKey(signer)) throw new InvalidOperationException("Unauthorized signer");
if (HasSignedRecently(snapshot, number, signer)) throw new InvalidOperationException($"Recently signed (trying to sign {number} when last signed {snapshot.Signers[signer]} with {snapshot.Signers.Count} signers)");
if (!snapshot.Signers.TryGetValue(signer, out var value)) throw new InvalidOperationException("Unauthorized signer");
if (HasSignedRecently(snapshot, number, signer)) throw new InvalidOperationException($"Recently signed (trying to sign {number} when last signed {value} with {snapshot.Signers.Count} signers)");

snapshot.Signers[signer] = number;

Expand Down Expand Up @@ -353,25 +354,26 @@ private Snapshot Apply(Snapshot original, List<BlockHeader> headers, ulong epoch

private bool Cast(Snapshot snapshot, Address address, bool authorize)
{
if (!snapshot.Tally.ContainsKey(address))
ref Tally? value = ref CollectionsMarshal.GetValueRefOrAddDefault(snapshot.Tally, address, out bool exists);
if (!exists)
{
snapshot.Tally[address] = new Tally(authorize);
value = new Tally(authorize);
}

// Ensure the vote is meaningful
if (!IsValidVote(snapshot, address, authorize)) return false;

// Cast the vote into tally
snapshot.Tally[address].Votes++;
// Cast the vote into tally ref
value.Votes++;
return true;
}

private bool Uncast(Snapshot snapshot, Address address, bool authorize)
{
// If there's no tally, it's a dangling vote, just drop
if (!snapshot.Tally.ContainsKey(address)) return true;
if (!snapshot.Tally.TryGetValue(address, out Tally? value)) return true;

Tally tally = snapshot.Tally[address];
Tally tally = value;
// Ensure we only revert counted votes
if (tally.Authorize != authorize) return false;

Expand Down
22 changes: 12 additions & 10 deletions src/Nethermind/Nethermind.Consensus.Ethash/HintBasedCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Nethermind.Logging;
Expand Down Expand Up @@ -55,12 +56,13 @@ public void Hint(Guid guid, long start, long end)
throw new InvalidOperationException("Hint too wide");
}

if (!_epochsPerGuid.ContainsKey(guid))
ref HashSet<uint>? value = ref CollectionsMarshal.GetValueRefOrAddDefault(_epochsPerGuid, guid, out bool exists);
if (!exists)
{
_epochsPerGuid[guid] = new HashSet<uint>();
value = new HashSet<uint>();
}

HashSet<uint> epochForGuid = _epochsPerGuid[guid];
HashSet<uint> epochForGuid = value;
uint currentMin = uint.MaxValue;
uint currentMax = 0;
foreach (uint alreadyCachedEpoch in epochForGuid.ToList())
Expand All @@ -78,12 +80,12 @@ public void Hint(Guid guid, long start, long end)
if (alreadyCachedEpoch < startEpoch || alreadyCachedEpoch > endEpoch)
{
epochForGuid.Remove(alreadyCachedEpoch);
if (!_epochRefs.ContainsKey(alreadyCachedEpoch))
if (!_epochRefs.TryGetValue(alreadyCachedEpoch, out var epochValue))
{
throw new InvalidAsynchronousStateException("Epoch ref missing");
}

_epochRefs[alreadyCachedEpoch] = _epochRefs[alreadyCachedEpoch] - 1;
_epochRefs[alreadyCachedEpoch] = epochValue - 1;
if (_epochRefs[alreadyCachedEpoch] == 0)
{
// _logger.Warn($"Removing data set for epoch {alreadyCachedEpoch}");
Expand All @@ -99,15 +101,15 @@ public void Hint(Guid guid, long start, long end)
for (long i = startEpoch; i <= endEpoch; i++)
{
uint epoch = (uint)i;
if (!epochForGuid.Contains(epoch))
if (epochForGuid.Add(epoch))
{
epochForGuid.Add(epoch);
if (!_epochRefs.ContainsKey(epoch))
if (!_epochRefs.TryGetValue(epoch, out var epochValue))
{
_epochRefs[epoch] = 0;
epochValue = 0;
_epochRefs[epoch] = epochValue;
}

_epochRefs[epoch] = _epochRefs[epoch] + 1;
_epochRefs[epoch] = epochValue + 1;
if (_epochRefs[epoch] == 1)
{
// _logger.Warn($"Building data set for epoch {epoch}");
Expand Down
12 changes: 6 additions & 6 deletions src/Nethermind/Nethermind.Core/Collections/LinkedHashSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Nethermind.Core.Collections
{
public class LinkedHashSet<T> : ISet<T>, IReadOnlySet<T> where T : notnull
{
private readonly IDictionary<T, LinkedListNode<T>> _dict;
private readonly Dictionary<T, LinkedListNode<T>> _dict;
private readonly LinkedList<T> _list;

public LinkedHashSet(int initialCapacity)
Expand Down Expand Up @@ -71,7 +71,7 @@ public void IntersectWith(IEnumerable<T>? other)

T[] ts = new T[Count];
CopyTo(ts, 0);
ISet<T> set = other.ToHashSet();
HashSet<T> set = other.ToHashSet();
foreach (T t in this.ToArray())
{
if (!set.Contains(t))
Expand Down Expand Up @@ -106,7 +106,7 @@ public bool IsProperSupersetOf(IEnumerable<T>? other)
{
ArgumentNullException.ThrowIfNull(other);

ISet<T> set = other.ToHashSet();
HashSet<T> set = other.ToHashSet();
int otherCount = set.Count;
if (Count > otherCount)
{
Expand Down Expand Up @@ -134,7 +134,7 @@ public bool IsSubsetOf(IEnumerable<T>? other)
{
ArgumentNullException.ThrowIfNull(other);

ISet<T> set = other.ToHashSet();
HashSet<T> set = other.ToHashSet();
return this.All(t => set.Contains(t));
}

Expand Down Expand Up @@ -167,7 +167,7 @@ public void SymmetricExceptWith(IEnumerable<T> other)
T[] ts = new T[Count];
CopyTo(ts, 0);

ISet<T> set = other.ToHashSet();
HashSet<T> set = other.ToHashSet();
for (int index = 0; index < ts.Length; index++)
{
T t = ts[index];
Expand Down Expand Up @@ -201,7 +201,7 @@ public void UnionWith(IEnumerable<T>? other)

public int Count => _dict.Count;

public bool IsReadOnly => _dict.IsReadOnly;
public bool IsReadOnly => false;

void ICollection<T>.Add(T item)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace Nethermind.Core.Resettables
{
Expand Down Expand Up @@ -96,6 +97,11 @@ public bool TryGetValue(TKey key, out TValue value)
#pragma warning restore 8601
}

public ref TValue? GetValueRefOrAddDefault(TKey key, out bool exists)
{
return ref CollectionsMarshal.GetValueRefOrAddDefault(_wrapped, key, out exists);
}

public TValue this[TKey key]
{
get => _wrapped[key];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Extensions;
Expand Down Expand Up @@ -320,16 +321,17 @@ public override void ReportBalanceChange(Address address, UInt256? before, UInt2
throw new InvalidOperationException($"{nameof(ParityLikeTxTracer)} did not expect state change report.");
}

if (!_trace.StateChanges.ContainsKey(address))
ref ParityAccountStateChange? value = ref CollectionsMarshal.GetValueRefOrAddDefault(_trace.StateChanges, address, out bool exists);
if (!exists)
{
_trace.StateChanges[address] = new ParityAccountStateChange();
value = new ParityAccountStateChange();
}
else
{
before = _trace.StateChanges[address].Balance?.Before ?? before;
before = value.Balance?.Before ?? before;
}

_trace.StateChanges[address].Balance = new ParityStateChange<UInt256?>(before, after);
value.Balance = new ParityStateChange<UInt256?>(before, after);
}

public override void ReportCodeChange(Address address, byte[] before, byte[] after)
Expand All @@ -339,48 +341,50 @@ public override void ReportCodeChange(Address address, byte[] before, byte[] aft
throw new InvalidOperationException($"{nameof(ParityLikeTxTracer)} did not expect state change report.");
}

if (!_trace.StateChanges.ContainsKey(address))
ref ParityAccountStateChange? value = ref CollectionsMarshal.GetValueRefOrAddDefault(_trace.StateChanges, address, out bool exists);
if (!exists)
{
_trace.StateChanges[address] = new ParityAccountStateChange();
value = new ParityAccountStateChange();
}
else
{
before = _trace.StateChanges[address].Code?.Before ?? before;
before = value.Code?.Before ?? before;
}

_trace.StateChanges[address].Code = new ParityStateChange<byte[]>(before, after);
value.Code = new ParityStateChange<byte[]>(before, after);
}

public override void ReportNonceChange(Address address, UInt256? before, UInt256? after)
{
if (!_trace.StateChanges!.ContainsKey(address))
ref ParityAccountStateChange? value = ref CollectionsMarshal.GetValueRefOrAddDefault(_trace.StateChanges, address, out bool exists);
if (!exists)
{
_trace.StateChanges[address] = new ParityAccountStateChange();
value = new ParityAccountStateChange();
}
else
{
before = _trace.StateChanges[address].Nonce?.Before ?? before;
before = value.Nonce?.Before ?? before;
}

_trace.StateChanges[address].Nonce = new ParityStateChange<UInt256?>(before, after);
value.Nonce = new ParityStateChange<UInt256?>(before, after);
}

public override void ReportStorageChange(in StorageCell storageCell, byte[] before, byte[] after)
{
if (!_trace.StateChanges!.ContainsKey(storageCell.Address))
ref ParityAccountStateChange? value = ref CollectionsMarshal.GetValueRefOrAddDefault(_trace.StateChanges, storageCell.Address, out bool exists);
if (!exists)
{
_trace.StateChanges[storageCell.Address] = new ParityAccountStateChange();
value = new ParityAccountStateChange();
}

Dictionary<UInt256, ParityStateChange<byte[]>> storage =
_trace.StateChanges[storageCell.Address].Storage ?? (_trace.StateChanges[storageCell.Address].Storage = new Dictionary<UInt256, ParityStateChange<byte[]>>());

if (storage.TryGetValue(storageCell.Index, out ParityStateChange<byte[]> value))
Dictionary<UInt256, ParityStateChange<byte[]>> storage = value.Storage ??= [];
ref ParityStateChange<byte[]>? change = ref CollectionsMarshal.GetValueRefOrAddDefault(storage, storageCell.Index, out exists);
if (exists)
{
before = value.Before ?? before;
before = change.Before ?? before;
}

storage[storageCell.Index] = new ParityStateChange<byte[]>(before, after);
change = new ParityStateChange<byte[]>(before, after);
}

public override void ReportAction(long gas, UInt256 value, Address from, Address to, ReadOnlyMemory<byte> input, ExecutionType callType, bool isPrecompileCall = false)
Expand Down
7 changes: 4 additions & 3 deletions src/Nethermind/Nethermind.Network/P2P/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -572,12 +572,13 @@ public void AddProtocolHandler(IProtocolHandler handler)
private AdaptiveCodeResolver GetOrCreateResolver()
{
string key = string.Join(":", _protocols.Select(p => p.Key).OrderBy(x => x).ToArray());
if (!_resolvers.ContainsKey(key))
if (!_resolvers.TryGetValue(key, out AdaptiveCodeResolver? value))
{
_resolvers[key] = new AdaptiveCodeResolver(_protocols);
value = new AdaptiveCodeResolver(_protocols);
_resolvers[key] = value;
}

return _resolvers[key];
return value;
}

public override string ToString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public TestBuilder StartNode(string name, string baseConfigFile, string key = nu

private NethermindProcessWrapper GetOrCreateNode(string name, string baseConfigFile, string key)
{
if (!Nodes.ContainsKey(name))
if (!Nodes.TryGetValue(name, out NethermindProcessWrapper value))
{
string bootnodes = string.Empty;
foreach ((_, NethermindProcessWrapper process) in Nodes)
Expand All @@ -227,11 +227,12 @@ private NethermindProcessWrapper GetOrCreateNode(string name, string baseConfigF
int p2pPort = _startPort + _nodeCounter;
int httpPort = _startHttpPort + _nodeCounter;
TestContext.WriteLine($"Creating {name} at {p2pPort}, http://localhost:{httpPort}");
Nodes[name] = _processBuilder.Create(name, _runnerDir, configPath, dbDir, httpPort, p2pPort, nodeKey, bootnodes);
value = _processBuilder.Create(name, _runnerDir, configPath, dbDir, httpPort, p2pPort, nodeKey, bootnodes);
Nodes[name] = value;
_nodeCounter++;
}

return Nodes[name];
return value;
}

private string GetNodeKey(string key)
Expand Down
Loading

0 comments on commit f62468e

Please sign in to comment.