Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use TryGetValue to halve Dictionary lookups #6352

Merged
merged 6 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -92,16 +93,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 @@ -112,15 +111,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)
{
if (other is null) throw new ArgumentNullException(nameof(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)
{
if (other is null) throw new ArgumentNullException(nameof(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