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

Hunting allocations 2 #6604

Merged
merged 13 commits into from
Jan 26, 2024
4 changes: 2 additions & 2 deletions src/Nethermind/Ethereum.Test.Base/BlockchainTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ private List<string> RunAssertions(BlockchainTest test, Block headBlock, IWorldS

foreach (KeyValuePair<UInt256, byte[]> clearedStorage in clearedStorages)
{
byte[] value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key));
Span<byte> value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, clearedStorage.Key));
if (!value.IsZero())
{
differences.Add($"{acountAddress} storage[{clearedStorage.Key}] exp: 0x00, actual: {value.ToHexString(true)}");
Expand All @@ -415,7 +415,7 @@ private List<string> RunAssertions(BlockchainTest test, Block headBlock, IWorldS

foreach (KeyValuePair<UInt256, byte[]> storageItem in accountState.Storage)
{
byte[] value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key)) ?? new byte[0];
Span<byte> value = !stateProvider.AccountExists(acountAddress) ? Bytes.Empty : stateProvider.Get(new StorageCell(acountAddress, storageItem.Key));
if (!Bytes.AreEqual(storageItem.Value, value))
{
differences.Add($"{acountAddress} storage[{storageItem.Key}] exp: {storageItem.Value.ToHexString(true)}, actual: {value.ToHexString(true)}");
Expand Down
3 changes: 2 additions & 1 deletion src/Nethermind/Nethermind.Analytics/SupplyVerifier.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Collections.Generic;
using Nethermind.Core;
using Nethermind.Core.Crypto;
Expand Down Expand Up @@ -78,7 +79,7 @@ public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext)
}
}

public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[] value = null)
public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan<byte> value)
{
_nodesVisited++;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void VisitMissingNode(Hash256 nodeHash, TrieVisitContext trieVisitContext

public void VisitExtension(TrieNode node, TrieVisitContext trieVisitContext) => PersistNode(node);

public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, byte[]? value = null) => PersistNode(node);
public void VisitLeaf(TrieNode node, TrieVisitContext trieVisitContext, ReadOnlySpan<byte> value) => PersistNode(node);

public void VisitCode(Hash256 codeHash, TrieVisitContext trieVisitContext) { }

Expand All @@ -78,7 +78,7 @@ private void PersistNode(TrieNode node)
if (node.Keccak is not null)
{
// simple copy of nodes RLP
_pruningContext.Set(node.Keccak.Bytes, node.FullRlp.ToArray(), _writeFlags);
_pruningContext.PutSpan(node.Keccak.Bytes, node.FullRlp.AsSpan(), _writeFlags);
Interlocked.Increment(ref _persistedNodes);

// log message every 1 mln nodes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public ref struct KeccaksIterator
private readonly Span<byte> _buffer;
public long Index { get; private set; }

public KeccaksIterator(Span<byte> data, Span<byte> buffer)
public KeccaksIterator(ReadOnlySpan<byte> data, Span<byte> buffer)
{
if (buffer.Length != 32) throw new ArgumentException("Buffer must be 32 bytes long");
_decoderContext = new Rlp.ValueDecoderContext(data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public ref struct LogEntriesIterator
private readonly IReceiptRefDecoder _receiptRefDecoder;
public long Index { get; private set; }

public LogEntriesIterator(Span<byte> data, IReceiptRefDecoder receiptRefDecoder)
public LogEntriesIterator(ReadOnlySpan<byte> data, IReceiptRefDecoder receiptRefDecoder)
{
_decoderContext = new Rlp.ValueDecoderContext(data);
_length = _decoderContext.ReadSequenceLength();
Expand Down
4 changes: 2 additions & 2 deletions src/Nethermind/Nethermind.Core/Address.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ public ref struct AddressStructRef
private const int HexCharsCount = 2 * ByteLength; // 5a4eab120fb44eb6684e5e32785702ff45ea344d
private const int PrefixedHexCharsCount = 2 + HexCharsCount; // 0x5a4eab120fb44eb6684e5e32785702ff45ea344d

public Span<byte> Bytes { get; }
public ReadOnlySpan<byte> Bytes { get; }

public AddressStructRef(Hash256StructRef keccak) : this(keccak.Bytes.Slice(12, ByteLength)) { }

Expand Down Expand Up @@ -274,7 +274,7 @@ public static bool IsValidAddress(string hexString, bool allowPrefix)

public AddressStructRef(string hexString) : this(Extensions.Bytes.FromHexString(hexString)) { }

public AddressStructRef(Span<byte> bytes)
public AddressStructRef(ReadOnlySpan<byte> bytes)
{
if (bytes.Length != ByteLength)
{
Expand Down
56 changes: 2 additions & 54 deletions src/Nethermind/Nethermind.Core/Bloom.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,37 +229,12 @@ public ref struct BloomStructRef
public const int BitLength = 2048;
public const int ByteLength = BitLength / 8;

public BloomStructRef(LogEntry[] logEntries, Bloom? blockBloom = null)
{
Bytes = new byte[ByteLength];
Add(logEntries, blockBloom);
}

public BloomStructRef(Span<byte> bytes)
public BloomStructRef(ReadOnlySpan<byte> bytes)
{
Bytes = bytes;
}

public Span<byte> Bytes { get; }

public void Set(ReadOnlySpan<byte> sequence)
{
Set(sequence, null);
}

private readonly void Set(ReadOnlySpan<byte> sequence, Bloom? masterBloom = null)
{
Bloom.BloomExtract indexes = GetExtract(sequence);
Set(indexes.Index1);
Set(indexes.Index2);
Set(indexes.Index3);
if (masterBloom is not null)
{
masterBloom.Set(indexes.Index1);
masterBloom.Set(indexes.Index2);
masterBloom.Set(indexes.Index3);
}
}
public ReadOnlySpan<byte> Bytes { get; }

public bool Matches(ReadOnlySpan<byte> sequence)
{
Expand Down Expand Up @@ -306,26 +281,6 @@ public override readonly int GetHashCode()
return Core.Extensions.Bytes.GetSimplifiedHashCode(Bytes);
}

public void Add(LogEntry[] logEntries, Bloom? blockBloom)
{
for (int entryIndex = 0; entryIndex < logEntries.Length; entryIndex++)
{
LogEntry logEntry = logEntries[entryIndex];
byte[] addressBytes = logEntry.LoggersAddress.Bytes;
Set(addressBytes, blockBloom);
for (int topicIndex = 0; topicIndex < logEntry.Topics.Length; topicIndex++)
{
Hash256 topic = logEntry.Topics[topicIndex];
Set(topic.Bytes, blockBloom);
}
}
}

public readonly void Accumulate(BloomStructRef bloom)
{
Bytes.Or(bloom.Bytes);
}

public bool Matches(LogEntry logEntry)
{
if (Matches(logEntry.LoggersAddress))
Expand All @@ -351,13 +306,6 @@ private readonly bool Get(int index)
return Bytes[bytePosition].GetBit(shift);
}

private readonly void Set(int index)
{
int bytePosition = index / 8;
int shift = index % 8;
Bytes[bytePosition].SetBit(shift);
}

public bool Matches(Address address) => Matches(address.Bytes);

public bool Matches(Hash256 topic) => Matches(topic.Bytes);
Expand Down
23 changes: 23 additions & 0 deletions src/Nethermind/Nethermind.Core/ByteReadOnlyMemoryConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Nethermind.Serialization.Json;

public class ByteReadOnlyMemoryConverter : JsonConverter<ReadOnlyMemory<byte>>
{
public override ReadOnlyMemory<byte> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
ByteArrayConverter.Convert(ref reader);

public override void Write(
Utf8JsonWriter writer,
ReadOnlyMemory<byte> bytes,
JsonSerializerOptions options) =>
ByteArrayConverter.Convert(writer, bytes.Span, skipLeadingZeros: false);
}
4 changes: 2 additions & 2 deletions src/Nethermind/Nethermind.Core/Crypto/Hash256.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,9 @@ public ref struct Hash256StructRef

public static int MemorySize => MemorySizes.ArrayOverhead + Size;

public Span<byte> Bytes { get; }
public ReadOnlySpan<byte> Bytes { get; }

public Hash256StructRef(Span<byte> bytes)
public Hash256StructRef(ReadOnlySpan<byte> bytes)
{
if (bytes.Length != Size)
{
Expand Down
12 changes: 6 additions & 6 deletions src/Nethermind/Nethermind.Core/Crypto/Keccak.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ public static class ValueKeccak
/// <returns>
/// <string>0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470</string>
/// </returns>
public static readonly ValueHash256 OfAnEmptyString = InternalCompute(new byte[] { });
public static readonly ValueHash256 OfAnEmptyString = InternalCompute(Array.Empty<byte>());

/// <returns>
/// <string>0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347</string>
/// </returns>
public static readonly ValueHash256 OfAnEmptySequenceRlp = InternalCompute(new byte[] { 192 });
public static readonly ValueHash256 OfAnEmptySequenceRlp = InternalCompute([192]);

/// <summary>
/// 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
/// </summary>
public static readonly ValueHash256 EmptyTreeHash = InternalCompute(new byte[] { 128 });
public static readonly ValueHash256 EmptyTreeHash = InternalCompute([128]);

/// <returns>
/// <string>0x0000000000000000000000000000000000000000000000000000000000000000</string>
Expand Down Expand Up @@ -82,17 +82,17 @@ public static class Keccak
/// <returns>
/// <string>0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470</string>
/// </returns>
public static readonly Hash256 OfAnEmptyString = new Hash256(ValueKeccak.InternalCompute(new byte[] { }));
public static readonly Hash256 OfAnEmptyString = new Hash256(ValueKeccak.InternalCompute(Array.Empty<byte>()));

/// <returns>
/// <string>0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347</string>
/// </returns>
public static readonly Hash256 OfAnEmptySequenceRlp = new Hash256(ValueKeccak.InternalCompute(new byte[] { 192 }));
public static readonly Hash256 OfAnEmptySequenceRlp = new Hash256(ValueKeccak.InternalCompute([192]));

/// <summary>
/// 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
/// </summary>
public static Hash256 EmptyTreeHash = new Hash256(ValueKeccak.InternalCompute(new byte[] { 128 }));
public static Hash256 EmptyTreeHash = new Hash256(ValueKeccak.InternalCompute([128]));

/// <returns>
/// <string>0x0000000000000000000000000000000000000000000000000000000000000000</string>
Expand Down
23 changes: 15 additions & 8 deletions src/Nethermind/Nethermind.Core/Extensions/Bytes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public static unsafe partial class Bytes
public static readonly IEqualityComparer<byte[]?> NullableEqualityComparer = new NullableBytesEqualityComparer();
public static readonly ISpanEqualityComparer<byte> SpanEqualityComparer = new SpanBytesEqualityComparer();
public static readonly BytesComparer Comparer = new();
public static readonly ReadOnlyMemory<byte> ZeroByte = new byte[] { 0 };
public static readonly ReadOnlyMemory<byte> OneByte = new byte[] { 1 };

private class BytesEqualityComparer : EqualityComparer<byte[]>
{
Expand Down Expand Up @@ -198,26 +200,28 @@ public static int TrailingZerosCount(this byte[] bytes)
return lastIndex < 0 ? bytes.Length : bytes.Length - lastIndex - 1;
}

public static Span<byte> WithoutLeadingZeros(this byte[] bytes)
public static ReadOnlySpan<byte> WithoutLeadingZeros(this byte[] bytes)
{
return bytes.AsSpan().WithoutLeadingZeros();
}

public static Span<byte> WithoutLeadingZerosOrEmpty(this byte[] bytes)
public static ReadOnlySpan<byte> WithoutLeadingZerosOrEmpty(this byte[] bytes)
{
if (bytes is null || bytes.Length == 0) return Array.Empty<byte>();
return bytes.AsSpan().WithoutLeadingZeros();
}

public static Span<byte> WithoutLeadingZerosOrEmpty(this Span<byte> bytes)
public static ReadOnlySpan<byte> WithoutLeadingZerosOrEmpty(this Span<byte> bytes) =>
((ReadOnlySpan<byte>)bytes).WithoutLeadingZeros();

public static ReadOnlySpan<byte> WithoutLeadingZeros(this Span<byte> bytes)
{
if (bytes.IsNullOrEmpty()) return Array.Empty<byte>();
return bytes.WithoutLeadingZeros();
return ((ReadOnlySpan<byte>)bytes).WithoutLeadingZeros();
}

public static Span<byte> WithoutLeadingZeros(this Span<byte> bytes)
public static ReadOnlySpan<byte> WithoutLeadingZeros(this ReadOnlySpan<byte> bytes)
{
if (bytes.Length == 0) return new byte[] { 0 };
if (bytes.Length == 0) return ZeroByte.Span;

int nonZeroIndex = bytes.IndexOfAnyExcept((byte)0);
// Keep one or it will be interpreted as null
Expand All @@ -235,7 +239,10 @@ public static byte[] Concat(byte prefix, byte[] bytes)
public static byte[] PadLeft(this byte[] bytes, int length, byte padding = 0)
=> bytes.Length == length ? bytes : bytes.AsSpan().PadLeft(length, padding);

public static byte[] PadLeft(this Span<byte> bytes, int length, byte padding = 0)
public static byte[] PadLeft(this Span<byte> bytes, int length, byte padding = 0) =>
((ReadOnlySpan<byte>)bytes).PadLeft(length, padding);

public static byte[] PadLeft(this ReadOnlySpan<byte> bytes, int length, byte padding = 0)
{
if (bytes.Length == length)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Core/IKeyValueStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ bool KeyExists(ReadOnlySpan<byte> key)
return result;
}

void DangerousReleaseMemory(in Span<byte> span) { }
void DangerousReleaseMemory(in ReadOnlySpan<byte> span) { }
}

public interface IWriteOnlyKeyValueStore
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Core/KeyValueStoreExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public static void Set(this IWriteOnlyKeyValueStore db, Hash256 key, in CappedAr
{
if (value.IsUncapped && db.PreferWriteByArray)
{
db.Set(key.Bytes, value.ToArray(), writeFlags);
db.PutSpan(key.Bytes, value.AsSpan(), writeFlags);
return;
}

Expand Down
6 changes: 3 additions & 3 deletions src/Nethermind/Nethermind.Core/LogEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public LogEntry(Address address, byte[] data, Hash256[] topics)

public ref struct LogEntryStructRef
{
public LogEntryStructRef(AddressStructRef address, Span<byte> data, Span<byte> topicsRlp)
public LogEntryStructRef(AddressStructRef address, ReadOnlySpan<byte> data, ReadOnlySpan<byte> topicsRlp)
{
LoggersAddress = address;
Data = data;
Expand All @@ -45,8 +45,8 @@ public LogEntryStructRef(LogEntry logEntry)
/// <summary>
/// Rlp encoded array of Keccak
/// </summary>
public Span<byte> TopicsRlp { get; }
public ReadOnlySpan<byte> TopicsRlp { get; }

public Span<byte> Data { get; }
public ReadOnlySpan<byte> Data { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2024 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Nethermind.Serialization.Json;

public class NullableByteReadOnlyMemoryConverter : JsonConverter<ReadOnlyMemory<byte>?>
{
public override ReadOnlyMemory<byte>? Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
ByteArrayConverter.Convert(ref reader);

public override void Write(
Utf8JsonWriter writer,
ReadOnlyMemory<byte>? bytes,
JsonSerializerOptions options) =>
ByteArrayConverter.Convert(writer, bytes is null ? ReadOnlySpan<byte>.Empty : bytes.Value.Span, skipLeadingZeros: false);
}
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Core/TransactionReceipt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public ref struct TxReceiptStructRef
/// <summary>
/// Rlp encoded logs
/// </summary>
public Span<byte> LogsRlp { get; set; }
public ReadOnlySpan<byte> LogsRlp { get; set; }

public LogEntry[]? Logs { get; set; }

Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Db.Rocks/ColumnDb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public void Compact()
public long GetIndexSize() => _mainDb.GetIndexSize();
public long GetMemtableSize() => _mainDb.GetMemtableSize();

public void DangerousReleaseMemory(in Span<byte> span)
public void DangerousReleaseMemory(in ReadOnlySpan<byte> span)
{
_mainDb.DangerousReleaseMemory(span);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Nethermind/Nethermind.Db.Rocks/DbOnTheRocks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ public void PutSpan(ReadOnlySpan<byte> key, ReadOnlySpan<byte> value, WriteFlags
SetWithColumnFamily(key, null, value, writeFlags);
}

public void DangerousReleaseMemory(in Span<byte> span)
public void DangerousReleaseMemory(in ReadOnlySpan<byte> span)
{
if (!span.IsNullOrEmpty())
{
Expand Down
Loading
Loading