From 52d49b84eb58fd9b162eb45d22be6033a744350f Mon Sep 17 00:00:00 2001 From: Dmitry Antipov Date: Mon, 30 Jan 2023 21:04:40 +0300 Subject: [PATCH] perf: optimize the only block case in Cache::writeContiguous() (#4679) --- libtransmission/cache.cc | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/libtransmission/cache.cc b/libtransmission/cache.cc index 0b0852491..ef446b244 100644 --- a/libtransmission/cache.cc +++ b/libtransmission/cache.cc @@ -71,21 +71,30 @@ std::pair Cache::findContiguous(CIter const begin, C int Cache::writeContiguous(CIter const begin, CIter const end) const { - // join the blocks together into contiguous memory `buf` + // The most common case without an extra data copy. + auto const* towrite = begin->buf.get(); + + // Contiguous area to join more than one block, if any. auto buf = std::vector{}; - auto const buflen = std::accumulate( - begin, - end, - size_t{}, - [](size_t sum, auto const& block) { return sum + std::size(*block.buf); }); - buf.reserve(buflen); - for (auto iter = begin; iter != end; ++iter) + + if (end - begin > 1) { - TR_ASSERT(begin->key.first == iter->key.first); - TR_ASSERT(begin->key.second + std::distance(begin, iter) == iter->key.second); - buf.insert(std::end(buf), std::begin(*iter->buf), std::end(*iter->buf)); + // Yes, there are. + auto const buflen = std::accumulate( + begin, + end, + size_t{}, + [](size_t sum, auto const& block) { return sum + std::size(*block.buf); }); + buf.reserve(buflen); + for (auto iter = begin; iter != end; ++iter) + { + TR_ASSERT(begin->key.first == iter->key.first); + TR_ASSERT(begin->key.second + std::distance(begin, iter) == iter->key.second); + buf.insert(std::end(buf), std::begin(*iter->buf), std::end(*iter->buf)); + } + TR_ASSERT(std::size(buf) == buflen); + towrite = &buf; } - TR_ASSERT(std::size(buf) == buflen); // save it auto const& [torrent_id, block] = begin->key; @@ -97,13 +106,13 @@ int Cache::writeContiguous(CIter const begin, CIter const end) const auto const loc = tor->blockLoc(block); - if (auto const err = tr_ioWrite(tor, loc, std::size(buf), std::data(buf)); err != 0) + if (auto const err = tr_ioWrite(tor, loc, std::size(*towrite), std::data(*towrite)); err != 0) { return err; } ++disk_writes_; - disk_write_bytes_ += std::size(buf); + disk_write_bytes_ += std::size(*towrite); return {}; }