From d2200cf9ea8c457ef3c82f5591991998eeb97de5 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 27 Jun 2023 12:08:29 -0500 Subject: [PATCH] perf: in cache, flush biggest contiguous blocks (#5671) --- libtransmission/cache.cc | 100 +++++++++++++++++---------------------- libtransmission/cache.h | 12 ++--- 2 files changed, 49 insertions(+), 63 deletions(-) diff --git a/libtransmission/cache.cc b/libtransmission/cache.cc index f7ae03dcc..3b58722b2 100644 --- a/libtransmission/cache.cc +++ b/libtransmission/cache.cc @@ -28,48 +28,41 @@ Cache::Key Cache::makeKey(tr_torrent const* torrent, tr_block_info::Location loc return std::make_pair(torrent->id(), loc.block); } -std::pair Cache::findContiguous(CIter const begin, CIter const end, CIter const iter) noexcept +Cache::CIter Cache::find_span_end(CIter span_begin, CIter end) noexcept { - if (iter == end) + static constexpr auto NotAdjacent = [](CacheBlock const& block1, CacheBlock const& block2) { - return std::make_pair(end, end); - } - - auto span_begin = iter; - for (auto key = iter->key;;) - { - if (span_begin == begin) - { - break; - } - - --key.second; - auto const prev = std::prev(span_begin); - if (prev->key != key) - { - break; - } - } - - auto span_end = std::next(iter); - for (auto key = iter->key;;) - { - if (span_end == end) - { - break; - } - - ++key.second; - if (span_end->key != key) - { - break; - } - } - - return std::make_pair(span_begin, span_end); + return block1.key.first != block2.key.first || block1.key.second + 1 != block2.key.second; + }; + auto const span_end = std::adjacent_find(span_begin, end, NotAdjacent); + return span_end == end ? end : std::next(span_end); } -int Cache::writeContiguous(CIter const begin, CIter const end) const +std::pair Cache::find_biggest_span(CIter const begin, CIter const end) noexcept +{ + auto biggest_begin = begin; + auto biggest_end = begin; + auto biggest_len = std::distance(biggest_begin, biggest_end); + + for (auto span_begin = begin; span_begin < end;) + { + auto span_end = find_span_end(span_begin, end); + auto const len = std::distance(span_begin, span_end); + + if (len > biggest_len) + { + biggest_begin = span_begin; + biggest_end = span_end; + biggest_len = len; + } + + std::advance(span_begin, len); + } + + return { biggest_begin, biggest_end }; +} + +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(); @@ -150,8 +143,6 @@ int Cache::writeBlock(tr_torrent_id_t tor_id, tr_block_index_t block, std::uniqu iter->key = key; } - iter->time_added = tr_time(); - iter->buf = std::move(writeme); ++cache_writes_; @@ -198,18 +189,18 @@ int Cache::prefetchBlock(tr_torrent* torrent, tr_block_info::Location loc, uint3 // --- -int Cache::flushSpan(CIter const begin, CIter const end) +int Cache::flush_span(CIter const begin, CIter const end) { - for (auto walk = begin; walk < end;) + for (auto span_begin = begin; span_begin < end;) { - auto const [contig_begin, contig_end] = findContiguous(begin, end, walk); + auto const span_end = find_span_end(span_begin, end); - if (auto const err = writeContiguous(contig_begin, contig_end); err != 0) + if (auto const err = write_contiguous(span_begin, span_end); err != 0) { return err; } - walk = contig_end; + span_begin = span_end; } blocks_.erase(begin, end); @@ -222,7 +213,7 @@ int Cache::flushFile(tr_torrent const* torrent, tr_file_index_t file) auto const tor_id = torrent->id(); auto const [block_begin, block_end] = tr_torGetFileBlockSpan(torrent, file); - return flushSpan( + return flush_span( std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id, block_begin), compare), std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id, block_end), compare)); } @@ -232,26 +223,21 @@ int Cache::flushTorrent(tr_torrent const* torrent) auto const compare = CompareCacheBlockByKey{}; auto const tor_id = torrent->id(); - return flushSpan( + return flush_span( std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id, 0), compare), std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id + 1, 0), compare)); } -int Cache::flushOldest() +int Cache::flush_biggest() { - auto const oldest = std::min_element( - std::begin(blocks_), - std::end(blocks_), - [](auto const& a, auto const& b) { return a.time_added < b.time_added; }); + auto const [begin, end] = find_biggest_span(std::begin(blocks_), std::end(blocks_)); - if (oldest == std::end(blocks_)) // nothing to flush + if (begin == end) // nothing to flush { return 0; } - auto const [begin, end] = findContiguous(std::begin(blocks_), std::end(blocks_), oldest); - - if (auto const err = writeContiguous(begin, end); err != 0) + if (auto const err = write_contiguous(begin, end); err != 0) { return err; } @@ -264,7 +250,7 @@ int Cache::cacheTrim() { while (std::size(blocks_) > max_blocks_) { - if (auto const err = flushOldest(); err != 0) + if (auto const err = flush_biggest(); err != 0) { return err; } diff --git a/libtransmission/cache.h b/libtransmission/cache.h index 9d6455610..9ff0a972b 100644 --- a/libtransmission/cache.h +++ b/libtransmission/cache.h @@ -11,7 +11,6 @@ #include // for size_t #include // for intX_t, uintX_t -#include #include // for std::unique_ptr #include // for std::pair #include @@ -50,7 +49,6 @@ private: { Key key; std::unique_ptr> buf; - time_t time_added = {}; }; using Blocks = std::vector; @@ -70,16 +68,18 @@ private: [[nodiscard]] static Key makeKey(tr_torrent const* torrent, tr_block_info::Location loc) noexcept; - [[nodiscard]] static std::pair findContiguous(CIter const begin, CIter const end, CIter const iter) noexcept; + [[nodiscard]] static std::pair find_biggest_span(CIter begin, CIter end) noexcept; + + [[nodiscard]] static CIter find_span_end(CIter span_begin, CIter end) noexcept; // @return any error code from tr_ioWrite() - [[nodiscard]] int writeContiguous(CIter const begin, CIter const end) const; + [[nodiscard]] int write_contiguous(CIter begin, CIter end) const; // @return any error code from writeContiguous() - [[nodiscard]] int flushSpan(CIter const begin, CIter const end); + [[nodiscard]] int flush_span(CIter begin, CIter end); // @return any error code from writeContiguous() - [[nodiscard]] int flushOldest(); + [[nodiscard]] int flush_biggest(); // @return any error code from writeContiguous() [[nodiscard]] int cacheTrim();