perf: use timer to flush outbuf to avoid taking lock frequently (#8423)

* perf: use timer to flush outbuf to avoid taking lock frequently

* code review: extract to `flush_outbuf_soon()`

* code review: make `flush_outbuf_trigger_` const
This commit is contained in:
Yat Ho
2026-02-12 00:21:31 +08:00
committed by GitHub
parent 831ebe6198
commit 4d695a8a4c
2 changed files with 38 additions and 19 deletions

View File

@@ -32,6 +32,7 @@
#include "libtransmission/peer-io.h"
#include "libtransmission/peer-socket.h" // tr_peer_socket, tr_netOpen...
#include "libtransmission/session.h"
#include "libtransmission/timer.h"
#include "libtransmission/tr-assert.h"
#include "libtransmission/utils.h" // for _()
@@ -84,6 +85,7 @@ tr_peerIo::tr_peerIo(
: bandwidth_{ parent_bandwidth }
, info_hash_{ info_hash != nullptr ? *info_hash : tr_sha1_digest_t{} }
, session_{ session }
, flush_outbuf_trigger_{ session->timerMaker().create() }
, client_is_seed_{ client_is_seed }
, is_incoming_{ is_incoming }
{
@@ -101,8 +103,18 @@ std::shared_ptr<tr_peerIo> tr_peerIo::create(
TR_ASSERT(session != nullptr);
auto lock = session->unique_lock();
auto io = std::make_shared<tr_peerIo>(session, std::move(socket), parent, info_hash, is_incoming, is_seed);
auto const io = std::shared_ptr<tr_peerIo>{
new tr_peerIo{ session, std::move(socket), parent, info_hash, is_incoming, is_seed }
};
io->bandwidth().set_peer(io);
io->flush_outbuf_trigger_->set_callback(
[weak = io->weak_from_this()]
{
if (auto const ptr = weak.lock())
{
ptr->try_write(SIZE_MAX);
}
});
tr_logAddTraceIo(io, fmt::format("bandwidth is {}; its parent is {}", fmt::ptr(&io->bandwidth()), fmt::ptr(parent)));
return io;
}
@@ -573,6 +585,11 @@ size_t tr_peerIo::flush_outgoing_protocol_msgs()
return flush(tr_direction::Up, byte_count);
}
void tr_peerIo::flush_outbuf_soon()
{
flush_outbuf_trigger_->start_single_shot(std::chrono::milliseconds::zero());
}
void tr_peerIo::write_bytes(void const* bytes, size_t n_bytes, bool is_piece_data)
{
if (n_bytes == 0U)
@@ -586,14 +603,7 @@ void tr_peerIo::write_bytes(void const* bytes, size_t n_bytes, bool is_piece_dat
filter_.encrypt(reinterpret_cast<std::byte const*>(bytes), n_bytes, resbuf);
outbuf_.commit_space(n_bytes);
session_->queue_session_thread(
[ptr = weak_from_this()]()
{
if (auto io = ptr.lock(); io)
{
io->try_write(SIZE_MAX);
}
});
flush_outbuf_soon();
}
// ---

View File

@@ -34,10 +34,15 @@ struct tr_error;
struct tr_session;
struct tr_socket_address;
namespace tr::test
namespace tr
{
class Timer;
namespace test
{
class HandshakeTest;
} // namespace tr::test
}
} // namespace tr
enum class ReadState : uint8_t
{
@@ -63,14 +68,6 @@ class tr_peerIo final : public std::enable_shared_from_this<tr_peerIo>
using GotError = void (*)(tr_peerIo* io, tr_error const& error, void* user_data);
public:
tr_peerIo(
tr_session* session,
tr_peer_socket&& socket,
tr_bandwidth* parent_bandwidth,
tr_sha1_digest_t const* info_hash,
bool is_incoming,
bool client_is_seed);
~tr_peerIo();
tr_peerIo(tr_peerIo const&) = delete;
@@ -325,6 +322,14 @@ private:
friend class tr::test::HandshakeTest;
tr_peerIo(
tr_session* session,
tr_peer_socket&& socket,
tr_bandwidth* parent_bandwidth,
tr_sha1_digest_t const* info_hash,
bool is_incoming,
bool client_is_seed);
[[nodiscard]] constexpr auto client_is_seed() const noexcept
{
return client_is_seed_;
@@ -345,6 +350,8 @@ private:
void close();
void flush_outbuf_soon();
static void event_read_cb(evutil_socket_t fd, short /*event*/, void* vio);
static void event_write_cb(evutil_socket_t fd, short /*event*/, void* vio);
@@ -388,6 +395,8 @@ private:
GotError got_error_ = nullptr;
void* user_data_ = nullptr;
std::unique_ptr<tr::Timer> const flush_outbuf_trigger_;
tr::evhelpers::event_unique_ptr event_read_;
tr::evhelpers::event_unique_ptr event_write_;