From: Mohit Agrawal Date: Tue, 30 Jun 2026 08:53:46 +0000 (+0530) Subject: crimson/osd: add per-class mClock scheduler perf counters X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=cfb382b82c186401ce2d6cdef4cd7bf13f08bc64;p=ceph.git crimson/osd: add per-class mClock scheduler perf counters Fixes: https://tracker.ceph.com/issues/77806 Signed-off-by: Mohit Agrawal --- diff --git a/src/crimson/osd/osd_operation.cc b/src/crimson/osd/osd_operation.cc index 41b630eb767..7b9a80a8be8 100644 --- a/src/crimson/osd/osd_operation.cc +++ b/src/crimson/osd/osd_operation.cc @@ -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("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); diff --git a/src/crimson/osd/osd_operation.h b/src/crimson/osd/osd_operation.h index e41cc1abf52..40a7ddfe73c 100644 --- a/src/crimson/osd/osd_operation.h +++ b/src/crimson/osd/osd_operation.h @@ -362,6 +362,13 @@ class OperationThrottler : public BlockerT, friend BlockerT; static constexpr const char* type_name = "OperationThrottler"; + // Perf counters used to capture mClock throttling behavior per op class + std::unordered_map throttled_ops; + std::unordered_map total_wait_ms; + std::unordered_map max_wait_ms; + std::unordered_map 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( + 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;