From 15056045bd3ce0045d15a0eeca12f44f3dd3f6ff Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Thu, 28 Jul 2022 10:01:59 -0500 Subject: [PATCH] perf: batch up calls to the RNG (#3537) --- libtransmission/crypto-utils.h | 26 +++++ libtransmission/peer-mgr-wishlist.cc | 5 +- libtransmission/peer-mgr.cc | 26 +++-- libtransmission/rpcimpl.cc | 2 - tests/libtransmission/crypto-test-ref.h | 129 ++++++++++++------------ 5 files changed, 111 insertions(+), 77 deletions(-) diff --git a/libtransmission/crypto-utils.h b/libtransmission/crypto-utils.h index 7d87f9a68..851225b8b 100644 --- a/libtransmission/crypto-utils.h +++ b/libtransmission/crypto-utils.h @@ -6,6 +6,7 @@ #ifndef TR_CRYPTO_UTILS_H #define TR_CRYPTO_UTILS_H +#include #include // size_t #include #include @@ -190,6 +191,31 @@ std::string tr_sha256_to_string(tr_sha256_digest_t const&); */ std::optional tr_sha256_from_string(std::string_view hex); +// Convenience utility to efficiently get many random small values. +// Use this instead of making a lot of calls to tr_rand_int(). +class tr_salt_shaker +{ +public: + [[nodiscard]] auto operator()() noexcept + { + if (pos == std::size(buf)) + { + pos = 0U; + } + + if (pos == 0U) + { + tr_rand_buffer(std::data(buf), std::size(buf)); + } + + return buf[pos++]; + } + +private: + size_t pos = 0; + std::array buf; +}; + /** @} */ #endif /* TR_CRYPTO_UTILS_H */ diff --git a/libtransmission/peer-mgr-wishlist.cc b/libtransmission/peer-mgr-wishlist.cc index 0bc404101..62acb172a 100644 --- a/libtransmission/peer-mgr-wishlist.cc +++ b/libtransmission/peer-mgr-wishlist.cc @@ -87,15 +87,14 @@ std::vector getCandidates(Wishlist::Mediator const& mediator) } // transform them into candidates + auto salter = tr_salt_shaker{}; auto const n = std::size(wanted_pieces); - auto saltbuf = std::vector(n); - tr_rand_buffer(std::data(saltbuf), n); auto candidates = std::vector{}; candidates.reserve(n); for (size_t i = 0; i < n; ++i) { auto const [piece, n_missing] = wanted_pieces[i]; - candidates.emplace_back(piece, n_missing, mediator.priority(piece), saltbuf[i]); + candidates.emplace_back(piece, n_missing, mediator.priority(piece), salter()); } return candidates; diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index a801bb6b2..a7ba84e93 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -1869,9 +1869,10 @@ enum tr_rechoke_state struct tr_rechoke_info { - tr_rechoke_info(tr_peerMsgs* peer_in, int rechoke_state_in) + tr_rechoke_info(tr_peerMsgs* peer_in, int rechoke_state_in, uint8_t salt_in) : peer{ peer_in } , rechoke_state{ rechoke_state_in } + , salt{ salt_in } { } @@ -1882,7 +1883,12 @@ struct tr_rechoke_info return this->rechoke_state - that.rechoke_state; } - return this->salt - that.salt; + if (this->salt != that.salt) + { + return this->salt < that.salt ? -1 : 1; + } + + return 0; } [[nodiscard]] constexpr auto operator<(tr_rechoke_info const& that) const noexcept @@ -1892,7 +1898,7 @@ struct tr_rechoke_info tr_peerMsgs* peer; int rechoke_state; - int salt = tr_rand_int_weak(INT_MAX); + uint8_t salt; }; } // namespace @@ -1908,6 +1914,7 @@ void rechokeDownloads(tr_swarm* s) uint16_t max_peers = 0; auto rechoke = std::vector{}; + auto salter = tr_salt_shaker{}; /* some cases where this function isn't necessary */ if (s->tor->isDone() || !s->tor->clientCanDownload()) @@ -2035,7 +2042,7 @@ void rechokeDownloads(tr_swarm* s) rechoke_state = RECHOKE_STATE_BAD; } - rechoke.emplace_back(peer, rechoke_state); + rechoke.emplace_back(peer, rechoke_state, salter()); } } @@ -2083,7 +2090,7 @@ struct ChokeData bool wasChoked; bool isChoked; int rate; - int salt; + uint8_t salt; tr_peerMsgs* msgs; [[nodiscard]] constexpr auto compare(ChokeData const& that) const noexcept // <=> @@ -2100,7 +2107,7 @@ struct ChokeData if (this->salt != that.salt) // random order { - return this->salt - that.salt; + return this->salt < that.salt ? -1 : 1; } return 0; @@ -2169,6 +2176,7 @@ void rechokeUploads(tr_swarm* s, uint64_t const now) int size = 0; /* sort the peers by preference and rate */ + auto salter = tr_salt_shaker{}; for (auto* const peer : peers) { if (peer->isSeed()) @@ -2188,7 +2196,7 @@ void rechokeUploads(tr_swarm* s, uint64_t const now) n->isInterested = peer->is_peer_interested(); n->wasChoked = peer->is_peer_choked(); n->rate = getRateBps(s->tor, peer, now); - n->salt = tr_rand_int_weak(INT_MAX); + n->salt = salter(); n->isChoked = true; } } @@ -2753,6 +2761,7 @@ struct peer_candidate candidates.reserve(atom_count); /* populate the candidate array */ + auto salter = tr_salt_shaker{}; for (auto* tor : session->torrents()) { if (!tor->swarm->is_running) @@ -2784,8 +2793,7 @@ struct peer_candidate { if (isPeerCandidate(tor, atom, now)) { - uint8_t const salt = tr_rand_int_weak(1024); - candidates.push_back({ getPeerCandidateScore(tor, atom, salt), tor, &atom }); + candidates.push_back({ getPeerCandidateScore(tor, atom, salter()), tor, &atom }); } } } diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index b8b605273..1b1b27d2d 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -479,8 +479,6 @@ static void addPeers(tr_torrent const* tor, tr_variant* list) static void initField(tr_torrent const* const tor, tr_stat const* const st, tr_variant* const initme, tr_quark key) { - char* str = nullptr; - switch (key) { case TR_KEY_activityDate: diff --git a/tests/libtransmission/crypto-test-ref.h b/tests/libtransmission/crypto-test-ref.h index 74ba76fc1..4053c542c 100644 --- a/tests/libtransmission/crypto-test-ref.h +++ b/tests/libtransmission/crypto-test-ref.h @@ -10,30 +10,21 @@ #ifdef CRYPTO_REFERENCE_CHECK -#define tr_sha1_ctx_t tr_sha1_ctx_t_ -#define tr_ssl_ctx_t tr_ssl_ctx_t_ -#define tr_x509_store_t tr_x509_store_t_ -#define tr_x509_cert_t tr_x509_cert_t_ -#define tr_sha1 tr_sha1_ -#define tr_sha1_init tr_sha1_init_ -#define tr_sha1_update tr_sha1_update_ -#define tr_sha1_final tr_sha1_final_ -#define tr_ssl_get_x509_store tr_ssl_get_x509_store_ -#define tr_x509_store_add tr_x509_store_add_ -#define tr_x509_cert_new tr_x509_cert_new_ -#define tr_x509_cert_free tr_x509_cert_free_ -#define tr_rand_int tr_rand_int_ -#define tr_rand_int_weak tr_rand_int_weak_ -#define tr_rand_buffer tr_rand_buffer_ -#define tr_ssha1 tr_ssha1_ -#define tr_ssha1_matches tr_ssha1_matches_ -#define tr_ssha1_test tr_ssha1_test_ -#define tr_base64_encode tr_base64_encode_ -#define tr_base64_encode_impl tr_base64_encode_impl_ #define tr_base64_decode tr_base64_decode_ #define tr_base64_decode_impl tr_base64_decode_impl_ -#define tr_sha1_to_string tr_sha1_to_string_ +#define tr_base64_encode tr_base64_encode_ +#define tr_base64_encode_impl tr_base64_encode_impl_ +#define tr_rand_buffer tr_rand_buffer_ +#define tr_rand_int tr_rand_int_ +#define tr_rand_int_weak tr_rand_int_weak_ +#define tr_salt_shaker tr_salt_shaker_ +#define tr_sha1 tr_sha1_ +#define tr_sha1_ctx_t tr_sha1_ctx_t_ +#define tr_sha1_final tr_sha1_final_ #define tr_sha1_from_string tr_sha1_from_string_ +#define tr_sha1_init tr_sha1_init_ +#define tr_sha1_to_string tr_sha1_to_string_ +#define tr_sha1_update tr_sha1_update_ #define tr_sha256 tr_sha256_ #define tr_sha256_ctx_t tr_sha256_ctx_t_ #define tr_sha256_final tr_sha256_final_ @@ -41,6 +32,16 @@ #define tr_sha256_init tr_sha256_init_ #define tr_sha256_to_string tr_sha256_to_string_ #define tr_sha256_update tr_sha256_update_ +#define tr_ssha1 tr_ssha1_ +#define tr_ssha1_matches tr_ssha1_matches_ +#define tr_ssha1_test tr_ssha1_test_ +#define tr_ssl_ctx_t tr_ssl_ctx_t_ +#define tr_ssl_get_x509_store tr_ssl_get_x509_store_ +#define tr_x509_cert_free tr_x509_cert_free_ +#define tr_x509_cert_new tr_x509_cert_new_ +#define tr_x509_cert_t tr_x509_cert_t_ +#define tr_x509_store_add tr_x509_store_add_ +#define tr_x509_store_t tr_x509_store_t_ #undef TR_ENCRYPTION_H #undef TR_CRYPTO_UTILS_H @@ -49,30 +50,21 @@ #include "crypto-utils.cc" #include "crypto-utils-openssl.cc" -#undef tr_sha1_ctx_t -#undef tr_ssl_ctx_t -#undef tr_x509_store_t -#undef tr_x509_cert_t -#undef tr_sha1 -#undef tr_sha1_init -#undef tr_sha1_update -#undef tr_sha1_final -#undef tr_ssl_get_x509_store -#undef tr_x509_store_add -#undef tr_x509_cert_new -#undef tr_x509_cert_free -#undef tr_rand_int -#undef tr_rand_int_weak -#undef tr_rand_buffer -#undef tr_ssha1 -#undef tr_ssha1_matches -#undef tr_ssha1_test -#undef tr_base64_encode -#undef tr_base64_encode_impl #undef tr_base64_decode #undef tr_base64_decode_impl -#undef tr_sha1_to_string +#undef tr_base64_encode +#undef tr_base64_encode_impl +#undef tr_rand_buffer +#undef tr_rand_int +#undef tr_rand_int_weak +#undef tr_salt_shaker +#undef tr_sha1 +#undef tr_sha1_ctx_t +#undef tr_sha1_final #undef tr_sha1_from_string +#undef tr_sha1_init +#undef tr_sha1_to_string +#undef tr_sha1_update #undef tr_sha256 #undef tr_sha256_ctx_t #undef tr_sha256_final @@ -80,33 +72,34 @@ #undef tr_sha256_init #undef tr_sha256_to_string #undef tr_sha256_update +#undef tr_ssha1 +#undef tr_ssha1_matches +#undef tr_ssha1_test +#undef tr_ssl_ctx_t +#undef tr_ssl_get_x509_store +#undef tr_x509_cert_free +#undef tr_x509_cert_new +#undef tr_x509_cert_t +#undef tr_x509_store_add +#undef tr_x509_store_t #else /* CRYPTO_REFERENCE_CHECK */ -#define tr_sha1_ctx_t_ tr_sha1_ctx_t -#define tr_ssl_ctx_t_ tr_ssl_ctx_t -#define tr_x509_store_t_ tr_x509_store_t -#define tr_x509_cert_t_ tr_x509_cert_t -#define tr_sha1_ tr_sha1 -#define tr_sha1_init_ tr_sha1_init -#define tr_sha1_update_ tr_sha1_update -#define tr_sha1_final_ tr_sha1_final -#define tr_ssl_get_x509_store_ tr_ssl_get_x509_store -#define tr_x509_store_add_ tr_x509_store_add -#define tr_x509_cert_new_ tr_x509_cert_new -#define tr_x509_cert_free_ tr_x509_cert_free -#define tr_rand_int_ tr_rand_int -#define tr_rand_int_weak_ tr_rand_int_weak -#define tr_rand_buffer_ tr_rand_buffer -#define tr_ssha1_ tr_ssha1 -#define tr_ssha1_matches_ tr_ssha1_matches -#define tr_ssha1_test_ tr_ssha1_test -#define tr_base64_encode_ tr_base64_encode -#define tr_base64_encode_impl_ tr_base64_encode_impl #define tr_base64_decode_ tr_base64_decode #define tr_base64_decode_impl_ tr_base64_decode_impl -#define tr_sha1_to_string_ tr_sha1_to_string +#define tr_base64_encode_ tr_base64_encode +#define tr_base64_encode_impl_ tr_base64_encode_impl +#define tr_rand_buffer_ tr_rand_buffer +#define tr_rand_int_ tr_rand_int +#define tr_rand_int_weak_ tr_rand_int_weak +#define tr_salt_shaker_ tr_salt_shaker +#define tr_sha1_ tr_sha1 +#define tr_sha1_ctx_t_ tr_sha1_ctx_t +#define tr_sha1_final_ tr_sha1_final #define tr_sha1_from_string_ tr_sha1_from_string +#define tr_sha1_init_ tr_sha1_init +#define tr_sha1_to_string_ tr_sha1_to_string +#define tr_sha1_update_ tr_sha1_update #define tr_sha256_ tr_sha256 #define tr_sha256_ctx_t_ tr_sha256_ctx_t #define tr_sha256_final_ tr_sha256_final @@ -114,6 +107,16 @@ #define tr_sha256_init_ tr_sha256_init #define tr_sha256_to_string_ tr_sha256_to_string #define tr_sha256_update_ tr_sha256_update +#define tr_ssha1_ tr_ssha1 +#define tr_ssha1_matches_ tr_ssha1_matches +#define tr_ssha1_test_ tr_ssha1_test +#define tr_ssl_ctx_t_ tr_ssl_ctx_t +#define tr_ssl_get_x509_store_ tr_ssl_get_x509_store +#define tr_x509_cert_free_ tr_x509_cert_free +#define tr_x509_cert_new_ tr_x509_cert_new +#define tr_x509_cert_t_ tr_x509_cert_t +#define tr_x509_store_add_ tr_x509_store_add +#define tr_x509_store_t_ tr_x509_store_t #endif /* CRYPTO_REFERENCE_CHECK */