perf: in cache, flush biggest contiguous blocks (#5671)

This commit is contained in:
Charles Kerr 2023-06-27 12:08:29 -05:00
parent b86afe185b
commit d2200cf9ea
2 changed files with 49 additions and 63 deletions

View File

@ -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); return std::make_pair(torrent->id(), loc.block);
} }
std::pair<Cache::CIter, Cache::CIter> 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); 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);
auto span_begin = iter; return span_end == end ? end : std::next(span_end);
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);
} }
int Cache::writeContiguous(CIter const begin, CIter const end) const std::pair<Cache::CIter, Cache::CIter> 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. // The most common case without an extra data copy.
auto const* towrite = begin->buf.get(); 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->key = key;
} }
iter->time_added = tr_time();
iter->buf = std::move(writeme); iter->buf = std::move(writeme);
++cache_writes_; ++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; return err;
} }
walk = contig_end; span_begin = span_end;
} }
blocks_.erase(begin, 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 tor_id = torrent->id();
auto const [block_begin, block_end] = tr_torGetFileBlockSpan(torrent, file); 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_begin), compare),
std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id, block_end), 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 compare = CompareCacheBlockByKey{};
auto const tor_id = torrent->id(); 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, 0), compare),
std::lower_bound(std::begin(blocks_), std::end(blocks_), std::make_pair(tor_id + 1, 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( auto const [begin, end] = find_biggest_span(std::begin(blocks_), std::end(blocks_));
std::begin(blocks_),
std::end(blocks_),
[](auto const& a, auto const& b) { return a.time_added < b.time_added; });
if (oldest == std::end(blocks_)) // nothing to flush if (begin == end) // nothing to flush
{ {
return 0; return 0;
} }
auto const [begin, end] = findContiguous(std::begin(blocks_), std::end(blocks_), oldest); if (auto const err = write_contiguous(begin, end); err != 0)
if (auto const err = writeContiguous(begin, end); err != 0)
{ {
return err; return err;
} }
@ -264,7 +250,7 @@ int Cache::cacheTrim()
{ {
while (std::size(blocks_) > max_blocks_) while (std::size(blocks_) > max_blocks_)
{ {
if (auto const err = flushOldest(); err != 0) if (auto const err = flush_biggest(); err != 0)
{ {
return err; return err;
} }

View File

@ -11,7 +11,6 @@
#include <cstdint> // for size_t #include <cstdint> // for size_t
#include <cstdint> // for intX_t, uintX_t #include <cstdint> // for intX_t, uintX_t
#include <ctime>
#include <memory> // for std::unique_ptr #include <memory> // for std::unique_ptr
#include <utility> // for std::pair #include <utility> // for std::pair
#include <vector> #include <vector>
@ -50,7 +49,6 @@ private:
{ {
Key key; Key key;
std::unique_ptr<std::vector<uint8_t>> buf; std::unique_ptr<std::vector<uint8_t>> buf;
time_t time_added = {};
}; };
using Blocks = std::vector<CacheBlock>; using Blocks = std::vector<CacheBlock>;
@ -70,16 +68,18 @@ private:
[[nodiscard]] static Key makeKey(tr_torrent const* torrent, tr_block_info::Location loc) noexcept; [[nodiscard]] static Key makeKey(tr_torrent const* torrent, tr_block_info::Location loc) noexcept;
[[nodiscard]] static std::pair<CIter, CIter> findContiguous(CIter const begin, CIter const end, CIter const iter) noexcept; [[nodiscard]] static std::pair<CIter, CIter> 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() // @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() // @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() // @return any error code from writeContiguous()
[[nodiscard]] int flushOldest(); [[nodiscard]] int flush_biggest();
// @return any error code from writeContiguous() // @return any error code from writeContiguous()
[[nodiscard]] int cacheTrim(); [[nodiscard]] int cacheTrim();