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

Reduce TrieNode allocations #5457

Merged
merged 7 commits into from
Mar 22, 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
144 changes: 76 additions & 68 deletions src/Nethermind/Nethermind.Benchmark/Store/PatriciaTreeBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace Nethermind.Benchmarks.Store
{
[MemoryDiagnoser]
public class PatriciaTreeBenchmarks
{
private static readonly Account _empty = Build.An.Account.WithBalance(0).TestObject;
Expand All @@ -20,10 +21,26 @@ public class PatriciaTreeBenchmarks
private static readonly Account _account2 = Build.An.Account.WithBalance(3).TestObject;
private static readonly Account _account3 = Build.An.Account.WithBalance(4).TestObject;

private static readonly Keccak _keccak1 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000");
private static readonly Keccak _keccak2 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0");
private static readonly Keccak _keccak3 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1");
private static readonly Keccak _keccak4 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111");
private static readonly Keccak _keccak5 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddd");
private static readonly Keccak _keccak6 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddd");
private static readonly Keccak _keccak7 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaab00000000");
private static readonly Keccak _keccak8 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaab11111111");
private static readonly Keccak _keccak9 = new("1111111111111111111111111111111111111111111111111111111111111111");
private static readonly Keccak _keccak10 = new("1111111111111111111111111111111ddddddddddddddddddddddddddddddddd");
private static readonly Keccak _keccak11 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111111111111111111111111111");
private static readonly Keccak _keccak12 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000000000000000000000000000");
private static readonly Keccak _keccak13 = new("111111111111111111111111111111111111111111111111111111111ddddddd");
private static readonly Keccak _keccak14 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000");
private static readonly Keccak _keccak15 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111");
private static readonly Keccak _keccak16 = new("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222");

private StateTree _tree;

private (string Name, Action<StateTree> Action)[] _scenarios = new (string, Action<StateTree>)[]
{
private readonly (string Name, Action<StateTree> Action)[] _scenarios = {
("set_3_via_address", tree =>
{
tree.Set(TestItem.AddressA, _account0);
Expand All @@ -33,163 +50,163 @@ public class PatriciaTreeBenchmarks
}),
("set_3_via_hash", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0);
tree.Set(_keccak1, _account0);
tree.Set(_keccak2, _account0);
tree.Set(_keccak3, _account0);
tree.Commit(1);
}),
("set_3_delete_1", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null);
tree.Set(_keccak1, _account0);
tree.Set(_keccak2, _account0);
tree.Set(_keccak3, _account0);
tree.Set(_keccak3, null);
tree.Commit(1);
}),
("set_3_delete_2", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), null);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null);
tree.Set(_keccak1, _account0);
tree.Set(_keccak2, _account0);
tree.Set(_keccak3, _account0);
tree.Set(_keccak2, null);
tree.Set(_keccak3, null);
tree.Commit(1);
}),
("set_3_delete_all", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb0"), null);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb1eeeeeb1"), null);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), null);
tree.Set(_keccak1, _account0);
tree.Set(_keccak2, _account0);
tree.Set(_keccak3, _account0);
tree.Set(_keccak2, null);
tree.Set(_keccak3, null);
tree.Set(_keccak1, null);
tree.Commit(1);
}),
("extension_read_full_match", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1);
Account account = tree.Get(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"));
tree.Set(_keccak1, _account0);
tree.Set(_keccak4, _account1);
Account account = tree.Get(_keccak4);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("extension_read_missing", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1);
Account account = tree.Get(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddd"));
tree.Set(_keccak1, _account0);
tree.Set(_keccak4, _account1);
Account account = tree.Get(_keccak5);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("extension_new_branch", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeedddddddddddddddddddddddd"), _account2);
tree.Set(_keccak1, _account0);
tree.Set(_keccak4, _account1);
tree.Set(_keccak5, _account2);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("extension_delete_missing", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeddddddddddddddddddddddddd"), null);
tree.Set(_keccak1, _account0);
tree.Set(_keccak4, _account1);
tree.Set(_keccak6, null);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("extenson_create_new_extension", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111"), _account1);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaab00000000"), _account2);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaaaaaab11111111"), _account3);
tree.Set(_keccak1, _account0);
tree.Set(_keccak4, _account1);
tree.Set(_keccak7, _account2);
tree.Set(_keccak8, _account3);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("leaf_new_value", tree =>
{
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), _account0);
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), _account1);
tree.Set(_keccak9, _account0);
tree.Set(_keccak9, _account1);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("leaf_no_change", tree =>
{
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), _account0);
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), _account0);
tree.Set(_keccak9, _account0);
tree.Set(_keccak9, _account0);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("leaf_delete", tree =>
{
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), _account0);
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), null);
tree.Set(_keccak9, _account0);
tree.Set(_keccak9, null);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("leaf_delete_missing", tree =>
{
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), _account0);
tree.Set(new Keccak("1111111111111111111111111111111ddddddddddddddddddddddddddddddddd"), null);
tree.Set(_keccak9, _account0);
tree.Set(_keccak10, null);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("leaf_update_extension", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111111111111111111111111111111"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000000000000000000000000000000"), _account1);
tree.Set(_keccak11, _account0);
tree.Set(_keccak12, _account1);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("leaf_read", tree =>
{
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), _account0);
Account account = tree.Get(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"));
tree.Set(_keccak9, _account0);
Account account = tree.Get(_keccak9);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("leaf_update_missing", tree =>
{
tree.Set(new Keccak("1111111111111111111111111111111111111111111111111111111111111111"), _account0);
Account account = tree.Get(new Keccak("111111111111111111111111111111111111111111111111111111111ddddddd"));
tree.Set(_keccak9, _account0);
Account account = tree.Get(_keccak13);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("branch_update_missing", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222"), _account2);
tree.Set(_keccak14, _account0);
tree.Set(_keccak15, _account1);
tree.Set(_keccak16, _account2);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("branch_read_missing", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1);
Account account = tree.Get(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222"));
tree.Set(_keccak14, _account0);
tree.Set(_keccak15, _account1);
Account account = tree.Get(_keccak16);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
}),
("branch_delete_missing", tree =>
{
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb00000"), _account0);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb11111"), _account1);
tree.Set(new Keccak("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeb22222"), null);
tree.Set(_keccak14, _account0);
tree.Set(_keccak15, _account1);
tree.Set(_keccak16, null);
tree.UpdateRootHash();
Keccak rootHash = tree.RootHash;
tree.Commit(1);
Expand All @@ -202,15 +219,6 @@ public void Setup()
_tree = new StateTree();
}

[Benchmark]
public void Improved()
{
for (int i = 0; i < 19; i++)
{
_scenarios[i].Action(_tree);
}
}

[Benchmark]
public void Current()
{
Expand Down
24 changes: 12 additions & 12 deletions src/Nethermind/Nethermind.Trie.Test/TrieNodeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -532,8 +532,8 @@ public void Size_of_a_branch_is_correct()
node.SetChild(i, ctx.AccountLeaf);
}

Assert.AreEqual(3664, node.GetMemorySize(true));
Assert.AreEqual(208, node.GetMemorySize(false));
Assert.AreEqual(3656, node.GetMemorySize(true));
Assert.AreEqual(200, node.GetMemorySize(false));
}

[Test]
Expand All @@ -544,7 +544,7 @@ public void Size_of_an_extension_is_correct()
trieNode.Key = new byte[] { 1 };
trieNode.SetChild(0, ctx.TiniestLeaf);

Assert.AreEqual(120, trieNode.GetMemorySize(false));
Assert.AreEqual(112, trieNode.GetMemorySize(false));
}

[Test]
Expand All @@ -555,38 +555,38 @@ public void Size_of_unknown_node_is_correct()
trieNode.Key = new byte[] { 1 };
trieNode.SetChild(0, ctx.TiniestLeaf);

Assert.AreEqual(264, trieNode.GetMemorySize(true));
Assert.AreEqual(120, trieNode.GetMemorySize(false));
Assert.AreEqual(256, trieNode.GetMemorySize(true));
Assert.AreEqual(112, trieNode.GetMemorySize(false));
}

[Test]
public void Size_of_an_unknown_empty_node_is_correct()
{
TrieNode trieNode = new(NodeType.Unknown);
trieNode.GetMemorySize(false).Should().Be(56);
trieNode.GetMemorySize(false).Should().Be(48);
}

[Test]
public void Size_of_an_unknown_node_with_keccak_is_correct()
{
TrieNode trieNode = new(NodeType.Unknown, Keccak.Zero);
trieNode.GetMemorySize(false).Should().Be(136);
trieNode.GetMemorySize(false).Should().Be(128);
}

[Test]
public void Size_of_extension_with_child()
{
TrieNode trieNode = new(NodeType.Extension);
trieNode.SetChild(0, null);
trieNode.GetMemorySize(false).Should().Be(96);
trieNode.GetMemorySize(false).Should().Be(88);
}

[Test]
public void Size_of_branch_with_data()
{
TrieNode trieNode = new(NodeType.Branch);
trieNode.SetChild(0, null);
trieNode.GetMemorySize(false).Should().Be(208);
trieNode.GetMemorySize(false).Should().Be(200);
}

[Test]
Expand All @@ -601,7 +601,7 @@ public void Size_of_leaf_with_value()
public void Size_of_an_unknown_node_with_full_rlp_is_correct()
{
TrieNode trieNode = new(NodeType.Unknown, new byte[7]);
trieNode.GetMemorySize(false).Should().Be(120);
trieNode.GetMemorySize(false).Should().Be(80);
}

[Test]
Expand Down Expand Up @@ -699,7 +699,7 @@ public void Extension_child_as_keccak_memory_size()
trieNode.SetChild(0, child);

trieNode.PrunePersistedRecursively(1);
trieNode.GetMemorySize(false).Should().Be(176);
trieNode.GetMemorySize(false).Should().Be(168);
}

[Test]
Expand All @@ -712,7 +712,7 @@ public void Extension_child_as_keccak_clone()
trieNode.PrunePersistedRecursively(1);
TrieNode cloned = trieNode.Clone();

cloned.GetMemorySize(false).Should().Be(176);
cloned.GetMemorySize(false).Should().Be(168);
}

[Test]
Expand Down
Loading