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

Perf/faster block load for receipt #5708

Merged
merged 24 commits into from
May 25, 2023
Merged

Conversation

asdacap
Copy link
Contributor

@asdacap asdacap commented May 19, 2023

  • Turns out, if you increase the range of block per eth_getLogs, the different between compact and standard receipt encoding grows. This run uses 256 blocks per request instead of 50, where the non compact receipt can reach 2000 request per second, while compact receipt reach 500 request per second.
  • This pr reduces memory allocation 2.5MB per request to 1.3MB per request, however only increase request per second to 600. For reference, non compact encoding use 0.5MB per request.
  • This works by:
    • Adding a ReceiptRecoveryBlock class which stores the tx's byte section as raw serialized Memory<byte>.
      • This class exposes GetNextTransaction which is used by block recovery.
      • It still return a Transaction instead of a ref struct, but reuse the object which turns out to be significant.
    • Adding a DisableLazyHash rlp param, so that transaction hash is calculated ahead of time as it will be needed.
    • Switch Transaction.Data from byte[] to Memory<byte> which can be backed by rocksdb's memory.

Types of changes

What types of changes does your code introduce?

  • Optimization

Testing

Requires testing

  • Yes
  • No

If yes, did you write tests?

  • Yes
  • No

Notes on testing

eth_getLogs matches master.

@asdacap asdacap mentioned this pull request May 22, 2023
6 tasks
@asdacap asdacap marked this pull request as ready for review May 23, 2023 08:19
src/Nethermind/Nethermind.Core/Transaction.cs Outdated Show resolved Hide resolved
return memory.Value.FasterToArray();
}

public static byte[] FasterToArray(this in Memory<byte> memory)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming could cause confusion, normally you expect a copy.
Minor: is the code layout readable here? Would prefer ? operator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you have in mind? AsArray, AsArrayOrCopy?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like .AsArray()

src/Nethermind/Nethermind.Core.Test/TransactionTests.cs Outdated Show resolved Hide resolved
src/Nethermind/Nethermind.Blockchain/Blocks/BlockStore.cs Outdated Show resolved Hide resolved
Comment on lines 45 to 59
private Transaction? _txBuffer;

public Transaction GetNextTransaction()
{
if (_transactions != null)
{
return _transactions[_currentTransactionIndex++];
}

Rlp.ValueDecoderContext decoderContext = new(_transactionData, true);
decoderContext.Position = _currentTransactionPosition;
TxDecoder.Instance.Decode(ref decoderContext, ref _txBuffer, RlpBehaviors.AllowUnsigned | RlpBehaviors.DisableLazyHash);
_currentTransactionPosition = decoderContext.Position;

return _txBuffer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TransactionStruct? and then have a generic decoder that would work with ITransaction objects? This way we could reuse the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a follow up PR. Code in decoder is significant too.

Comment on lines +152 to +163
Data = (Memory<byte>?)data,
Type = Type,
AccessList = TryGetAccessList(),
ChainId = chainId,
MaxFeePerDataGas = MaxFeePerDataGas,
};

if (data is null)
{
tx.Data = null; // Yes this is needed... really. Try a debugger.
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data = data is null ? data : (Memory<byte>?)data,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, does not work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoa, why?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry meant: Data = data is null ? null : (Memory<byte>?)data

@benaadams
Copy link
Member

FasterToArray -> AsArray would be good to do, wasn't sure what FasterToArray meant

@asdacap asdacap merged commit 67337c4 into master May 25, 2023
@asdacap asdacap deleted the perf/faster-block-load-for-receipt branch May 25, 2023 07:06
@asdacap
Copy link
Contributor Author

asdacap commented Jul 10, 2023

Did a mistake during benchmark as I forgot to remove a spinwait in KeccakF. Rerun benchmark. They are both CPU limited, likely at JSON serialization.

Configuration Request Per sec Read IO bandwidh IO per call
Non compact 2100 1.5 GBps 0.7 KB
Compact 1800 1.75 GBps 0.97 KB

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants