From 0dafee517882196894e7959da3554c200d822f41 Mon Sep 17 00:00:00 2001 From: Yingxin Cheng Date: Mon, 2 Sep 2024 10:30:31 +0800 Subject: [PATCH] crimson/os/seastore/cache: report cache access stats Signed-off-by: Yingxin Cheng --- src/crimson/os/seastore/cache.cc | 64 +++++++++++++++++++- src/crimson/os/seastore/cache.h | 4 ++ src/crimson/os/seastore/seastore.cc | 13 ++++ src/crimson/os/seastore/seastore_types.cc | 74 +++++++++++++++++++++++ src/crimson/os/seastore/seastore_types.h | 67 ++++++++++++++++++++ 5 files changed, 221 insertions(+), 1 deletion(-) diff --git a/src/crimson/os/seastore/cache.cc b/src/crimson/os/seastore/cache.cc index e1c82a577a4d5..cf8d3c0891d7f 100644 --- a/src/crimson/os/seastore/cache.cc +++ b/src/crimson/os/seastore/cache.cc @@ -150,6 +150,9 @@ void Cache::register_metrics() last_dirty_io_by_src_ext = {}; last_trim_rewrites = {}; last_reclaim_rewrites = {}; + last_access = {}; + last_cache_absent_by_src = {}; + last_access_by_src_ext = {}; namespace sm = seastar::metrics; using src_t = Transaction::src_t; @@ -2257,12 +2260,17 @@ cache_stats_t Cache::get_stats( lru.get_stats(ret, report_detail, seconds); /* - * get dirty stats + * dirty stats + * rewrite stats + * index stats + * access stats */ ret.dirty_sizes = cache_size_stats_t{stats.dirty_bytes, dirty.size()}; ret.dirty_io = stats.dirty_io; ret.dirty_io.minus(last_dirty_io); + ret.access = stats.access; + ret.access.minus(last_access); if (report_detail && seconds != 0) { counter_by_src_t > @@ -2357,14 +2365,68 @@ cache_stats_t Cache::get_stats( oss << "\ncache total" << cache_size_stats_t{extents_index.get_bytes(), extents_index.size()}; + counter_by_src_t > + _access_by_src_ext = stats.access_by_src_ext; + counter_by_src_t access_by_src; + for (uint8_t _src=0; _src(_src); + cache_access_stats_t& trans_access = get_by_src(access_by_src, src); + trans_access.cache_absent = get_by_src(stats.cache_absent_by_src, src); + trans_access.cache_absent -= get_by_src(last_cache_absent_by_src, src); + auto& access_by_ext = get_by_src(_access_by_src_ext, src); + const auto& last_access_by_ext = get_by_src(last_access_by_src_ext, src); + for (uint8_t _ext=0; _ext(_ext); + extent_access_stats_t& extent_access = get_by_ext(access_by_ext, ext); + const auto& last_extent_access = get_by_ext(last_access_by_ext, ext); + extent_access.minus(last_extent_access); + trans_access.s.add(extent_access); + } + } + oss << "\naccess: total" + << cache_access_stats_printer_t{seconds, ret.access}; + for (uint8_t _src=0; _src(_src); + const auto& trans_access = get_by_src(access_by_src, src); + if (trans_access.is_empty()) { + continue; + } + extent_access_stats_t data_access; + extent_access_stats_t mdat_access; + extent_access_stats_t phys_access; + const auto& access_by_ext = get_by_src(_access_by_src_ext, src); + for (uint8_t _ext=0; _ext(_ext); + const auto& extent_access = get_by_ext(access_by_ext, ext); + if (is_data_type(ext)) { + data_access.add(extent_access); + } else if (is_logical_metadata_type(ext)) { + mdat_access.add(extent_access); + } else if (is_physical_type(ext)) { + phys_access.add(extent_access); + } + } + oss << "\n " << src << ": " + << cache_access_stats_printer_t{seconds, trans_access} + << "\n data" + << extent_access_stats_printer_t{seconds, data_access} + << "\n mdat" + << extent_access_stats_printer_t{seconds, mdat_access} + << "\n phys" + << extent_access_stats_printer_t{seconds, phys_access}; + } + INFO("{}", oss.str()); last_dirty_io_by_src_ext = stats.dirty_io_by_src_ext; last_trim_rewrites = stats.trim_rewrites; last_reclaim_rewrites = stats.reclaim_rewrites; + last_cache_absent_by_src = stats.cache_absent_by_src; + last_access_by_src_ext = stats.access_by_src_ext; } last_dirty_io = stats.dirty_io; + last_access = stats.access; return ret; } diff --git a/src/crimson/os/seastore/cache.h b/src/crimson/os/seastore/cache.h index 01be2a82277ba..dba3610e95f46 100644 --- a/src/crimson/os/seastore/cache.h +++ b/src/crimson/os/seastore/cache.h @@ -1722,6 +1722,10 @@ private: last_dirty_io_by_src_ext; mutable rewrite_stats_t last_trim_rewrites; mutable rewrite_stats_t last_reclaim_rewrites; + mutable cache_access_stats_t last_access; + mutable counter_by_src_t last_cache_absent_by_src; + mutable counter_by_src_t > + last_access_by_src_ext; void account_conflict(Transaction::src_t src1, Transaction::src_t src2) { assert(src1 < Transaction::src_t::MAX); diff --git a/src/crimson/os/seastore/seastore.cc b/src/crimson/os/seastore/seastore.cc index 9a0ac439083d0..e41de39fa7292 100644 --- a/src/crimson/os/seastore/seastore.cc +++ b/src/crimson/os/seastore/seastore.cc @@ -740,6 +740,19 @@ seastar::future<> SeaStore::report_stats() dirty_sizes_ps, dirty_io_stats_printer_t{seconds, dirty_io_ps}); + cache_access_stats_t access_ps = cache_total.access; + access_ps.cache_absent /= seastar::smp::count; + access_ps.s.trans_pending /= seastar::smp::count; + access_ps.s.trans_dirty /= seastar::smp::count; + access_ps.s.trans_lru /= seastar::smp::count; + access_ps.s.cache_dirty /= seastar::smp::count; + access_ps.s.cache_lru /= seastar::smp::count; + access_ps.s.load_absent /= seastar::smp::count; + access_ps.s.load_present /= seastar::smp::count; + INFO("cache_access: total{}; per-shard{}", + cache_access_stats_printer_t{seconds, cache_total.access}, + cache_access_stats_printer_t{seconds, access_ps}); + return seastar::now(); }); } diff --git a/src/crimson/os/seastore/seastore_types.cc b/src/crimson/os/seastore/seastore_types.cc index 13637a59db67f..e1430b30019a5 100644 --- a/src/crimson/os/seastore/seastore_types.cc +++ b/src/crimson/os/seastore/seastore_types.cc @@ -1038,4 +1038,78 @@ std::ostream& operator<<(std::ostream& out, const dirty_io_stats_printer_t& p) return out; } +std::ostream& operator<<(std::ostream& out, const extent_access_stats_printer_t& p) +{ + constexpr const char* dfmt = "{:.2f}"; + double est_total_access = static_cast(p.stats.get_estimated_total_access()); + out << "(~"; + if (est_total_access > 1000000) { + out << fmt::format(dfmt, est_total_access/1000000) + << "M, "; + } else { + out << fmt::format(dfmt, est_total_access/1000) + << "K, "; + } + double trans_hit = static_cast(p.stats.get_trans_hit()); + double cache_hit = static_cast(p.stats.get_cache_hit()); + double est_cache_access = static_cast(p.stats.get_estimated_cache_access()); + double load_absent = static_cast(p.stats.load_absent); + out << "trans-hit=~" + << fmt::format(dfmt, trans_hit/est_total_access*100) + << "%(p" + << fmt::format(dfmt, p.stats.trans_pending/trans_hit) + << ",d" + << fmt::format(dfmt, p.stats.trans_dirty/trans_hit) + << ",l" + << fmt::format(dfmt, p.stats.trans_lru/trans_hit) + << "), cache-hit=~" + << fmt::format(dfmt, cache_hit/est_cache_access*100) + << "%(d" + << fmt::format(dfmt, p.stats.cache_dirty/cache_hit) + << ",l" + << fmt::format(dfmt, p.stats.cache_lru/cache_hit) + <<"), load-present/absent=" + << fmt::format(dfmt, p.stats.load_present/load_absent) + << ")"; + return out; +} + +std::ostream& operator<<(std::ostream& out, const cache_access_stats_printer_t& p) +{ + constexpr const char* dfmt = "{:.2f}"; + double total_access = static_cast(p.stats.get_total_access()); + out << "("; + if (total_access > 1000000) { + out << fmt::format(dfmt, total_access/1000000) + << "M, "; + } else { + out << fmt::format(dfmt, total_access/1000) + << "K, "; + } + double trans_hit = static_cast(p.stats.s.get_trans_hit()); + double cache_hit = static_cast(p.stats.s.get_cache_hit()); + double cache_access = static_cast(p.stats.get_cache_access()); + double load_absent = static_cast(p.stats.s.load_absent); + out << "trans-hit=" + << fmt::format(dfmt, trans_hit/total_access*100) + << "%(p" + << fmt::format(dfmt, p.stats.s.trans_pending/trans_hit) + << ",d" + << fmt::format(dfmt, p.stats.s.trans_dirty/trans_hit) + << ",l" + << fmt::format(dfmt, p.stats.s.trans_lru/trans_hit) + << "), cache-hit=" + << fmt::format(dfmt, cache_hit/cache_access*100) + << "%(d" + << fmt::format(dfmt, p.stats.s.cache_dirty/cache_hit) + << ",l" + << fmt::format(dfmt, p.stats.s.cache_lru/cache_hit) + <<"), load/absent=" + << fmt::format(dfmt, load_absent/p.stats.cache_absent*100) + << "%, load-present/absent=" + << fmt::format(dfmt, p.stats.s.load_present/load_absent) + << ")"; + return out; +} + } // namespace crimson::os::seastore diff --git a/src/crimson/os/seastore/seastore_types.h b/src/crimson/os/seastore/seastore_types.h index ba2928848deb0..62bb3e386359c 100644 --- a/src/crimson/os/seastore/seastore_types.h +++ b/src/crimson/os/seastore/seastore_types.h @@ -2886,10 +2886,51 @@ struct extent_access_stats_t { uint64_t load_absent = 0; uint64_t load_present = 0; + uint64_t get_trans_hit() const { + return trans_pending + trans_dirty + trans_lru; + } + uint64_t get_cache_hit() const { return cache_dirty + cache_lru; } + + uint64_t get_estimated_cache_access() const { + return get_cache_hit() + load_absent; + } + + uint64_t get_estimated_total_access() const { + return get_trans_hit() + get_cache_hit() + load_absent; + } + + bool is_empty() const { + return get_estimated_total_access() == 0; + } + + void add(const extent_access_stats_t& o) { + trans_pending += o.trans_pending; + trans_dirty += o.trans_dirty; + trans_lru += o.trans_lru; + cache_dirty += o.cache_dirty; + cache_lru += o.cache_lru; + load_absent += o.load_absent; + load_present += o.load_present; + } + + void minus(const extent_access_stats_t& o) { + trans_pending -= o.trans_pending; + trans_dirty -= o.trans_dirty; + trans_lru -= o.trans_lru; + cache_dirty -= o.cache_dirty; + cache_lru -= o.cache_lru; + load_absent -= o.load_absent; + load_present -= o.load_present; + } }; +struct extent_access_stats_printer_t { + double seconds; + const extent_access_stats_t& stats; +}; +std::ostream& operator<<(std::ostream&, const extent_access_stats_printer_t&); struct cache_access_stats_t { extent_access_stats_t s; @@ -2898,19 +2939,44 @@ struct cache_access_stats_t { uint64_t get_cache_access() const { return s.get_cache_hit() + cache_absent; } + + uint64_t get_total_access() const { + return s.get_trans_hit() + get_cache_access(); + } + + bool is_empty() const { + return get_total_access() == 0; + } + + void add(const cache_access_stats_t& o) { + s.add(o.s); + cache_absent += o.cache_absent; + } + + void minus(const cache_access_stats_t& o) { + s.minus(o.s); + cache_absent -= o.cache_absent; + } +}; +struct cache_access_stats_printer_t { + double seconds; + const cache_access_stats_t& stats; }; +std::ostream& operator<<(std::ostream&, const cache_access_stats_printer_t&); struct cache_stats_t { cache_size_stats_t lru_sizes; cache_io_stats_t lru_io; cache_size_stats_t dirty_sizes; dirty_io_stats_t dirty_io; + cache_access_stats_t access; void add(const cache_stats_t& o) { lru_sizes.add(o.lru_sizes); lru_io.add(o.lru_io); dirty_sizes.add(o.dirty_sizes); dirty_io.add(o.dirty_io); + access.add(o.access); } }; @@ -2932,6 +2998,7 @@ WRITE_CLASS_DENC_BOUNDED(crimson::os::seastore::alloc_delta_t) WRITE_CLASS_DENC_BOUNDED(crimson::os::seastore::segment_tail_t) #if FMT_VERSION >= 90000 +template <> struct fmt::formatter : fmt::ostream_formatter {}; template <> struct fmt::formatter : fmt::ostream_formatter {}; template <> struct fmt::formatter : fmt::ostream_formatter {}; template <> struct fmt::formatter : fmt::ostream_formatter {}; -- 2.39.5