]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/osd: add per-class mClock scheduler perf counters 69827/head
authorMohit Agrawal <moagrawa@redhat.com>
Tue, 30 Jun 2026 08:53:46 +0000 (14:23 +0530)
committerMohit Agrawal <mohit84.agrawal@gmail.com>
Thu, 9 Jul 2026 10:37:15 +0000 (16:07 +0530)
Fixes: https://tracker.ceph.com/issues/77806
Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
src/crimson/osd/osd_operation.cc
src/crimson/osd/osd_operation.h

index 41b630eb76794bd0872389923bcd574be2333d4c..7b9a80a8be840efc7706a9205f3188bf608476a7 100644 (file)
@@ -167,9 +167,61 @@ void OperationThrottler::start()
   return;
 }
 
+void OperationThrottler::register_metrics(const std::string &sched_type) {
+  namespace sm = seastar::metrics;
+
+  LOG_PREFIX(OperationThrottler::register_metrics);
+  INFO("registering metrics for scheduler {}", sched_type);
+  const std::string group_name =
+    (sched_type == "mclock_scheduler") ? "osd_mclock" : "osd_wpq";
+
+  for (auto& [op_class, name] : {
+    std::pair{SchedulerClass::background_recovery,    "background_recovery"},
+    std::pair{SchedulerClass::background_best_effort, "background_best_effort"},
+    std::pair{SchedulerClass::client,                 "client"},
+    std::pair{SchedulerClass::repop,                  "repop"},
+    std::pair{SchedulerClass::immediate,              "immediate"},
+  }) {
+    auto label = sm::label("op_class")(name);
+    metrics.add_group(group_name, {
+      sm::make_counter("throttled_ops",
+        [this, op_class] { return throttled_ops[op_class]; },
+        sm::description("ops delayed by mClock scheduler"), {label}),
+      sm::make_counter("total_wait_ms",
+        [this, op_class] { return total_wait_ms[op_class]; },
+        sm::description("total ms spent waiting in mClock"), {label}),
+      sm::make_gauge("max_wait_ms",
+        [this, op_class] { return max_wait_ms[op_class]; },
+        sm::description("max wait ms in mClock by op class"), {label}),
+      sm::make_histogram("throttle_wait_latency",
+        [this, op_class]() -> seastar::metrics::histogram& {
+          return wait_hist[op_class]; },
+        sm::description("mClock throttle wait distribution"), {label}),
+    });
+  }
+}
+
+
 OperationThrottler::OperationThrottler(ConfigProxy &conf)
 {
   conf.add_observer(this);
+  for (auto op_class : {SchedulerClass::background_recovery,
+                        SchedulerClass::background_best_effort,
+                        SchedulerClass::client,
+                        SchedulerClass::repop,
+                        SchedulerClass::immediate}) {
+    wait_hist[op_class].buckets = {
+      {0, 1},
+      {0, 5},
+      {0, 10},
+      {0, 50},
+      {0, 100},
+      {0, 500},
+      {0, 1000},
+    };
+  }
+  register_metrics(conf.get_val<std::string>("osd_op_queue"));
+
 }
 
 void OperationThrottler::initialize_scheduler(CephContext *cct, ConfigProxy &conf, bool is_rotational, int whoami)
@@ -262,6 +314,26 @@ seastar::future<> OperationThrottler::stop()
   co_return;
 }
 
+void OperationThrottler::record_throttle_wait(
+  SchedulerClass op_class, uint64_t wait_ms)
+{
+  if (wait_ms == 0) {
+    return;
+  }
+  throttled_ops[op_class]++;
+  total_wait_ms[op_class] += wait_ms;
+  max_wait_ms[op_class] = std::max(max_wait_ms[op_class], wait_ms);
+
+  auto& h = wait_hist[op_class];
+  h.sample_count++;
+  h.sample_sum += wait_ms;
+  for (auto& bucket : h.buckets) {
+    if (wait_ms <= bucket.upper_bound) {
+      bucket.count++;
+    }
+  }
+}
+
 void OperationThrottler::dump_detail(Formatter *f) const
 {
   f->dump_unsigned("max_in_progress", max_in_progress);
index e41cc1abf525eaf240d5b2cf73c7b3ab34bcbba3..40a7ddfe73ca041d30fb07e7bee4fa14f633f202 100644 (file)
@@ -362,6 +362,13 @@ class OperationThrottler : public BlockerT<OperationThrottler>,
   friend BlockerT<OperationThrottler>;
   static constexpr const char* type_name = "OperationThrottler";
 
+  // Perf counters used to capture mClock throttling behavior per op class
+  std::unordered_map<SchedulerClass, uint64_t> throttled_ops;
+  std::unordered_map<SchedulerClass, uint64_t> total_wait_ms;
+  std::unordered_map<SchedulerClass, uint64_t> max_wait_ms;
+  std::unordered_map<SchedulerClass, seastar::metrics::histogram> wait_hist;
+  seastar::metrics::metric_groups metrics;
+
 public:
   OperationThrottler(ConfigProxy &conf);
   void start();
@@ -396,14 +403,19 @@ public:
     }
   };
 
+  void record_throttle_wait(SchedulerClass op_class, uint64_t wait_ms);
   auto get_throttle(crimson::osd::scheduler::params_t params) {
+    auto start = seastar::steady_clock_type::now();
     return acquire_throttle(
       params
-    ).then([this] {
+    ).then([this, start, klass = params.klass] {
+      auto wait_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
+      seastar::steady_clock_type::now() - start).count();
+      record_throttle_wait(klass, wait_ms);
       return ThrottleReleaser{this};
     });
   }
-
+  void register_metrics(const std::string &sched_type);
   void initialize_scheduler(CephContext* cct, ConfigProxy &conf, bool is_rotational, int whoami);
 private:
   void dump_detail(Formatter *f) const final;