1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-03-04 02:28:03 +00:00

perf: avoid extra heap alloc in block cache (#5522)

This commit is contained in:
Charles Kerr 2023-05-13 14:16:00 -05:00 committed by GitHub
parent 69fc149f07
commit 8a1a6dba49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 18 deletions

View file

@ -73,7 +73,8 @@ std::pair<Cache::CIter, Cache::CIter> Cache::find_contiguous(CIter const begin,
int Cache::write_contiguous(CIter const begin, CIter const end) const
{
// The most common case without an extra data copy.
auto const* towrite = begin->buf.get();
auto const* out = std::data(*begin->buf);
auto outlen = std::size(*begin->buf);
// Contiguous area to join more than one block, if any.
auto buf = std::vector<uint8_t>{};
@ -94,7 +95,8 @@ int Cache::write_contiguous(CIter const begin, CIter const end) const
buf.insert(std::end(buf), std::begin(*iter->buf), std::end(*iter->buf));
}
TR_ASSERT(std::size(buf) == buflen);
towrite = &buf;
out = std::data(buf);
outlen = std::size(buf);
}
// save it
@ -107,13 +109,13 @@ int Cache::write_contiguous(CIter const begin, CIter const end) const
auto const loc = tor->block_loc(block);
if (auto const err = tr_ioWrite(tor, loc, std::size(*towrite), std::data(*towrite)); err != 0)
if (auto const err = tr_ioWrite(tor, loc, outlen, out); err != 0)
{
return err;
}
++disk_writes_;
disk_write_bytes_ += std::size(*towrite);
disk_write_bytes_ += outlen;
return {};
}
@ -141,7 +143,7 @@ Cache::Cache(tr_torrents& torrents, int64_t max_bytes)
// ---
int Cache::write_block(tr_torrent_id_t tor_id, tr_block_index_t block, std::unique_ptr<std::vector<uint8_t>> writeme)
int Cache::write_block(tr_torrent_id_t tor_id, tr_block_index_t block, std::unique_ptr<BlockData> writeme)
{
auto const key = Key{ tor_id, block };
auto iter = std::lower_bound(std::begin(blocks_), std::end(blocks_), key, CompareCacheBlockByKey{});

View file

@ -26,6 +26,44 @@ struct tr_torrent;
class Cache
{
public:
class BlockData
{
public:
BlockData(size_t size)
: size_{ size }
{
}
[[nodiscard]] constexpr auto size() const noexcept
{
return size_;
}
[[nodiscard]] constexpr auto* data() noexcept
{
return std::data(data_);
}
[[nodiscard]] constexpr const auto* data() const noexcept
{
return std::data(data_);
}
[[nodiscard]] constexpr auto* begin() const noexcept
{
return data();
}
[[nodiscard]] constexpr auto* end() const noexcept
{
return begin() + size();
}
private:
std::array<uint8_t, tr_block_info::BlockSize> data_;
size_t const size_;
};
Cache(tr_torrents& torrents, int64_t max_bytes);
int set_limit(int64_t new_limit);
@ -36,7 +74,7 @@ public:
}
// @return any error code from cacheTrim()
int write_block(tr_torrent_id_t tor, tr_block_index_t block, std::unique_ptr<std::vector<uint8_t>> writeme);
int write_block(tr_torrent_id_t tor, tr_block_index_t block, std::unique_ptr<BlockData> writeme);
int read_block(tr_torrent* torrent, tr_block_info::Location const& loc, uint32_t len, uint8_t* setme);
int prefetch_block(tr_torrent* torrent, tr_block_info::Location const& loc, uint32_t len);
@ -49,7 +87,7 @@ private:
struct CacheBlock
{
Key key;
std::unique_ptr<std::vector<uint8_t>> buf;
std::unique_ptr<BlockData> buf;
time_t time_added = {};
};

View file

@ -224,7 +224,7 @@ struct tr_incoming
struct incoming_piece_data
{
explicit incoming_piece_data(uint32_t block_size)
: buf{ std::make_unique<std::vector<uint8_t>>(block_size) }
: buf{ std::make_unique<Cache::BlockData>(block_size) }
, block_size_{ block_size }
{
}
@ -249,7 +249,7 @@ struct tr_incoming
return have_.count() >= block_size_;
}
std::unique_ptr<std::vector<uint8_t>> buf;
std::unique_ptr<Cache::BlockData> buf;
private:
std::bitset<tr_block_info::BlockSize> have_;
@ -1347,7 +1347,7 @@ void peerMadeRequest(tr_peerMsgsImpl* msgs, struct peer_request const* req)
}
}
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<std::vector<uint8_t>> block_data, tr_block_index_t block);
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<Cache::BlockData> block_data, tr_block_index_t block);
ReadResult read_piece_data(tr_peerMsgsImpl* msgs, PeerMessageReader& payload)
{
@ -1645,7 +1645,7 @@ ReadResult process_peer_message(tr_peerMsgsImpl* msgs, uint8_t id, PeerMessageRe
}
/* returns 0 on success, or an errno on failure */
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<std::vector<uint8_t>> block_data, tr_block_index_t const block)
int clientGotBlock(tr_peerMsgsImpl* msgs, std::unique_ptr<Cache::BlockData> block_data, tr_block_index_t const block)
{
TR_ASSERT(msgs != nullptr);

View file

@ -338,7 +338,7 @@ public:
tr_session* session,
tr_torrent_id_t tor_id,
tr_block_index_t block,
std::unique_ptr<std::vector<uint8_t>>& data,
std::unique_ptr<Cache::BlockData> data,
tr_webseed* webseed)
: session_{ session }
, tor_id_{ tor_id }
@ -363,7 +363,7 @@ private:
tr_session* const session_;
tr_torrent_id_t const tor_id_;
tr_block_index_t const block_;
std::unique_ptr<std::vector<uint8_t>> data_;
std::unique_ptr<Cache::BlockData> data_;
tr_webseed* const webseed_;
};
@ -394,10 +394,9 @@ void useFetchedBlocks(tr_webseed_task* task)
}
else
{
auto block_buf = std::make_unique<std::vector<uint8_t>>();
block_buf->resize(block_size);
auto block_buf = std::make_unique<Cache::BlockData>(block_size);
evbuffer_remove(task->content(), std::data(*block_buf), std::size(*block_buf));
auto* const data = new write_block_data{ session, tor->id(), task->loc.block, block_buf, webseed };
auto* const data = new write_block_data{ session, tor->id(), task->loc.block, std::move(block_buf), webseed };
session->runInSessionThread(&write_block_data::write_block_func, data);
}

View file

@ -76,7 +76,7 @@ TEST_P(IncompleteDirTest, incompleteDir)
tr_torrent* tor = {};
tr_block_index_t block = {};
tr_piece_index_t pieceIndex = {};
std::unique_ptr<std::vector<uint8_t>> buf = {};
std::unique_ptr<Cache::BlockData> buf = {};
bool done = {};
};
@ -97,7 +97,8 @@ TEST_P(IncompleteDirTest, incompleteDir)
for (tr_block_index_t block_index = begin; block_index < end; ++block_index)
{
data.buf = std::make_unique<std::vector<uint8_t>>(tr_block_info::BlockSize, '\0');
data.buf = std::make_unique<Cache::BlockData>(tr_block_info::BlockSize);
std::fill_n(std::data(*data.buf), tr_block_info::BlockSize, '\0');
data.block = block_index;
data.done = false;
session_->runInSessionThread(test_incomplete_dir_threadfunc, &data);