]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr: add get_latest_counter() to C++ -> Python interface.
authorJan Fajerski <jfajerski@suse.com>
Fri, 7 Sep 2018 08:26:31 +0000 (10:26 +0200)
committerJan Fajerski <jfajerski@suse.com>
Mon, 10 Sep 2018 18:58:32 +0000 (20:58 +0200)
This allows Python land to only retrieve the latest perf counters,
instead of of retrieving all from C++ land and pick out the latest.

Signed-off-by: Jan Fajerski <jfajerski@suse.com>
src/mgr/ActivePyModules.cc
src/mgr/ActivePyModules.h
src/mgr/BaseMgrModule.cc
src/mgr/DaemonState.h
src/pybind/mgr/mgr_module.py

index 6bac2ec6e0318976ef3956a3438caa0874203840..0ba80c792390438745772e5118022b66aa8c23e8 100644 (file)
@@ -603,10 +603,11 @@ std::map<std::string, std::string> ActivePyModules::get_services() const
   return result;
 }
 
-PyObject* ActivePyModules::get_counter_python(
+PyObject* ActivePyModules::with_perf_counters(
+    std::function<void(PerfCounterInstance& counter_instance, PerfCounterType& counter_type, PyFormatter& f)> fct,
     const std::string &svc_name,
     const std::string &svc_id,
-    const std::string &path)
+    const std::string &path) const
 {
   PyThreadState *tstate = PyEval_SaveThread();
   Mutex::Locker l(lock);
@@ -621,27 +622,10 @@ PyObject* ActivePyModules::get_counter_python(
     if (metadata->perf_counters.instances.count(path)) {
       auto counter_instance = metadata->perf_counters.instances.at(path);
       auto counter_type = metadata->perf_counters.types.at(path);
-      if (counter_type.type & PERFCOUNTER_LONGRUNAVG) {
-        const auto &avg_data = counter_instance.get_data_avg();
-        for (const auto &datapoint : avg_data) {
-          f.open_array_section("datapoint");
-          f.dump_unsigned("t", datapoint.t.sec());
-          f.dump_unsigned("s", datapoint.s);
-          f.dump_unsigned("c", datapoint.c);
-          f.close_section();
-        }
-      } else {
-        const auto &data = counter_instance.get_data();
-        for (const auto &datapoint : data) {
-          f.open_array_section("datapoint");
-          f.dump_unsigned("t", datapoint.t.sec());
-          f.dump_unsigned("v", datapoint.v);
-          f.close_section();
-        }
-      }
+      fct(counter_instance, counter_type, f);
     } else {
       dout(4) << "Missing counter: '" << path << "' ("
-              << svc_name << "." << svc_id << ")" << dendl;
+        << svc_name << "." << svc_id << ")" << dendl;
       dout(20) << "Paths are:" << dendl;
       for (const auto &i : metadata->perf_counters.instances) {
         dout(20) << i.first << dendl;
@@ -649,12 +633,68 @@ PyObject* ActivePyModules::get_counter_python(
     }
   } else {
     dout(4) << "No daemon state for "
-              << svc_name << "." << svc_id << ")" << dendl;
+      << svc_name << "." << svc_id << ")" << dendl;
   }
   f.close_section();
   return f.get();
 }
 
+PyObject* ActivePyModules::get_counter_python(
+    const std::string &svc_name,
+    const std::string &svc_id,
+    const std::string &path)
+{
+  auto extract_counters = [](
+      PerfCounterInstance& counter_instance,
+      PerfCounterType& counter_type,
+      PyFormatter& f)
+  {
+    if (counter_type.type & PERFCOUNTER_LONGRUNAVG) {
+      const auto &avg_data = counter_instance.get_data_avg();
+      for (const auto &datapoint : avg_data) {
+        f.open_array_section("datapoint");
+        f.dump_unsigned("t", datapoint.t.sec());
+        f.dump_unsigned("s", datapoint.s);
+        f.dump_unsigned("c", datapoint.c);
+        f.close_section();
+      }
+    } else {
+      const auto &data = counter_instance.get_data();
+      for (const auto &datapoint : data) {
+        f.open_array_section("datapoint");
+        f.dump_unsigned("t", datapoint.t.sec());
+        f.dump_unsigned("v", datapoint.v);
+        f.close_section();
+      }
+    }
+  };
+  return with_perf_counters(extract_counters, svc_name, svc_id, path);
+}
+
+PyObject* ActivePyModules::get_latest_counter_python(
+    const std::string &svc_name,
+    const std::string &svc_id,
+    const std::string &path)
+{
+  auto extract_latest_counters = [](
+      PerfCounterInstance& counter_instance,
+      PerfCounterType& counter_type,
+      PyFormatter& f)
+  {
+    if (counter_type.type & PERFCOUNTER_LONGRUNAVG) {
+      const auto &datapoint = counter_instance.get_latest_data_avg();
+      f.dump_unsigned("t", datapoint.t.sec());
+      f.dump_unsigned("s", datapoint.s);
+      f.dump_unsigned("c", datapoint.c);
+    } else {
+      const auto &datapoint = counter_instance.get_latest_data();
+      f.dump_unsigned("t", datapoint.t.sec());
+      f.dump_unsigned("v", datapoint.v);
+    }
+  };
+  return with_perf_counters(extract_latest_counters, svc_name, svc_id, path);
+}
+
 PyObject* ActivePyModules::get_perf_schema_python(
     const std::string &svc_type,
     const std::string &svc_id)
index 0b2ccd7ae8864535f90e8b7f6506cdbcbbee77ab..91fc09697ec9742f7ee9ad877f3d0c3f39c679fc 100644 (file)
@@ -18,6 +18,8 @@
 #include "common/Finisher.h"
 #include "common/Mutex.h"
 
+#include "PyFormatter.h"
+
 #include "osdc/Objecter.h"
 #include "client/Client.h"
 #include "common/LogClient.h"
@@ -71,11 +73,23 @@ public:
     const std::string &svc_type,
     const std::string &svc_id,
     const std::string &path);
+  PyObject *get_latest_counter_python(
+    const std::string &svc_type,
+    const std::string &svc_id,
+    const std::string &path);
   PyObject *get_perf_schema_python(
      const std::string &svc_type,
      const std::string &svc_id);
   PyObject *get_context();
   PyObject *get_osdmap();
+  PyObject *with_perf_counters(
+      std::function<void(
+        PerfCounterInstance& counter_instance,
+        PerfCounterType& counter_type,
+        PyFormatter& f)> fct,
+      const std::string &svc_name,
+      const std::string &svc_id,
+      const std::string &path) const;
 
   bool get_store(const std::string &module_name,
       const std::string &key, std::string *val) const;
index c52bf165d867a11bd2d5ab9a46e62c7af8b4cf12..6cc3cda87a566a1602d64759459f5c9578978746 100644 (file)
@@ -505,6 +505,20 @@ get_counter(BaseMgrModule *self, PyObject *args)
       svc_name, svc_id, counter_path);
 }
 
+static PyObject*
+get_latest_counter(BaseMgrModule *self, PyObject *args)
+{
+  char *svc_name = nullptr;
+  char *svc_id = nullptr;
+  char *counter_path = nullptr;
+  if (!PyArg_ParseTuple(args, "sss:get_counter", &svc_name,
+                                                  &svc_id, &counter_path)) {
+    return nullptr;
+  }
+  return self->py_modules->get_latest_counter_python(
+      svc_name, svc_id, counter_path);
+}
+
 static PyObject*
 get_perf_schema(BaseMgrModule *self, PyObject *args)
 {
@@ -641,6 +655,9 @@ PyMethodDef BaseMgrModule_methods[] = {
   {"_ceph_get_counter", (PyCFunction)get_counter, METH_VARARGS,
     "Get a performance counter"},
 
+  {"_ceph_get_latest_counter", (PyCFunction)get_latest_counter, METH_VARARGS,
+    "Get the latest performance counter"},
+
   {"_ceph_get_perf_schema", (PyCFunction)get_perf_schema, METH_VARARGS,
     "Get the performance counter schema"},
 
index 0a083ac5617d35d52a9784ad77808f10511b0cf6..5732178390ae71f746066e6b3137bf894ffc38d8 100644 (file)
@@ -74,10 +74,18 @@ class PerfCounterInstance
   {
     return buffer;
   }
+  const DataPoint& get_latest_data() const
+  {
+    return buffer.back();
+  }
   const boost::circular_buffer<AvgDataPoint> & get_data_avg() const
   {
     return avg_buffer;
   }
+  const AvgDataPoint& get_latest_data_avg() const
+  {
+    return avg_buffer.back();
+  }
   void push(utime_t t, uint64_t const &v);
   void push_avg(utime_t t, uint64_t const &s, uint64_t const &c);
 
index fd427bd074047eb5bc409e99073e2cb56b6f676c..d1ab2de71916bc84a173a5369687f248726caebd 100644 (file)
@@ -479,6 +479,20 @@ class MgrModule(ceph_module.BaseMgrModule):
         """
         return self._ceph_get_counter(svc_type, svc_name, path)
 
+    def get_latest_counter(self, svc_type, svc_name, path):
+        """
+        Called by the plugin to fetch only the newest performance counter data
+        pointfor a particular counter on a particular service.
+
+        :param str svc_type:
+        :param str svc_name:
+        :param str path: a period-separated concatenation of the subsystem and the
+            counter name, for example "mds.inodes".
+        :return: A list of two-tuples of (timestamp, value) is returned.  This may be
+            empty if no data is available.
+        """
+        return self._ceph_get_latest_counter(svc_type, svc_name, path)
+
     def list_servers(self):
         """
         Like ``get_server``, but gives information about all servers (i.e. all
@@ -721,19 +735,17 @@ class MgrModule(ceph_module.BaseMgrModule):
         """
         return self._ceph_get_osdmap()
 
-    # TODO: improve C++->Python interface to return just
-    # the latest if that's all we want.
     def get_latest(self, daemon_type, daemon_name, counter):
-        data = self.get_counter(daemon_type, daemon_name, counter)[counter]
+        data = self.get_latest_counter(daemon_type, daemon_name, counter)[counter]
         if data:
-            return data[-1][1]
+            return data[1]
         else:
             return 0
 
     def get_latest_avg(self, daemon_type, daemon_name, counter):
-        data = self.get_counter(daemon_type, daemon_name, counter)[counter]
+        data = self.get_latest_counter(daemon_type, daemon_name, counter)[counter]
         if data:
-            return (data[-1][1], data[-1][2])
+            return (data[1], data[2])
         else:
             return (0, 0)
 
@@ -742,7 +754,7 @@ class MgrModule(ceph_module.BaseMgrModule):
         Return the perf counters currently known to this ceph-mgr
         instance, filtered by priority equal to or greater than `prio_limit`.
 
-        The result us a map of string to dict, associating services
+        The result is a map of string to dict, associating services
         (like "osd.123") with their counters.  The counter
         dict for each service maps counter paths to a counter
         info structure, which is the information from