From 08e4497c6e3b3f434c0bb255c3942648f153fe66 Mon Sep 17 00:00:00 2001 From: Lee Clagett Date: Sun, 24 Jan 2021 07:42:57 +0000 Subject: Improve cryptonote (block and tx) binary read performance --- src/serialization/binary_archive.h | 90 +++++++++++++++++++------------------ src/serialization/binary_utils.h | 3 +- src/serialization/container.h | 10 ++--- src/serialization/crypto.h | 6 +-- src/serialization/debug_archive.h | 1 + src/serialization/difficulty_type.h | 8 ++-- src/serialization/json_archive.h | 7 ++- src/serialization/pair.h | 12 ++--- src/serialization/serialization.h | 36 +++++++-------- src/serialization/string.h | 2 +- src/serialization/variant.h | 8 ++-- 11 files changed, 94 insertions(+), 89 deletions(-) (limited to 'src/serialization') diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h index 49ca8aa57..acda70039 100644 --- a/src/serialization/binary_archive.h +++ b/src/serialization/binary_archive.h @@ -36,9 +36,11 @@ #include #include #include +#include #include #include "common/varint.h" +#include "span.h" #include "warnings.h" /* I have no clue what these lines means */ @@ -55,16 +57,15 @@ DISABLE_VS_WARNINGS(4244) * purpse is to define the functions used for the binary_archive. Its * a header, basically. I think it was declared simply to save typing... */ -template +template struct binary_archive_base { - typedef Stream stream_type; - typedef binary_archive_base base_type; + typedef binary_archive_base base_type; typedef boost::mpl::bool_ is_saving; typedef uint8_t variant_tag_type; - explicit binary_archive_base(stream_type &s) : stream_(s) { } + explicit binary_archive_base() { } /* definition of standard API functions */ void tag(const char *) { } @@ -72,12 +73,6 @@ struct binary_archive_base void end_object() { } void begin_variant() { } void end_variant() { } - /* I just want to leave a comment saying how this line really shows - flaws in the ownership model of many OOP languages, that is all. */ - stream_type &stream() { return stream_; } - -protected: - stream_type &stream_; }; /* \struct binary_archive @@ -95,15 +90,18 @@ struct binary_archive; template <> -struct binary_archive : public binary_archive_base +struct binary_archive : public binary_archive_base { + explicit binary_archive(epee::span s) + : base_type(), bytes_(s), begin_(s.begin()), good_(true), varint_bug_backward_compatibility_(false) + {} - explicit binary_archive(stream_type &s) : base_type(s), varint_bug_backward_compatibility_(false) { - stream_type::pos_type pos = stream_.tellg(); - stream_.seekg(0, std::ios_base::end); - eof_pos_ = stream_.tellg(); - stream_.seekg(pos); - } + bool good() const noexcept { return good_; } + void set_fail() noexcept { good_ = false; } + + //! If implementing as `std::istream`, reset stream error state after `peek()` call. + bool eof() const noexcept { return bytes_.empty(); } + std::size_t getpos() const noexcept { return bytes_.begin() - begin_; } template void serialize_int(T &v) @@ -116,24 +114,24 @@ struct binary_archive : public binary_archive_base * \brief serializes an unsigned integer */ template - void serialize_uint(T &v, size_t width = sizeof(T)) + void serialize_uint(T &v) { - T ret = 0; - unsigned shift = 0; - for (size_t i = 0; i < width; i++) { - //std::cerr << "tell: " << stream_.tellg() << " value: " << ret << std::endl; - char c; - stream_.get(c); - T b = (unsigned char)c; - ret += (b << shift); // can this be changed to OR, i think it can. - shift += 8; + const std::size_t actual = bytes_.remove_prefix(sizeof(T)); + good_ &= (actual == sizeof(T)); + if (actual == sizeof(T)) + { + std::memcpy(std::addressof(v), bytes_.data() - sizeof(T), sizeof(T)); + boost::endian::little_to_native_inplace(v); // epee isn't templated } - v = ret; + else + v = 0; // ensures initialization } void serialize_blob(void *buf, size_t len, const char *delimiter="") { - stream_.read((char *)buf, len); + const std::size_t actual = bytes_.remove_prefix(len); + good_ &= (len == actual); + std::memcpy(buf, bytes_.data() - actual, actual); } template @@ -145,9 +143,11 @@ struct binary_archive : public binary_archive_base template void serialize_uvarint(T &v) { - typedef std::istreambuf_iterator it; - if (tools::read_varint(it(stream_), it(), v) < 0) - stream_.setstate(std::ios_base::failbit); + auto current = bytes_.cbegin(); + auto end = bytes_.cend(); + good_ &= (0 <= tools::read_varint(current, end, v)); + current = std::min(current, bytes_.cend()); + bytes_ = {current, std::size_t(bytes_.cend() - current)}; } void begin_array(size_t &s) @@ -166,26 +166,26 @@ struct binary_archive : public binary_archive_base serialize_int(t); } - size_t remaining_bytes() { - if (!stream_.good()) - return 0; - //std::cerr << "tell: " << stream_.tellg() << std::endl; - assert(stream_.tellg() <= eof_pos_); - return eof_pos_ - stream_.tellg(); - } - + size_t remaining_bytes() const noexcept { return good() ? bytes_.size() : 0; } void enable_varint_bug_backward_compatibility() { varint_bug_backward_compatibility_ = true; } bool varint_bug_backward_compatibility_enabled() const { return varint_bug_backward_compatibility_; } - protected: - std::streamoff eof_pos_; + epee::span bytes_; + std::uint8_t const* const begin_; + bool good_; bool varint_bug_backward_compatibility_; }; template <> -struct binary_archive : public binary_archive_base +struct binary_archive : public binary_archive_base { - explicit binary_archive(stream_type &s) : base_type(s) { } + typedef std::ostream stream_type; + explicit binary_archive(stream_type &s) : base_type(), stream_(s) { } + + bool good() const { return stream_.good(); } + void set_fail() { stream_.setstate(std::ios::failbit); } + + std::streampos getpos() const { return stream_.tellp(); } template void serialize_int(T v) @@ -234,6 +234,8 @@ struct binary_archive : public binary_archive_base } bool varint_bug_backward_compatibility_enabled() const { return false; } +protected: + stream_type& stream_; }; POP_WARNINGS diff --git a/src/serialization/binary_utils.h b/src/serialization/binary_utils.h index 8635585af..8444f220e 100644 --- a/src/serialization/binary_utils.h +++ b/src/serialization/binary_utils.h @@ -39,8 +39,7 @@ namespace serialization { template bool parse_binary(const std::string &blob, T &v) { - std::istringstream istr(blob); - binary_archive iar(istr); + binary_archive iar{epee::strspan(blob)}; return ::serialization::serialize(iar, v); } diff --git a/src/serialization/container.h b/src/serialization/container.h index a4997c8ae..77681ec93 100644 --- a/src/serialization/container.h +++ b/src/serialization/container.h @@ -67,13 +67,13 @@ bool do_serialize_container(Archive &ar, C &v) { size_t cnt; ar.begin_array(cnt); - if (!ar.stream().good()) + if (!ar.good()) return false; v.clear(); // very basic sanity check if (ar.remaining_bytes() < cnt) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } @@ -86,7 +86,7 @@ bool do_serialize_container(Archive &ar, C &v) if (!::serialization::detail::serialize_container_element(ar, e)) return false; ::serialization::detail::do_add(v, std::move(e)); - if (!ar.stream().good()) + if (!ar.good()) return false; } ar.end_array(); @@ -100,13 +100,13 @@ bool do_serialize_container(Archive &ar, C &v) ar.begin_array(cnt); for (auto i = v.begin(); i != v.end(); ++i) { - if (!ar.stream().good()) + if (!ar.good()) return false; if (i != v.begin()) ar.delimit_array(); if(!::serialization::detail::serialize_container_element(ar, (typename C::value_type&)*i)) return false; - if (!ar.stream().good()) + if (!ar.good()) return false; } ar.end_array(); diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index 42bd06e92..d635a9ee9 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -47,7 +47,7 @@ bool do_serialize(Archive &ar, std::vector &v) // very basic sanity check if (ar.remaining_bytes() < cnt*sizeof(crypto::signature)) { - ar.stream().setstate(std::ios::failbit); + ar.set_fail(); return false; } @@ -55,7 +55,7 @@ bool do_serialize(Archive &ar, std::vector &v) for (size_t i = 0; i < cnt; i++) { v.resize(i+1); ar.serialize_blob(&(v[i]), sizeof(crypto::signature), ""); - if (!ar.stream().good()) + if (!ar.good()) return false; } return true; @@ -70,7 +70,7 @@ bool do_serialize(Archive &ar, std::vector &v) size_t cnt = v.size(); for (size_t i = 0; i < cnt; i++) { ar.serialize_blob(&(v[i]), sizeof(crypto::signature), ""); - if (!ar.stream().good()) + if (!ar.good()) return false; } ar.end_string(); diff --git a/src/serialization/debug_archive.h b/src/serialization/debug_archive.h index b04d6ae19..e8ccb9a58 100644 --- a/src/serialization/debug_archive.h +++ b/src/serialization/debug_archive.h @@ -38,6 +38,7 @@ struct debug_archive : public json_archive { typedef typename json_archive::stream_type stream_type; debug_archive(stream_type &s) : json_archive(s) { } + stream_type& stream() { return this->stream_; } }; template diff --git a/src/serialization/difficulty_type.h b/src/serialization/difficulty_type.h index 56c0312e7..75d1fd13f 100644 --- a/src/serialization/difficulty_type.h +++ b/src/serialization/difficulty_type.h @@ -38,10 +38,10 @@ inline bool do_serialize(Archive& ar, cryptonote::difficulty_type &diff) { uint64_t hi, lo; ar.serialize_varint(hi); - if (!ar.stream().good()) + if (!ar.good()) return false; ar.serialize_varint(lo); - if (!ar.stream().good()) + if (!ar.good()) return false; diff = hi; diff <<= 64; @@ -52,13 +52,13 @@ inline bool do_serialize(Archive& ar, cryptonote::difficulty_type &diff) template