mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-17 21:32:00 +01:00
optimization: Add single byte write
Single byte writes are used very often (used for every (u)int8_t or std::byte or bool and for every VarInt's first byte which is also needed for every (pre)Vector). It makes sense to avoid the generalized serialization infrastructure that isn't needed: * AutoFile write doesn't need to allocate 4k buffer for a single byte now; * `VectorWriter` and `DataStream` avoids memcpy/insert calls. > cmake -B build -DBUILD_BENCH=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc) && build/src/bench/bench_bitcoin -filter='SizeComputerBlock|SerializeBlock|DeserializeBlock' --min-time=10000 > C compiler ............................ AppleClang 16.0.0.16000026 | ns/block | block/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 934,120.45 | 1,070.53 | 0.2% | 11.01 | `DeserializeBlock` | 170,719.27 | 5,857.57 | 0.1% | 10.99 | `SerializeBlock` | 12,048.40 | 82,998.58 | 0.2% | 11.01 | `SizeComputerBlock` > C++ compiler .......................... GNU 13.3.0 | ns/block | block/s | err% | ins/block | cyc/block | IPC | bra/block | miss% | total | benchmark |--------------------:|--------------------:|--------:|----------------:|----------------:|-------:|---------------:|--------:|----------:|:---------- | 4,433,835.04 | 225.54 | 0.0% | 53,688,481.60 | 15,918,730.23 | 3.373 | 2,409,056.47 | 0.5% | 11.01 | `DeserializeBlock` | 563,663.10 | 1,774.11 | 0.0% | 7,386,775.59 | 2,023,525.77 | 3.650 | 1,385,368.57 | 0.5% | 11.00 | `SerializeBlock` | 27,351.60 | 36,560.93 | 0.1% | 225,261.03 | 98,209.77 | 2.294 | 53,037.03 | 0.9% | 11.00 | `SizeComputerBlock`
This commit is contained in:
parent
028c006541
commit
c02600b8e1
@ -107,6 +107,10 @@ public:
|
||||
{
|
||||
ctx.Write(UCharCast(src.data()), src.size());
|
||||
}
|
||||
void write(std::byte src)
|
||||
{
|
||||
ctx.Write(UCharCast(&src), 1);
|
||||
}
|
||||
|
||||
/** Compute the double-SHA256 hash of all data written to this object.
|
||||
*
|
||||
@ -194,6 +198,11 @@ public:
|
||||
m_source.write(src);
|
||||
HashWriter::write(src);
|
||||
}
|
||||
void write(std::byte src)
|
||||
{
|
||||
m_source.write(src);
|
||||
HashWriter::write(src);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
HashedSourceWriter& operator<<(const T& obj)
|
||||
|
@ -53,7 +53,7 @@ constexpr deserialize_type deserialize {};
|
||||
*/
|
||||
template<typename Stream> inline void ser_writedata8(Stream &s, uint8_t obj)
|
||||
{
|
||||
s.write(AsBytes(Span{&obj, 1}));
|
||||
s.write(std::byte{obj});
|
||||
}
|
||||
template<typename Stream> inline void ser_writedata16(Stream &s, uint16_t obj)
|
||||
{
|
||||
@ -1067,6 +1067,10 @@ public:
|
||||
{
|
||||
this->nSize += src.size();
|
||||
}
|
||||
void write(std::byte)
|
||||
{
|
||||
this->nSize += 1;
|
||||
}
|
||||
|
||||
/** Pretend _nSize bytes are written, without specifying them. */
|
||||
void seek(size_t _nSize)
|
||||
@ -1131,6 +1135,7 @@ public:
|
||||
template <typename U> ParamsStream& operator<<(const U& obj) { ::Serialize(*this, obj); return *this; }
|
||||
template <typename U> ParamsStream& operator>>(U&& obj) { ::Unserialize(*this, obj); return *this; }
|
||||
void write(Span<const std::byte> src) { GetStream().write(src); }
|
||||
void write(std::byte src) { GetStream().write(src); }
|
||||
void read(Span<std::byte> dst) { GetStream().read(dst); }
|
||||
void ignore(size_t num) { GetStream().ignore(num); }
|
||||
bool eof() const { return GetStream().eof(); }
|
||||
|
@ -111,6 +111,24 @@ void AutoFile::write_large(Span<std::byte> src)
|
||||
if (m_position) *m_position += src.size();
|
||||
}
|
||||
|
||||
void AutoFile::write(std::byte val)
|
||||
{
|
||||
if (!m_file) throw std::ios_base::failure("AutoFile::write: file handle is nullptr");
|
||||
if (!m_obfuscation) {
|
||||
if (fwrite(&val, 1, 1, m_file) != 1) {
|
||||
throw std::ios_base::failure("AutoFile::write: write failed");
|
||||
}
|
||||
if (m_position.has_value()) *m_position += 1;
|
||||
} else {
|
||||
if (!m_position.has_value()) throw std::ios_base::failure("AutoFile::write: position unknown");
|
||||
auto src{Span{&val, 1}};
|
||||
m_obfuscation(src, *m_position);
|
||||
if (fwrite(src.data(), 1, 1, m_file) != 1) {
|
||||
throw std::ios_base::failure{"XorFile::write: failed"};
|
||||
}
|
||||
*m_position += 1;
|
||||
}
|
||||
}
|
||||
bool AutoFile::Commit()
|
||||
{
|
||||
return ::FileCommit(m_file);
|
||||
|
@ -62,6 +62,16 @@ public:
|
||||
}
|
||||
nPos += src.size();
|
||||
}
|
||||
void write(std::byte val)
|
||||
{
|
||||
assert(nPos <= vchData.size());
|
||||
if (nPos < vchData.size()) {
|
||||
vchData[nPos] = static_cast<unsigned char>(val);
|
||||
} else {
|
||||
vchData.push_back(static_cast<unsigned char>(val));
|
||||
}
|
||||
nPos += 1;
|
||||
}
|
||||
template <typename T>
|
||||
VectorWriter& operator<<(const T& obj)
|
||||
{
|
||||
@ -233,6 +243,11 @@ public:
|
||||
// Write to the end of the buffer
|
||||
vch.insert(vch.end(), src.begin(), src.end());
|
||||
}
|
||||
void write(value_type val)
|
||||
{
|
||||
// Push single value to the end of the buffer
|
||||
vch.push_back(val);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
DataStream& operator<<(const T& obj)
|
||||
@ -427,6 +442,7 @@ public:
|
||||
void ignore(size_t nSize);
|
||||
void write(Span<const std::byte> src);
|
||||
void write_large(Span<std::byte> src); // Note that src will be mutated
|
||||
void write(std::byte src);
|
||||
|
||||
template <typename T>
|
||||
AutoFile& operator<<(const T& obj)
|
||||
|
Loading…
x
Reference in New Issue
Block a user