]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/os/seastore/cache: report cache access stats
authorYingxin Cheng <yingxin.cheng@intel.com>
Mon, 2 Sep 2024 02:30:31 +0000 (10:30 +0800)
committerYingxin Cheng <yingxin.cheng@intel.com>
Mon, 2 Sep 2024 02:57:56 +0000 (10:57 +0800)
Signed-off-by: Yingxin Cheng <yingxin.cheng@intel.com>
src/crimson/os/seastore/cache.cc
src/crimson/os/seastore/cache.h
src/crimson/os/seastore/seastore.cc
src/crimson/os/seastore/seastore_types.cc
src/crimson/os/seastore/seastore_types.h

index e1c82a577a4d518838fc15139740ea768cb0fc40..cf8d3c0891d7f3a143cc592914bee1ebb85fcef2 100644 (file)
@@ -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<counter_by_extent_t<dirty_io_stats_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<counter_by_extent_t<extent_access_stats_t> >
+      _access_by_src_ext = stats.access_by_src_ext;
+    counter_by_src_t<cache_access_stats_t> access_by_src;
+    for (uint8_t _src=0; _src<TRANSACTION_TYPE_MAX; ++_src) {
+      auto src = static_cast<transaction_type_t>(_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<EXTENT_TYPES_MAX; ++_ext) {
+        auto ext = static_cast<extent_types_t>(_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<TRANSACTION_TYPE_MAX; ++_src) {
+      auto src = static_cast<transaction_type_t>(_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<EXTENT_TYPES_MAX; ++_ext) {
+        auto ext = static_cast<extent_types_t>(_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;
 }
index 01be2a82277ba21db7880b1f31254074e907748f..dba3610e95f4631c43ae3da6b5edda4de1284cb5 100644 (file)
@@ -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<uint64_t> last_cache_absent_by_src;
+  mutable counter_by_src_t<counter_by_extent_t<extent_access_stats_t> >
+    last_access_by_src_ext;
 
   void account_conflict(Transaction::src_t src1, Transaction::src_t src2) {
     assert(src1 < Transaction::src_t::MAX);
index 9a0ac439083d029d282b0b55824d800d3d78812f..e41de39fa72926841b162dbb19ddb66f356298e9 100644 (file)
@@ -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();
   });
 }
index 13637a59db67f8a6db51dae1a4875ae223db0b40..e1430b30019a5dde0fb61ed8662d5e3fa8b1c5fa 100644 (file)
@@ -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<double>(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<double>(p.stats.get_trans_hit());
+  double cache_hit = static_cast<double>(p.stats.get_cache_hit());
+  double est_cache_access = static_cast<double>(p.stats.get_estimated_cache_access());
+  double load_absent = static_cast<double>(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<double>(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<double>(p.stats.s.get_trans_hit());
+  double cache_hit = static_cast<double>(p.stats.s.get_cache_hit());
+  double cache_access = static_cast<double>(p.stats.get_cache_access());
+  double load_absent = static_cast<double>(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
index ba2928848deb0d48870456c097c526fd53d92e28..62bb3e386359cb6c1c189691aafc2cbb3625bcd3 100644 (file)
@@ -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<crimson::os::seastore::cache_access_stats_printer_t> : fmt::ostream_formatter {};
 template <> struct fmt::formatter<crimson::os::seastore::cache_io_stats_printer_t> : fmt::ostream_formatter {};
 template <> struct fmt::formatter<crimson::os::seastore::cache_size_stats_t> : fmt::ostream_formatter {};
 template <> struct fmt::formatter<crimson::os::seastore::cache_size_stats_printer_t> : fmt::ostream_formatter {};