mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-11 14:32:58 +02:00
Merge bitcoin/bitcoin#35025: refactor: use SpanReader in deserialization benchmarks
13c8df4d5arefactor: replace `DataStream` with `SpanReader` in block deserialization tests (Lőrinc)2529f25555refactor: use `SpanReader` in `PrevectorDeserialize` (Lőrinc)b8eb6c2081refactor: use `SpanReader` in `TestBlockAndIndex` (Lőrinc)61d678a6e3refactor: use `DataStream::clear` in `::read` and `::ignore` (Lőrinc) Pull request description: ### Problem Block deserialization benches still read immutable fixture bytes through `DataStream`, which keeps around mutable stream semantics and old compaction-oriented setup that these call sites do not need anymore. ### Fix We first remove the stale `Rewind()` parameter and failure path, which reduces rewinding to a simple reset of the read position that `clear()` can reuse. We then route fully consumed `read()` and `ignore()` paths through `clear()`, remove the leftover compaction references and dummy-byte workaround, and finally switch the block deserialization benchmark readers to `SpanReader`. `DeserializeBlockTest` can then deserialize directly from the fixture bytes without an untimed setup phase, while `CheckBlockTest` still keeps setup only to rebuild a fresh `CBlock` before the timed `CheckBlock()` call. ### Context This follows the same direction as #34483 and is a follow-up to https://github.com/bitcoin/bitcoin/pull/34208. The modified benchmarks retain their previous timing. ### Benchmarks The affected benchmarks speeds don't seem to be affected by the changes. <details><summary>Before & After</summary> > Before: ```bash | ns/op | op/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 37,591,891.96 | 26.60 | 1.0% | 11.07 | `BlockToJsonVerboseWrite` | 155,664.09 | 6,424.09 | 0.1% | 10.99 | `BlockToJsonVerbosity1` | 28,620,345.39 | 34.94 | 0.1% | 10.99 | `BlockToJsonVerbosity2` | 28,637,604.74 | 34.92 | 0.1% | 11.01 | `BlockToJsonVerbosity3` | ns/block | block/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 530,167.00 | 1,886.20 | 4.7% | 0.01 | `CheckBlockTest` | 1,439,417.00 | 694.73 | 0.7% | 0.02 | `DeserializeBlockTest` | ns/op | op/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 269.95 | 3,704,375.43 | 0.4% | 11.01 | `PrevectorDeserializeNontrivial` | 14.90 | 67,114,436.52 | 0.0% | 10.88 | `PrevectorDeserializeTrivial` ``` > After: ```bash | ns/op | op/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 37,114,824.07 | 26.94 | 1.8% | 10.89 | `BlockToJsonVerboseWrite` | 154,881.99 | 6,456.53 | 0.2% | 10.99 | `BlockToJsonVerbosity1` | 28,546,697.37 | 35.03 | 0.2% | 10.98 | `BlockToJsonVerbosity2` | 28,547,328.27 | 35.03 | 0.3% | 11.02 | `BlockToJsonVerbosity3` | ns/block | block/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 522,750.00 | 1,912.96 | 4.7% | 0.01 | `CheckBlockTest` | 1,404,510.54 | 711.99 | 0.1% | 11.00 | `DeserializeBlockTest` | ns/op | op/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 273.52 | 3,655,991.66 | 0.4% | 11.00 | `PrevectorDeserializeNontrivial` | 14.31 | 69,863,193.52 | 1.4% | 11.03 | `PrevectorDeserializeTrivial` ``` </details> ACKs for top commit: maflcko: review ACK13c8df4d5a🐠 sedited: Re-ACK13c8df4d5aTree-SHA512: b469874908c694b6b7f45e686519bdce0c0f4da2ca56b3f7f9897c7f27bb19a787f9821466995f15414343d508f15616b24b7fd8f0fa389ade8698c8f190b669
This commit is contained in:
@@ -4,22 +4,14 @@
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bench/data/block413567.raw.h>
|
||||
#include <chainparams.h>
|
||||
#include <common/args.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <primitives/block.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <span.h>
|
||||
#include <streams.h>
|
||||
#include <util/chaintype.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
// These are the two major time-sinks which happen after we have fully received
|
||||
// a block off the wire, but before we can relay the block on to peers using
|
||||
@@ -27,27 +19,29 @@
|
||||
|
||||
static void DeserializeBlockTest(benchmark::Bench& bench)
|
||||
{
|
||||
DataStream stream;
|
||||
bench.unit("block").epochIterations(1)
|
||||
.setup([&] { stream = DataStream{benchmark::data::block413567}; })
|
||||
.run([&] { CBlock block; stream >> TX_WITH_WITNESS(block); });
|
||||
const auto block_data{benchmark::data::block413567};
|
||||
bench.unit("block").run([&] {
|
||||
CBlock block;
|
||||
SpanReader{block_data} >> TX_WITH_WITNESS(block);
|
||||
assert(block.vtx.size() == 1557);
|
||||
});
|
||||
}
|
||||
|
||||
static void CheckBlockTest(benchmark::Bench& bench)
|
||||
{
|
||||
ArgsManager bench_args;
|
||||
const auto chainParams = CreateChainParams(bench_args, ChainType::MAIN);
|
||||
const auto& chain_params{CChainParams::Main()};
|
||||
const auto block_data{benchmark::data::block413567};
|
||||
|
||||
CBlock block;
|
||||
bench.unit("block").epochIterations(1)
|
||||
.setup([&] {
|
||||
block = CBlock{};
|
||||
DataStream stream{benchmark::data::block413567};
|
||||
stream >> TX_WITH_WITNESS(block);
|
||||
SpanReader{block_data} >> TX_WITH_WITNESS(block);
|
||||
assert(block.vtx.size() == 1557);
|
||||
})
|
||||
.run([&] {
|
||||
BlockValidationState validationState;
|
||||
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus());
|
||||
const bool checked{CheckBlock(block, validationState, chain_params->GetConsensus())};
|
||||
assert(checked);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,22 +66,22 @@ static void PrevectorResize(benchmark::Bench& bench)
|
||||
template <typename T>
|
||||
static void PrevectorDeserialize(benchmark::Bench& bench)
|
||||
{
|
||||
DataStream s0{};
|
||||
DataStream data{};
|
||||
prevector<CScriptBase::STATIC_SIZE, T> t0;
|
||||
t0.resize(CScriptBase::STATIC_SIZE);
|
||||
for (auto x = 0; x < 900; ++x) {
|
||||
s0 << t0;
|
||||
data << t0;
|
||||
}
|
||||
t0.resize(100);
|
||||
for (auto x = 0; x < 101; ++x) {
|
||||
s0 << t0;
|
||||
for (auto x = 0; x < 100; ++x) {
|
||||
data << t0;
|
||||
}
|
||||
bench.batch(1000).run([&] {
|
||||
SpanReader s0{data};
|
||||
prevector<CScriptBase::STATIC_SIZE, T> t1;
|
||||
for (auto x = 0; x < 1000; ++x) {
|
||||
s0 >> t1;
|
||||
}
|
||||
s0.Rewind();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -31,10 +31,7 @@ struct TestBlockAndIndex {
|
||||
|
||||
TestBlockAndIndex()
|
||||
{
|
||||
DataStream stream{benchmark::data::block413567};
|
||||
std::byte a{0};
|
||||
stream.write({&a, 1}); // Prevent compaction
|
||||
|
||||
SpanReader stream{benchmark::data::block413567};
|
||||
stream >> TX_WITH_WITNESS(block);
|
||||
|
||||
blockHash = block.GetHash();
|
||||
|
||||
@@ -206,27 +206,6 @@ public:
|
||||
value_type* data() { return vch.data() + m_read_pos; }
|
||||
const value_type* data() const { return vch.data() + m_read_pos; }
|
||||
|
||||
inline void Compact()
|
||||
{
|
||||
vch.erase(vch.begin(), vch.begin() + m_read_pos);
|
||||
m_read_pos = 0;
|
||||
}
|
||||
|
||||
bool Rewind(std::optional<size_type> n = std::nullopt)
|
||||
{
|
||||
// Total rewind if no size is passed
|
||||
if (!n) {
|
||||
m_read_pos = 0;
|
||||
return true;
|
||||
}
|
||||
// Rewind by n characters if the buffer hasn't been compacted yet
|
||||
if (*n > m_read_pos)
|
||||
return false;
|
||||
m_read_pos -= *n;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Stream subset
|
||||
//
|
||||
@@ -243,8 +222,8 @@ public:
|
||||
}
|
||||
memcpy(dst.data(), &vch[m_read_pos], dst.size());
|
||||
if (next_read_pos.value() == vch.size()) {
|
||||
m_read_pos = 0;
|
||||
vch.clear();
|
||||
// If fully consumed, reset to empty state.
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
m_read_pos = next_read_pos.value();
|
||||
@@ -258,8 +237,8 @@ public:
|
||||
throw std::ios_base::failure("DataStream::ignore(): end of data");
|
||||
}
|
||||
if (next_read_pos.value() == vch.size()) {
|
||||
m_read_pos = 0;
|
||||
vch.clear();
|
||||
// If all bytes are ignored, reset to empty state.
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
m_read_pos = next_read_pos.value();
|
||||
|
||||
Reference in New Issue
Block a user