From b1f12671184a8da25c1b0059f23bf366483e395f Mon Sep 17 00:00:00 2001 From: Mykola Golub Date: Fri, 23 Nov 2018 15:25:22 +0200 Subject: [PATCH] mgr: add limit param to osd perf query Signed-off-by: Mykola Golub --- src/messages/MMgrConfigure.h | 4 +- src/mgr/ActivePyModules.cc | 5 ++- src/mgr/ActivePyModules.h | 4 +- src/mgr/BaseMgrModule.cc | 74 +++++++++++++++++++++++++++++-- src/mgr/DaemonServer.cc | 5 ++- src/mgr/DaemonServer.h | 4 +- src/mgr/MgrClient.h | 6 ++- src/mgr/OSDPerfMetricCollector.cc | 69 ++++++++++++++++++++-------- src/mgr/OSDPerfMetricCollector.h | 13 +++--- src/mgr/OSDPerfMetricTypes.cc | 5 +++ src/mgr/OSDPerfMetricTypes.h | 40 +++++++++++++++++ src/osd/OSD.cc | 16 ++++--- src/osd/OSD.h | 3 +- src/pybind/mgr/mgr_module.py | 1 + 14 files changed, 205 insertions(+), 44 deletions(-) diff --git a/src/messages/MMgrConfigure.h b/src/messages/MMgrConfigure.h index e53a357ff2b..05d21578b8b 100644 --- a/src/messages/MMgrConfigure.h +++ b/src/messages/MMgrConfigure.h @@ -32,11 +32,11 @@ private: public: uint32_t stats_period = 0; - + // Default 0 means if unspecified will include all stats uint32_t stats_threshold = 0; - std::list osd_perf_metric_queries; + std::map osd_perf_metric_queries; void decode_payload() override { diff --git a/src/mgr/ActivePyModules.cc b/src/mgr/ActivePyModules.cc index 595ac7d7e97..b5391b2566b 100644 --- a/src/mgr/ActivePyModules.cc +++ b/src/mgr/ActivePyModules.cc @@ -902,9 +902,10 @@ void ActivePyModules::set_uri(const std::string& module_name, } OSDPerfMetricQueryID ActivePyModules::add_osd_perf_query( - const OSDPerfMetricQuery &query) + const OSDPerfMetricQuery &query, + const std::optional &limit) { - return server.add_osd_perf_query(query); + return server.add_osd_perf_query(query, limit); } void ActivePyModules::remove_osd_perf_query(OSDPerfMetricQueryID query_id) diff --git a/src/mgr/ActivePyModules.h b/src/mgr/ActivePyModules.h index 03f0ee2d5fd..b0d0eade8e1 100644 --- a/src/mgr/ActivePyModules.h +++ b/src/mgr/ActivePyModules.h @@ -92,7 +92,9 @@ public: const std::string &svc_id, const std::string &path) const; - OSDPerfMetricQueryID add_osd_perf_query(const OSDPerfMetricQuery &query); + OSDPerfMetricQueryID add_osd_perf_query( + const OSDPerfMetricQuery &query, + const std::optional &limit); void remove_osd_perf_query(OSDPerfMetricQueryID query_id); PyObject *get_osd_perf_counters(OSDPerfMetricQueryID query_id); diff --git a/src/mgr/BaseMgrModule.cc b/src/mgr/BaseMgrModule.cc index 5c08bb88abc..8f209a8f30e 100644 --- a/src/mgr/BaseMgrModule.cc +++ b/src/mgr/BaseMgrModule.cc @@ -29,6 +29,8 @@ #include "BaseMgrModule.h" #include "Gil.h" +#include + #define dout_context g_ceph_context #define dout_subsys ceph_subsys_mgr @@ -681,8 +683,11 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args) static const std::string NAME_KEY_DESCRIPTOR = "key_descriptor"; static const std::string NAME_COUNTERS_DESCRIPTORS = "performance_counter_descriptors"; + static const std::string NAME_LIMIT = "limit"; static const std::string NAME_SUB_KEY_TYPE = "type"; static const std::string NAME_SUB_KEY_REGEX = "regex"; + static const std::string NAME_LIMIT_ORDER_BY = "order_by"; + static const std::string NAME_LIMIT_MAX_COUNT = "max_count"; static const std::map sub_key_types = { {"client_id", OSDPerfMetricSubKeyType::CLIENT_ID}, {"pool_id", OSDPerfMetricSubKeyType::POOL_ID}, @@ -712,6 +717,7 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args) PyObject *query_params = PyDict_Items(py_query); OSDPerfMetricQuery query; + std::optional limit; // { // 'key_descriptor': [ @@ -721,6 +727,7 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args) // 'performance_counter_descriptors': [ // list, of, descriptor, types // ], + // 'limit': {'order_by': performance_counter_type, 'max_count': n}, // } for (int i = 0; i < PyList_Size(query_params); ++i) { @@ -822,19 +829,80 @@ ceph_add_osd_perf_query(BaseMgrModule *self, PyObject *args) } query.performance_counter_descriptors.push_back(it->second); } + } else if (query_param_name == NAME_LIMIT) { + if (!PyDict_Check(query_param_val)) { + derr << __func__ << " query " << query_param_name << " not a dict" + << dendl; + Py_RETURN_NONE; + } + + limit = OSDPerfMetricLimit(); + PyObject *limit_params = PyDict_Items(query_param_val); + + for (int j = 0; j < PyList_Size(limit_params); ++j) { + PyObject *kv = PyList_GET_ITEM(limit_params, j); + char *limit_param_name = nullptr; + PyObject *limit_param_val = nullptr; + if (!PyArg_ParseTuple(kv, "sO:pair", &limit_param_name, + &limit_param_val)) { + derr << __func__ << " limit item " << j << " not a size 2 tuple" + << dendl; + Py_RETURN_NONE; + } + + if (limit_param_name == NAME_LIMIT_ORDER_BY) { + if (!PyString_Check(limit_param_val)) { + derr << __func__ << " " << limit_param_name << " not a string" + << dendl; + Py_RETURN_NONE; + } + auto order_by = PyString_AsString(limit_param_val); + auto it = counter_types.find(order_by); + if (it == counter_types.end()) { + derr << __func__ << " limit " << limit_param_name + << " not a valid counter type" << dendl; + Py_RETURN_NONE; + } + limit->order_by = it->second; + } else if (limit_param_name == NAME_LIMIT_MAX_COUNT) { +#if PY_MAJOR_VERSION <= 2 + if (!PyInt_Check(limit_param_val) && !PyLong_Check(limit_param_val)) { +#else + if (!PyLong_Check(limit_param_val)) { +#endif + derr << __func__ << " " << limit_param_name << " not an int" + << dendl; + Py_RETURN_NONE; + } + limit->max_count = PyLong_AsLong(limit_param_val); + } else { + derr << __func__ << " unknown limit param: " << limit_param_name + << dendl; + Py_RETURN_NONE; + } + } } else { - derr << "unknown query param: " << query_param_name << dendl; + derr << __func__ << " unknown query param: " << query_param_name << dendl; Py_RETURN_NONE; } } if (query.key_descriptor.empty() || query.performance_counter_descriptors.empty()) { - derr << "invalid query" << dendl; + derr << __func__ << " invalid query" << dendl; Py_RETURN_NONE; } - auto query_id = self->py_modules->add_osd_perf_query(query); + if (limit) { + auto &ds = query.performance_counter_descriptors; + if (std::find(ds.begin(), ds.end(), limit->order_by) == ds.end()) { + derr << __func__ << " limit order_by " << limit->order_by + << " not in performance_counter_descriptors" << dendl; + Py_RETURN_NONE; + } + } + + auto query_id = self->py_modules->add_osd_perf_query(query, limit); return PyLong_FromLong(query_id); } diff --git a/src/mgr/DaemonServer.cc b/src/mgr/DaemonServer.cc index 716ae6dde75..a1d5f87208e 100644 --- a/src/mgr/DaemonServer.cc +++ b/src/mgr/DaemonServer.cc @@ -2684,9 +2684,10 @@ void DaemonServer::_send_configure(ConnectionRef c) } OSDPerfMetricQueryID DaemonServer::add_osd_perf_query( - const OSDPerfMetricQuery &query) + const OSDPerfMetricQuery &query, + const std::optional &limit) { - return osd_perf_metric_collector.add_query(query); + return osd_perf_metric_collector.add_query(query, limit); } int DaemonServer::remove_osd_perf_query(OSDPerfMetricQueryID query_id) diff --git a/src/mgr/DaemonServer.h b/src/mgr/DaemonServer.h index 47020a884b4..d6a5aafbd6b 100644 --- a/src/mgr/DaemonServer.h +++ b/src/mgr/DaemonServer.h @@ -165,7 +165,9 @@ public: void _send_configure(ConnectionRef c); - OSDPerfMetricQueryID add_osd_perf_query(const OSDPerfMetricQuery &query); + OSDPerfMetricQueryID add_osd_perf_query( + const OSDPerfMetricQuery &query, + const std::optional &limit); int remove_osd_perf_query(OSDPerfMetricQueryID query_id); int get_osd_perf_counters(OSDPerfMetricQueryID query_id, std::map *c); diff --git a/src/mgr/MgrClient.h b/src/mgr/MgrClient.h index 72348ab23c5..09764afaf8c 100644 --- a/src/mgr/MgrClient.h +++ b/src/mgr/MgrClient.h @@ -79,7 +79,8 @@ protected: // If provided, use this to compose an MPGStats to send with // our reports (hook for use by OSD) std::function pgstats_cb; - std::function &)> set_perf_queries_cb; + std::function &)> set_perf_queries_cb; std::function *)> get_perf_report_cb; @@ -119,7 +120,8 @@ public: bool handle_command_reply(MCommandReply *m); void set_perf_metric_query_cb( - std::function &)> cb_set, + std::function &)> cb_set, std::function *)> cb_get) { diff --git a/src/mgr/OSDPerfMetricCollector.cc b/src/mgr/OSDPerfMetricCollector.cc index e8669bb163b..5cd8e27326a 100644 --- a/src/mgr/OSDPerfMetricCollector.cc +++ b/src/mgr/OSDPerfMetricCollector.cc @@ -11,22 +11,46 @@ #undef dout_prefix #define dout_prefix *_dout << "mgr.osd_perf_metric_collector " << __func__ << " " +namespace { + +bool is_limited(const std::map> &limits) { + for (auto &it : limits) { + if (!it.second) { + return false; + } + } + return true; +} + +} // anonymous namespace + OSDPerfMetricCollector::OSDPerfMetricCollector(Listener &listener) : listener(listener), lock("OSDPerfMetricCollector::lock") { } -std::list OSDPerfMetricCollector::get_queries() { +std::map +OSDPerfMetricCollector::get_queries() const { std::lock_guard locker(lock); - std::list query_list; + std::map result; for (auto &it : queries) { - query_list.push_back(it.first); + auto &query = it.first; + auto &limits = it.second; + auto result_it = result.insert({query, {}}).first; + if (is_limited(limits)) { + for (auto &iter : limits) { + result_it->second.insert(*iter.second); + } + } } - return query_list; + return result; } -int OSDPerfMetricCollector::add_query(const OSDPerfMetricQuery& query) { +OSDPerfMetricQueryID OSDPerfMetricCollector::add_query( + const OSDPerfMetricQuery& query, + const std::optional &limit) { uint64_t query_id; bool notify = false; @@ -38,12 +62,15 @@ int OSDPerfMetricCollector::add_query(const OSDPerfMetricQuery& query) { if (it == queries.end()) { it = queries.insert({query, {}}).first; notify = true; + } else if (is_limited(it->second)) { + notify = true; } - it->second.insert(query_id); + it->second.insert({query_id, limit}); counters[query_id]; } - dout(10) << query << " query_id=" << query_id << dendl; + dout(10) << query << " " << (limit ? stringify(*limit) : "unlimited") + << " query_id=" << query_id << dendl; if (notify) { listener.handle_query_updated(); @@ -60,16 +87,20 @@ int OSDPerfMetricCollector::remove_query(int query_id) { std::lock_guard locker(lock); for (auto it = queries.begin() ; it != queries.end(); it++) { - auto &ids = it->second; + auto iter = it->second.find(query_id); + if (iter == it->second.end()) { + continue; + } - if (ids.erase(query_id) > 0) { - if (ids.empty()) { - queries.erase(it); - notify = true; - } - found = true; - break; + it->second.erase(iter); + if (it->second.empty()) { + queries.erase(it); + notify = true; + } else if (is_limited(it->second)) { + notify = true; } + found = true; + break; } counters.erase(query_id); } @@ -142,7 +173,8 @@ void OSDPerfMetricCollector::process_reports( auto &key = it.first; auto bl_it = it.second.cbegin(); - for (auto query_id : queries[query]) { + for (auto &queries_it : queries[query]) { + auto query_id = queries_it.first; auto &key_counters = counters[query_id][key]; if (key_counters.empty()) { key_counters.resize(query.performance_counter_descriptors.size(), @@ -155,14 +187,15 @@ void OSDPerfMetricCollector::process_reports( if (desc_it == report.performance_counter_descriptors.end()) { break; } - if (desc_it->type != query.performance_counter_descriptors[i].type) { + if (*desc_it != query.performance_counter_descriptors[i]) { continue; } PerformanceCounter c; desc_it->unpack_counter(bl_it, &c); dout(20) << "counter " << key << " " << *desc_it << ": " << c << dendl; - for (auto query_id : queries[query]) { + for (auto &queries_it : queries[query]) { + auto query_id = queries_it.first; auto &key_counters = counters[query_id][key]; key_counters[i].first += c.first; key_counters[i].second += c.second; diff --git a/src/mgr/OSDPerfMetricCollector.h b/src/mgr/OSDPerfMetricCollector.h index 5b9b8dc10ba..89e33091574 100644 --- a/src/mgr/OSDPerfMetricCollector.h +++ b/src/mgr/OSDPerfMetricCollector.h @@ -8,8 +8,7 @@ #include "mgr/OSDPerfMetricTypes.h" -#include -#include +#include /** * OSD performance query class. @@ -25,9 +24,11 @@ public: OSDPerfMetricCollector(Listener &listener); - std::list get_queries(); + std::map get_queries() const; - OSDPerfMetricQueryID add_query(const OSDPerfMetricQuery& query); + OSDPerfMetricQueryID add_query( + const OSDPerfMetricQuery& query, + const std::optional &limit); int remove_query(OSDPerfMetricQueryID query_id); void remove_all_queries(); @@ -38,7 +39,9 @@ public: const std::map &reports); private: - typedef std::map> Queries; + typedef std::optional OptionalLimit; + typedef std::map> Queries; typedef std::map> Counters; diff --git a/src/mgr/OSDPerfMetricTypes.cc b/src/mgr/OSDPerfMetricTypes.cc index 181a1f38c7c..9cf733c3d23 100644 --- a/src/mgr/OSDPerfMetricTypes.cc +++ b/src/mgr/OSDPerfMetricTypes.cc @@ -93,6 +93,11 @@ std::ostream& operator<<(std::ostream& os, } } +std::ostream& operator<<(std::ostream& os, const OSDPerfMetricLimit &limit) { + return os << "{order_by=" << limit.order_by << ", max_count=" + << limit.max_count << "}"; +} + void OSDPerfMetricQuery::pack_counters(const PerformanceCounters &counters, bufferlist *bl) const { auto it = counters.begin(); diff --git a/src/mgr/OSDPerfMetricTypes.h b/src/mgr/OSDPerfMetricTypes.h index c1777af0fa4..f68740c38ff 100644 --- a/src/mgr/OSDPerfMetricTypes.h +++ b/src/mgr/OSDPerfMetricTypes.h @@ -157,6 +157,14 @@ struct PerformanceCounterDescriptor { return type < other.type; } + bool operator==(const PerformanceCounterDescriptor &other) const { + return type == other.type; + } + + bool operator!=(const PerformanceCounterDescriptor &other) const { + return type != other.type; + } + DENC(PerformanceCounterDescriptor, v, p) { DENC_START(1, 1, p); denc(v.type, p); @@ -212,6 +220,38 @@ struct denc_traits { } }; +struct OSDPerfMetricLimit { + PerformanceCounterDescriptor order_by; + uint64_t max_count = 0; + + OSDPerfMetricLimit() { + } + + OSDPerfMetricLimit(const PerformanceCounterDescriptor &order_by, + uint64_t max_count) + : order_by(order_by), max_count(max_count) { + } + + bool operator<(const OSDPerfMetricLimit &other) const { + if (order_by != other.order_by) { + return order_by < other.order_by; + } + return max_count < other.max_count; + } + + DENC(OSDPerfMetricLimit, v, p) { + DENC_START(1, 1, p); + denc(v.order_by, p); + denc(v.max_count, p); + DENC_FINISH(p); + } +}; +WRITE_CLASS_DENC(OSDPerfMetricLimit) + +std::ostream& operator<<(std::ostream& os, const OSDPerfMetricLimit &limit); + +typedef std::set OSDPerfMetricLimits; + typedef int OSDPerfMetricQueryID; struct OSDPerfMetricQuery { diff --git a/src/osd/OSD.cc b/src/osd/OSD.cc index 06f945ecbe5..0eeab719b4d 100644 --- a/src/osd/OSD.cc +++ b/src/osd/OSD.cc @@ -2807,7 +2807,7 @@ int OSD::init() mgrc.set_pgstats_cb([this](){ return collect_pg_stats(); }); mgrc.set_perf_metric_query_cb( - [this](const std::list &queries) { + [this](const std::map &queries) { set_perf_queries(queries); }, [this](std::map *reports) { @@ -9800,15 +9800,17 @@ int OSD::init_op_flags(OpRequestRef& op) return 0; } -void OSD::set_perf_queries(const std::list &queries) { +void OSD::set_perf_queries( + const std::map &queries) { dout(10) << "setting " << queries.size() << " queries" << dendl; std::list supported_queries; - std::copy_if(queries.begin(), queries.end(), - std::back_inserter(supported_queries), - [](const OSDPerfMetricQuery &query) { - return !query.key_descriptor.empty(); - }); + for (auto &it : queries) { + auto &query = it.first; + if (!query.key_descriptor.empty()) { + supported_queries.push_back(query); + } + } if (supported_queries.size() < queries.size()) { dout(1) << queries.size() - supported_queries.size() << " unsupported queries" << dendl; diff --git a/src/osd/OSD.h b/src/osd/OSD.h index 7253e9aa14a..49d689b588c 100644 --- a/src/osd/OSD.h +++ b/src/osd/OSD.h @@ -2310,7 +2310,8 @@ public: friend class OSDService; private: - void set_perf_queries(const std::list &queries); + void set_perf_queries( + const std::map &queries); void get_perf_reports( std::map *reports); diff --git a/src/pybind/mgr/mgr_module.py b/src/pybind/mgr/mgr_module.py index ccf763c776e..f66ba618346 100644 --- a/src/pybind/mgr/mgr_module.py +++ b/src/pybind/mgr/mgr_module.py @@ -967,6 +967,7 @@ class MgrModule(ceph_module.BaseMgrModule): 'performance_counter_descriptors': [ list, of, descriptor, types ], + 'limit': {'order_by': performance_counter_type, 'max_count': n}, } Valid subkey types: 'client_id', 'pool_id', 'object_name' -- 2.39.5