]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common: created labeled perf counters instead of normal ones
authorAli Maredia <amaredia@redhat.com>
Thu, 20 Oct 2022 03:15:56 +0000 (23:15 -0400)
committerAli Maredia <amaredia@redhat.com>
Fri, 28 Oct 2022 12:24:43 +0000 (08:24 -0400)
Signed-off-by: Ali Maredia <amaredia@redhat.com>
src/common/CMakeLists.txt
src/common/ceph_context.cc
src/common/ceph_context.h
src/common/labeled_perf_counters.cc [new file with mode: 0644]
src/common/labeled_perf_counters.h [new file with mode: 0644]
src/common/labeled_perf_counters_collection.cc [new file with mode: 0644]
src/common/labeled_perf_counters_collection.h [new file with mode: 0644]
src/common/perf_counters.cc
src/common/perf_counters.h
src/common/perf_counters_cache.h
src/rgw/rgw_op.cc

index fc32906193cbb4303b310a5a84d79d084f5be122..edfdb56ab79d6fe0a8245baa52120b46f7bfc066 100644 (file)
@@ -76,6 +76,8 @@ set(common_srcs
   hostname.cc
   ipaddr.cc
   iso_8601.cc
+  labeled_perf_counters.cc
+  labeled_perf_counters_collection.cc
   mempool.cc
   mime.c
   numa.cc
index eeee83618819c4a56dd161e63e5ba714ec4bcbc6..a0eb181dac796c7379ba330353fbe8c65e6a3d11 100644 (file)
@@ -104,7 +104,7 @@ PerfCountersCollectionImpl* CephContext::get_perfcounters_collection()
   return _perf_counters_collection.get_perf_collection();
 }
 
-PerfCountersCollectionImpl* CephContext::get_labeledperfcounters_collection()
+LabeledPerfCountersCollectionImpl* CephContext::get_labeledperfcounters_collection()
 {
   return _labeled_perf_counters_collection.get_perf_collection();
 }
@@ -748,7 +748,7 @@ CephContext::CephContext(uint32_t module_type_,
   _conf.add_observer(_lockdep_obs);
 #endif
   _perf_counters_collection = new PerfCountersCollection(this);
-  _labeled_perf_counters_collection = new PerfCountersCollection(this);
+  _labeled_perf_counters_collection = new LabeledPerfCountersCollection(this);
  
   _admin_socket = new AdminSocket(this);
   _heartbeat_map = new HeartbeatMap(this);
@@ -947,7 +947,7 @@ PerfCountersCollection *CephContext::get_perfcounters_collection()
   return _perf_counters_collection;
 }
 
-PerfCountersCollection *CephContext::get_labeledperfcounters_collection()
+LabeledPerfCountersCollection *CephContext::get_labeledperfcounters_collection()
 {
   return _labeled_perf_counters_collection;
 }
index 90eb9267212117894e3d8197d3b2d6561033f294..e317a50cd16fa46d93f293c8a5a321dfa82e167e 100644 (file)
@@ -41,9 +41,9 @@
 #include "common/config_proxy.h"
 #include "include/spinlock.h"
 #include "common/perf_counters_collection.h"
+#include "common/labeled_perf_counters_collection.h"
 #endif
 
-
 #include "crush/CrushLocation.h"
 
 class AdminSocket;
@@ -170,8 +170,8 @@ public:
   /* Get the PerfCountersCollection of this CephContext */
   PerfCountersCollection *get_perfcounters_collection();
 
-  /* Get the PerfCountersCollection of this CephContext */
-  PerfCountersCollection *get_labeledperfcounters_collection();
+  /* Get the LabeledPerfCountersCollection of this CephContext */
+  LabeledPerfCountersCollection *get_labeledperfcounters_collection();
 
   ceph::HeartbeatMap *get_heartbeat_map() {
     return _heartbeat_map;
@@ -329,7 +329,7 @@ private:
 
   /* The collection of profiling loggers associated with this context */
   PerfCountersCollection *_perf_counters_collection;
-  PerfCountersCollection *_labeled_perf_counters_collection;
+  LabeledPerfCountersCollection *_labeled_perf_counters_collection;
 
   md_config_obs_t *_perf_counters_conf_obs;
 
diff --git a/src/common/labeled_perf_counters.cc b/src/common/labeled_perf_counters.cc
new file mode 100644 (file)
index 0000000..ed39453
--- /dev/null
@@ -0,0 +1,593 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ * Copyright (C) 2017 OVH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "common/labeled_perf_counters.h"
+#include "common/dout.h"
+#include "common/valgrind.h"
+#include "include/common_fwd.h"
+
+using std::ostringstream;
+using std::make_pair;
+using std::pair;
+
+namespace TOPNSPC::common {
+LabeledPerfCountersCollectionImpl::LabeledPerfCountersCollectionImpl()
+{
+}
+
+LabeledPerfCountersCollectionImpl::~LabeledPerfCountersCollectionImpl()
+{
+  clear();
+}
+
+void LabeledPerfCountersCollectionImpl::add(LabeledPerfCounters *l)
+{
+  // make sure the name is unique
+  labeled_perf_counters_set_t::iterator i;
+  i = m_loggers.find(l);
+  while (i != m_loggers.end()) {
+    ostringstream ss;
+    ss << l->get_name() << "-" << (void*)l;
+    l->set_name(ss.str());
+    i = m_loggers.find(l);
+  }
+
+  m_loggers.insert(l);
+
+  for (unsigned int i = 0; i < l->m_data.size(); ++i) {
+    LabeledPerfCounters::perf_counter_data_any_d &data = l->m_data[i];
+
+    std::string path = l->get_name();
+    path += ".";
+    path += data.name;
+
+    by_path[path] = {&data, l};
+  }
+}
+
+void LabeledPerfCountersCollectionImpl::remove(LabeledPerfCounters *l)
+{
+  for (unsigned int i = 0; i < l->m_data.size(); ++i) {
+    LabeledPerfCounters::perf_counter_data_any_d &data = l->m_data[i];
+
+    std::string path = l->get_name();
+    path += ".";
+    path += data.name;
+
+    by_path.erase(path);
+  }
+
+  labeled_perf_counters_set_t::iterator i = m_loggers.find(l);
+  ceph_assert(i != m_loggers.end());
+  m_loggers.erase(i);
+}
+
+void LabeledPerfCountersCollectionImpl::clear()
+{
+  labeled_perf_counters_set_t::iterator i = m_loggers.begin();
+  labeled_perf_counters_set_t::iterator i_end = m_loggers.end();
+  for (; i != i_end; ) {
+    delete *i;
+    m_loggers.erase(i++);
+  }
+
+  by_path.clear();
+}
+
+bool LabeledPerfCountersCollectionImpl::reset(const std::string &name)
+{
+  bool result = false;
+  labeled_perf_counters_set_t::iterator i = m_loggers.begin();
+  labeled_perf_counters_set_t::iterator i_end = m_loggers.end();
+
+  if (!strcmp(name.c_str(), "all"))  {
+    while (i != i_end) {
+      (*i)->reset();
+      ++i;
+    }
+    result = true;
+  } else {
+    while (i != i_end) {
+      if (!name.compare((*i)->get_name())) {
+       (*i)->reset();
+       result = true;
+       break;
+      }
+      ++i;
+    }
+  }
+
+  return result;
+}
+
+
+/**
+ * Serialize current values of performance counters.  Optionally
+ * output the schema instead, or filter output to a particular
+ * LabeledPerfCounters or particular named counter.
+ *
+ * @param logger name of subsystem logger, e.g. "mds_cache", may be empty
+ * @param counter name of counter within subsystem, e.g. "num_strays",
+ *                may be empty.
+ * @param schema if true, output schema instead of current data.
+ * @param histograms if true, dump histogram values,
+ *                   if false dump all non-histogram counters
+ */
+void LabeledPerfCountersCollectionImpl::dump_formatted_generic(
+    Formatter *f,
+    bool schema,
+    bool histograms,
+    const std::string &logger,
+    const std::string &counter) const
+{
+  f->open_object_section("perfcounter_collection");
+  
+  for (labeled_perf_counters_set_t::iterator l = m_loggers.begin();
+       l != m_loggers.end(); ++l) {
+    // Optionally filter on logger name, pass through counter filter
+    if (logger.empty() || (*l)->get_name() == logger) {
+      (*l)->dump_formatted_generic(f, schema, histograms, counter);
+    }
+  }
+  f->close_section();
+}
+
+void LabeledPerfCountersCollectionImpl::with_counters(std::function<void(
+      const LabeledPerfCountersCollectionImpl::CounterMap &)> fn) const
+{
+  fn(by_path);
+}
+
+// ---------------------------
+
+LabeledPerfCounters::~LabeledPerfCounters()
+{
+}
+
+void LabeledPerfCounters::inc(int idx, uint64_t amt)
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return;
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  if (!(data.type & PERFCOUNTER_U64))
+    return;
+  if (data.type & PERFCOUNTER_LONGRUNAVG) {
+    data.avgcount++;
+    data.u64 += amt;
+    data.avgcount2++;
+  } else {
+    data.u64 += amt;
+  }
+  data.accessed = true;
+}
+
+void LabeledPerfCounters::dec(int idx, uint64_t amt)
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return;
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  ceph_assert(!(data.type & PERFCOUNTER_LONGRUNAVG));
+  if (!(data.type & PERFCOUNTER_U64))
+    return;
+  data.u64 -= amt;
+}
+
+void LabeledPerfCounters::set(int idx, uint64_t amt)
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return;
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  if (!(data.type & PERFCOUNTER_U64))
+    return;
+
+  ANNOTATE_BENIGN_RACE_SIZED(&data.u64, sizeof(data.u64),
+                             "perf counter atomic");
+  if (data.type & PERFCOUNTER_LONGRUNAVG) {
+    data.avgcount++;
+    data.u64 = amt;
+    data.avgcount2++;
+  } else {
+    data.u64 = amt;
+  }
+}
+
+uint64_t LabeledPerfCounters::get(int idx) const
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return 0;
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  if (!(data.type & PERFCOUNTER_U64))
+    return 0;
+  return data.u64;
+}
+
+void LabeledPerfCounters::tinc(int idx, utime_t amt)
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return;
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  if (!(data.type & PERFCOUNTER_TIME))
+    return;
+  if (data.type & PERFCOUNTER_LONGRUNAVG) {
+    data.avgcount++;
+    data.u64 += amt.to_nsec();
+    data.avgcount2++;
+  } else {
+    data.u64 += amt.to_nsec();
+  }
+}
+
+void LabeledPerfCounters::tinc(int idx, ceph::timespan amt)
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return;
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  if (!(data.type & PERFCOUNTER_TIME))
+    return;
+  if (data.type & PERFCOUNTER_LONGRUNAVG) {
+    data.avgcount++;
+    data.u64 += amt.count();
+    data.avgcount2++;
+  } else {
+    data.u64 += amt.count();
+  }
+}
+
+void LabeledPerfCounters::tset(int idx, utime_t amt)
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return;
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  if (!(data.type & PERFCOUNTER_TIME))
+    return;
+  data.u64 = amt.to_nsec();
+  if (data.type & PERFCOUNTER_LONGRUNAVG)
+    ceph_abort();
+}
+
+utime_t LabeledPerfCounters::tget(int idx) const
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return utime_t();
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  if (!(data.type & PERFCOUNTER_TIME))
+    return utime_t();
+  uint64_t v = data.u64;
+  return utime_t(v / 1000000000ull, v % 1000000000ull);
+}
+
+void LabeledPerfCounters::hinc(int idx, int64_t x, int64_t y)
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return;
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+
+  perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  ceph_assert(data.type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
+  ceph_assert(data.histogram);
+
+  data.histogram->inc(x, y);
+}
+
+pair<uint64_t, uint64_t> LabeledPerfCounters::get_tavg_ns(int idx) const
+{
+#ifndef WITH_SEASTAR
+  if (!m_cct->_conf->perf)
+    return make_pair(0, 0);
+#endif
+
+  ceph_assert(idx > m_lower_bound);
+  ceph_assert(idx < m_upper_bound);
+  const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
+  if (!(data.type & PERFCOUNTER_TIME))
+    return make_pair(0, 0);
+  if (!(data.type & PERFCOUNTER_LONGRUNAVG))
+    return make_pair(0, 0);
+  pair<uint64_t,uint64_t> a = data.read_avg();
+  return make_pair(a.second, a.first);
+}
+
+void LabeledPerfCounters::reset()
+{
+  perf_counter_data_vec_t::iterator d = m_data.begin();
+  perf_counter_data_vec_t::iterator d_end = m_data.end();
+
+  while (d != d_end) {
+    d->reset();
+    ++d;
+  }
+}
+
+void LabeledPerfCounters::dump_formatted_generic(Formatter *f, bool schema,
+    bool histograms, const std::string &counter) const
+{
+  f->open_object_section(m_name.c_str());
+  
+  for (perf_counter_data_vec_t::const_iterator d = m_data.begin();
+       d != m_data.end(); ++d) {
+    if (!counter.empty() && counter != d->name) {
+      // Optionally filter on counter name
+      continue;
+    }
+
+    // Switch between normal and histogram view
+    bool is_histogram = (d->type & PERFCOUNTER_HISTOGRAM) != 0;
+    if (is_histogram != histograms) {
+      continue;
+    }
+
+    if (schema) {
+      f->open_object_section(d->name);
+      // we probably should not have exposed this raw field (with bit
+      // values), but existing plugins rely on it so we're stuck with
+      // it.
+      f->dump_int("type", d->type);
+
+      if (d->type & PERFCOUNTER_COUNTER) {
+       f->dump_string("metric_type", "counter");
+      } else {
+       f->dump_string("metric_type", "gauge");
+      }
+
+      if (d->type & PERFCOUNTER_LONGRUNAVG) {
+       if (d->type & PERFCOUNTER_TIME) {
+         f->dump_string("value_type", "real-integer-pair");
+       } else {
+         f->dump_string("value_type", "integer-integer-pair");
+       }
+      } else if (d->type & PERFCOUNTER_HISTOGRAM) {
+       if (d->type & PERFCOUNTER_TIME) {
+         f->dump_string("value_type", "real-2d-histogram");
+       } else {
+         f->dump_string("value_type", "integer-2d-histogram");
+       }
+      } else {
+       if (d->type & PERFCOUNTER_TIME) {
+         f->dump_string("value_type", "real");
+       } else {
+         f->dump_string("value_type", "integer");
+       }
+      }
+
+      f->dump_string("description", d->description ? d->description : "");
+      if (d->nick != NULL) {
+        f->dump_string("nick", d->nick);
+      } else {
+        f->dump_string("nick", "");
+      }
+      f->dump_int("priority", get_adjusted_priority(d->prio));
+      
+      if (d->unit == UNIT_NONE) {
+       f->dump_string("units", "none"); 
+      } else if (d->unit == UNIT_BYTES) {
+       f->dump_string("units", "bytes");
+      }
+      f->close_section();
+    } else {
+      if (d->type & PERFCOUNTER_LONGRUNAVG) {
+       f->open_object_section(d->name);
+       pair<uint64_t,uint64_t> a = d->read_avg();
+       if (d->type & PERFCOUNTER_U64) {
+         f->dump_unsigned("avgcount", a.second);
+         f->dump_unsigned("sum", a.first);
+       } else if (d->type & PERFCOUNTER_TIME) {
+         f->dump_unsigned("avgcount", a.second);
+         f->dump_format_unquoted("sum", "%" PRId64 ".%09" PRId64,
+                                 a.first / 1000000000ull,
+                                 a.first % 1000000000ull);
+          uint64_t count = a.second;
+          uint64_t sum_ns = a.first;
+          if (count) {
+            uint64_t avg_ns = sum_ns / count;
+            f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64,
+                                    avg_ns / 1000000000ull,
+                                    avg_ns % 1000000000ull);
+          } else {
+            f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64, 0, 0);
+          }
+       } else {
+         ceph_abort();
+       }
+       f->close_section();
+      } else if (d->type & PERFCOUNTER_HISTOGRAM) {
+        ceph_assert(d->type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
+        ceph_assert(d->histogram);
+        f->open_object_section(d->name);
+        d->histogram->dump_formatted(f);
+        f->close_section();
+      } else {
+        if(d->accessed) {
+          uint64_t v = d->u64;
+          if (d->type & PERFCOUNTER_U64) {
+            f->dump_unsigned(d->name, v);
+          } else if (d->type & PERFCOUNTER_TIME) {
+            f->dump_format_unquoted(d->name, "%" PRId64 ".%09" PRId64,
+                                    v / 1000000000ull,
+                                    v % 1000000000ull);
+          } else {
+            ceph_abort();
+          }
+        }
+      }
+    }
+  }
+  f->close_section();
+}
+
+const std::string &LabeledPerfCounters::get_name() const
+{
+  return m_name;
+}
+
+LabeledPerfCounters::LabeledPerfCounters(CephContext *cct, const std::string &name,
+          int lower_bound, int upper_bound)
+  : m_cct(cct),
+    m_lower_bound(lower_bound),
+    m_upper_bound(upper_bound),
+    m_name(name)
+#if !defined(WITH_SEASTAR) || defined(WITH_ALIEN)
+    ,
+    m_lock_name(std::string("LabeledPerfCounters::") + name.c_str()),
+    m_lock(ceph::make_mutex(m_lock_name))
+#endif
+{
+  m_data.resize(upper_bound - lower_bound - 1);
+}
+
+LabeledPerfCountersBuilder::LabeledPerfCountersBuilder(CephContext *cct, const std::string &name,
+                  int first, int last)
+  : m_perf_counters(new LabeledPerfCounters(cct, name, first, last))
+{
+}
+
+LabeledPerfCountersBuilder::~LabeledPerfCountersBuilder()
+{
+  if (m_perf_counters)
+    delete m_perf_counters;
+  m_perf_counters = NULL;
+}
+
+void LabeledPerfCountersBuilder::add_u64_counter(
+  int idx, const char *name,
+  const char *description, const char *nick, int prio, int unit)
+{
+  add_impl(idx, name, description, nick, prio,
+          PERFCOUNTER_U64 | PERFCOUNTER_COUNTER, unit);
+}
+
+void LabeledPerfCountersBuilder::add_u64(
+  int idx, const char *name,
+  const char *description, const char *nick, int prio, int unit)
+{
+  add_impl(idx, name, description, nick, prio, PERFCOUNTER_U64, unit);
+}
+
+void LabeledPerfCountersBuilder::add_u64_avg(
+  int idx, const char *name,
+  const char *description, const char *nick, int prio, int unit)
+{
+  add_impl(idx, name, description, nick, prio,
+          PERFCOUNTER_U64 | PERFCOUNTER_LONGRUNAVG, unit);
+}
+
+void LabeledPerfCountersBuilder::add_time(
+  int idx, const char *name,
+  const char *description, const char *nick, int prio)
+{
+  add_impl(idx, name, description, nick, prio, PERFCOUNTER_TIME);
+}
+
+void LabeledPerfCountersBuilder::add_time_avg(
+  int idx, const char *name,
+  const char *description, const char *nick, int prio)
+{
+  add_impl(idx, name, description, nick, prio,
+          PERFCOUNTER_TIME | PERFCOUNTER_LONGRUNAVG);
+}
+
+void LabeledPerfCountersBuilder::add_u64_counter_histogram(
+  int idx, const char *name,
+  PerfHistogramCommon::axis_config_d x_axis_config,
+  PerfHistogramCommon::axis_config_d y_axis_config,
+  const char *description, const char *nick, int prio, int unit)
+{
+  add_impl(idx, name, description, nick, prio,
+          PERFCOUNTER_U64 | PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER, unit,
+           std::unique_ptr<PerfHistogram<>>{new PerfHistogram<>{x_axis_config, y_axis_config}});
+}
+
+void LabeledPerfCountersBuilder::add_impl(
+  int idx, const char *name,
+  const char *description, const char *nick, int prio, int ty, int unit,
+  std::unique_ptr<PerfHistogram<>> histogram)
+{
+  ceph_assert(idx > m_perf_counters->m_lower_bound);
+  ceph_assert(idx < m_perf_counters->m_upper_bound);
+  LabeledPerfCounters::perf_counter_data_vec_t &vec(m_perf_counters->m_data);
+  LabeledPerfCounters::perf_counter_data_any_d
+    &data(vec[idx - m_perf_counters->m_lower_bound - 1]);
+  ceph_assert(data.type == PERFCOUNTER_NONE);
+  data.name = name;
+  data.description = description;
+  // nick must be <= 4 chars
+  if (nick) {
+    ceph_assert(strlen(nick) <= 4);
+  }
+  data.nick = nick;
+  data.prio = prio ? prio : prio_default;
+  data.type = (enum perfcounter_type_d)ty;
+  data.unit = (enum unit_t) unit;
+  data.histogram = std::move(histogram);
+}
+
+LabeledPerfCounters *LabeledPerfCountersBuilder::create_perf_counters()
+{
+  LabeledPerfCounters::perf_counter_data_vec_t::const_iterator d = m_perf_counters->m_data.begin();
+  LabeledPerfCounters::perf_counter_data_vec_t::const_iterator d_end = m_perf_counters->m_data.end();
+  for (; d != d_end; ++d) {
+    ceph_assert(d->type != PERFCOUNTER_NONE);
+    ceph_assert(d->type & (PERFCOUNTER_U64 | PERFCOUNTER_TIME));
+  }
+
+  LabeledPerfCounters *ret = m_perf_counters;
+  m_perf_counters = NULL;
+  return ret;
+}
+
+}
diff --git a/src/common/labeled_perf_counters.h b/src/common/labeled_perf_counters.h
new file mode 100644 (file)
index 0000000..d35bfbe
--- /dev/null
@@ -0,0 +1,349 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2011 New Dream Network
+ * Copyright (C) 2017 OVH
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software 
+ * Foundation.  See file COPYING.
+ * 
+ */
+
+
+#ifndef CEPH_COMMON_LABELED_PERF_COUNTERS_H
+#define CEPH_COMMON_LABELED_PERF_COUNTERS_H
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <atomic>
+#include <cstdint>
+
+#include "common/perf_histogram.h"
+#include "common/perf_counters.h"
+#include "include/utime.h"
+#include "include/common_fwd.h"
+#include "common/ceph_mutex.h"
+#include "common/ceph_time.h"
+
+namespace TOPNSPC::common {
+  class CephContext;
+  class LabeledPerfCountersBuilder;
+  class LabeledPerfCounters;
+}
+
+/* Class for constructing a LabeledPerfCounters object.
+ *
+ * This class performs some validation that the parameters we have supplied are
+ * correct in create_perf_counters().
+ *
+ * In the future, we will probably get rid of the first/last arguments, since
+ * PerfCountersBuilder can deduce them itself.
+ */
+namespace TOPNSPC::common {
+class LabeledPerfCountersBuilder
+{
+public:
+  LabeledPerfCountersBuilder(CephContext *cct, const std::string &name,
+                   int first, int last);
+  ~LabeledPerfCountersBuilder();
+
+  // prio values: higher is better, and higher values get included in
+  // 'ceph daemonperf' (and similar) results.
+  // Use of priorities enables us to add large numbers of counters
+  // internally without necessarily overwhelming consumers.
+  enum {
+    PRIO_CRITICAL = 10,
+    // 'interesting' is the default threshold for `daemonperf` output
+    PRIO_INTERESTING = 8,
+    // `useful` is the default threshold for transmission to ceph-mgr
+    // and inclusion in prometheus/influxdb plugin output
+    PRIO_USEFUL = 5,
+    PRIO_UNINTERESTING = 2,
+    PRIO_DEBUGONLY = 0,
+  };
+  void add_u64(int key, const char *name,
+              const char *description=NULL, const char *nick = NULL,
+              int prio=0, int unit=UNIT_NONE);
+  void add_u64_counter(int key, const char *name,
+                      const char *description=NULL,
+                      const char *nick = NULL,
+                      int prio=0, int unit=UNIT_NONE);
+  void add_u64_avg(int key, const char *name,
+                  const char *description=NULL,
+                  const char *nick = NULL,
+                  int prio=0, int unit=UNIT_NONE);
+  void add_time(int key, const char *name,
+               const char *description=NULL,
+               const char *nick = NULL,
+               int prio=0);
+  void add_time_avg(int key, const char *name,
+                   const char *description=NULL,
+                   const char *nick = NULL,
+                   int prio=0);
+  void add_u64_counter_histogram(
+    int key, const char* name,
+    PerfHistogramCommon::axis_config_d x_axis_config,
+    PerfHistogramCommon::axis_config_d y_axis_config,
+    const char *description=NULL,
+    const char* nick = NULL,
+    int prio=0, int unit=UNIT_NONE);
+
+  void set_prio_default(int prio_)
+  {
+    prio_default = prio_;
+  }
+
+  LabeledPerfCounters* create_perf_counters();
+private:
+  LabeledPerfCountersBuilder(const PerfCountersBuilder &rhs);
+  LabeledPerfCountersBuilder& operator=(const PerfCountersBuilder &rhs);
+  void add_impl(int idx, const char *name,
+                const char *description, const char *nick, int prio, int ty, int unit=UNIT_NONE,
+                std::unique_ptr<PerfHistogram<>> histogram = nullptr);
+
+  LabeledPerfCounters *m_perf_counters;
+
+  int prio_default = 0;
+};
+
+/*
+ * A PerfCounters object is usually associated with a single subsystem.
+ * It contains counters which we modify to track performance and throughput
+ * over time. 
+ *
+ * PerfCounters can track several different types of values:
+ * 1) integer values & counters
+ * 2) floating-point values & counters
+ * 3) floating-point averages
+ * 4) 2D histograms of quantized value pairs
+ *
+ * The difference between values, counters and histograms is in how they are initialized
+ * and accessed. For a counter, use the inc(counter, amount) function (note
+ * that amount defaults to 1 if you don't set it). For a value, use the
+ * set(index, value) function. For histogram use the hinc(value1, value2) function.
+ * (For time, use the tinc and tset variants.)
+ *
+ * If for some reason you would like to reset your counters, you can do so using
+ * the set functions even if they are counters, and you can also
+ * increment your values if for some reason you wish to.
+ *
+ * For the time average, it returns the current value and
+ * the "avgcount" member when read off. avgcount is incremented when you call
+ * tinc. Calling tset on an average is an error and will assert out.
+ */
+class LabeledPerfCounters
+{
+public:
+  /** Represents a PerfCounters data element. */
+  struct perf_counter_data_any_d {
+    perf_counter_data_any_d()
+      : name(NULL),
+        description(NULL),
+        nick(NULL),
+        type(PERFCOUNTER_NONE),
+        unit(UNIT_NONE)
+    {}
+    perf_counter_data_any_d(const perf_counter_data_any_d& other)
+      : name(other.name),
+        description(other.description),
+        nick(other.nick),
+        type(other.type),
+        unit(other.unit),
+        u64(other.u64.load()) {
+      auto a = other.read_avg();
+      u64 = a.first;
+      avgcount = a.second;
+      avgcount2 = a.second;
+      if (other.histogram) {
+        histogram.reset(new PerfHistogram<>(*other.histogram));
+      }
+    }
+
+    const char *name;
+    const char *description;
+    const char *nick;
+    uint8_t prio = 0;
+    enum perfcounter_type_d type;
+    enum unit_t unit;
+    std::atomic<uint64_t> u64 = { 0 };
+    std::atomic<uint64_t> avgcount = { 0 };
+    std::atomic<uint64_t> avgcount2 = { 0 };
+    std::unique_ptr<PerfHistogram<>> histogram;
+    bool accessed = false;
+
+    void reset()
+    {
+      if (type != PERFCOUNTER_U64) {
+           u64 = 0;
+           avgcount = 0;
+           avgcount2 = 0;
+      }
+      if (histogram) {
+        histogram->reset();
+      }
+    }
+
+    // read <sum, count> safely by making sure the post- and pre-count
+    // are identical; in other words the whole loop needs to be run
+    // without any intervening calls to inc, set, or tinc.
+    std::pair<uint64_t,uint64_t> read_avg() const {
+      uint64_t sum, count;
+      do {
+       count = avgcount2;
+       sum = u64;
+      } while (avgcount != count);
+      return { sum, count };
+    }
+  };
+
+  template <typename T>
+  struct avg_tracker {
+    std::pair<uint64_t, T> last;
+    std::pair<uint64_t, T> cur;
+    avg_tracker() : last(0, 0), cur(0, 0) {}
+    T current_avg() const {
+      if (cur.first == last.first)
+        return 0;
+      return (cur.second - last.second) / (cur.first - last.first);
+    }
+    void consume_next(const std::pair<uint64_t, T> &next) {
+      last = cur;
+      cur = next;
+    }
+  };
+
+  ~LabeledPerfCounters();
+
+  void inc(int idx, uint64_t v = 1);
+  void dec(int idx, uint64_t v = 1);
+  void set(int idx, uint64_t v);
+  uint64_t get(int idx) const;
+
+  void tset(int idx, utime_t v);
+  void tinc(int idx, utime_t v);
+  void tinc(int idx, ceph::timespan v);
+  utime_t tget(int idx) const;
+
+  void hinc(int idx, int64_t x, int64_t y);
+
+  void reset();
+  void dump_formatted(ceph::Formatter *f, bool schema,
+                      const std::string &counter = "") const {
+    dump_formatted_generic(f, schema, false, counter);
+  }
+  void dump_formatted_histograms(ceph::Formatter *f, bool schema,
+                                 const std::string &counter = "") const {
+    dump_formatted_generic(f, schema, true, counter);
+  }
+  std::pair<uint64_t, uint64_t> get_tavg_ns(int idx) const;
+
+  const std::string& get_name() const;
+  void set_name(std::string s) {
+    m_name = s;
+  }
+
+  /// adjust priority values by some value
+  void set_prio_adjust(int p) {
+    prio_adjust = p;
+  }
+
+  int get_adjusted_priority(int p) const {
+    return std::max(std::min(p + prio_adjust,
+                             (int)PerfCountersBuilder::PRIO_CRITICAL),
+                    0);
+  }
+
+private:
+  LabeledPerfCounters(CephContext *cct, const std::string &name,
+            int lower_bound, int upper_bound);
+  LabeledPerfCounters(const PerfCounters &rhs);
+  LabeledPerfCounters& operator=(const PerfCounters &rhs);
+  void dump_formatted_generic(ceph::Formatter *f, bool schema, bool histograms,
+                              const std::string &counter = "") const;
+
+  typedef std::vector<perf_counter_data_any_d> perf_counter_data_vec_t;
+
+  CephContext *m_cct;
+  int m_lower_bound;
+  int m_upper_bound;
+  std::string m_name;
+
+  int prio_adjust = 0;
+
+#if !defined(WITH_SEASTAR) || defined(WITH_ALIEN)
+  const std::string m_lock_name;
+  /** Protects m_data */
+  ceph::mutex m_lock;
+#endif
+
+  perf_counter_data_vec_t m_data;
+
+  friend class LabeledPerfCountersBuilder;
+  friend class LabeledPerfCountersCollectionImpl;
+};
+
+class SortLabeledPerfCountersByName {
+public:
+  bool operator()(const LabeledPerfCounters* lhs, const LabeledPerfCounters* rhs) const {
+    return (lhs->get_name() < rhs->get_name());
+  }
+};
+
+typedef std::set <LabeledPerfCounters*, SortLabeledPerfCountersByName> labeled_perf_counters_set_t;
+
+/*
+ * PerfCountersCollectionImp manages PerfCounters objects for a Ceph process.
+ */
+class LabeledPerfCountersCollectionImpl
+{
+public:
+  LabeledPerfCountersCollectionImpl();
+  ~LabeledPerfCountersCollectionImpl();
+  void add(LabeledPerfCounters *l);
+  void remove(LabeledPerfCounters *l);
+  void clear();
+  bool reset(const std::string &name);
+
+  void dump_formatted(ceph::Formatter *f, bool schema,
+                      const std::string &logger = "",
+                      const std::string &counter = "") const {
+    dump_formatted_generic(f, schema, false, logger, counter);
+  }
+
+  void dump_formatted_histograms(ceph::Formatter *f, bool schema,
+                                 const std::string &logger = "",
+                                 const std::string &counter = "") const {
+    dump_formatted_generic(f, schema, true, logger, counter);
+  }
+
+  // A reference to a perf_counter_data_any_d, with an accompanying
+  // pointer to the enclosing PerfCounters, in order that the consumer
+  // can see the prio_adjust
+  class LabeledPerfCounterRef
+  {
+    public:
+    LabeledPerfCounters::perf_counter_data_any_d *data;
+    LabeledPerfCounters *perf_counters;
+  };
+  typedef std::map<std::string,
+          LabeledPerfCounterRef> CounterMap;
+
+  void with_counters(std::function<void(const CounterMap &)>) const;
+
+private:
+  void dump_formatted_generic(ceph::Formatter *f, bool schema, bool histograms,
+                              const std::string &logger = "",
+                              const std::string &counter = "") const;
+
+  labeled_perf_counters_set_t m_loggers;
+
+  CounterMap by_path; 
+};
+
+}
+#endif
diff --git a/src/common/labeled_perf_counters_collection.cc b/src/common/labeled_perf_counters_collection.cc
new file mode 100644 (file)
index 0000000..3da236b
--- /dev/null
@@ -0,0 +1,55 @@
+#include "common/labeled_perf_counters_collection.h"
+#include "common/ceph_mutex.h"
+#include "common/ceph_context.h"
+
+namespace ceph::common {
+LabeledPerfCountersCollection::LabeledPerfCountersCollection(CephContext *cct)
+  : m_cct(cct),
+    m_lock(ceph::make_mutex("PerfCountersCollection"))
+{
+}
+LabeledPerfCountersCollection::~LabeledPerfCountersCollection()
+{
+  clear();
+}
+void LabeledPerfCountersCollection::add(LabeledPerfCounters *l)
+{
+  std::lock_guard lck(m_lock);
+  perf_impl.add(l);
+}
+void LabeledPerfCountersCollection::remove(LabeledPerfCounters *l)
+{
+  std::lock_guard lck(m_lock);
+  perf_impl.remove(l);
+}
+void LabeledPerfCountersCollection::clear()
+{
+  std::lock_guard lck(m_lock);
+  perf_impl.clear();
+}
+bool LabeledPerfCountersCollection::reset(const std::string &name)
+{
+  std::lock_guard lck(m_lock);
+  return perf_impl.reset(name);
+}
+void LabeledPerfCountersCollection::dump_formatted(ceph::Formatter *f, bool schema,
+                      const std::string &logger,
+                      const std::string &counter)
+{
+  std::lock_guard lck(m_lock);
+  perf_impl.dump_formatted(f,schema,logger,counter);
+}
+void LabeledPerfCountersCollection::dump_formatted_histograms(ceph::Formatter *f, bool schema,
+                                 const std::string &logger,
+                                 const std::string &counter)
+{
+  std::lock_guard lck(m_lock);
+  perf_impl.dump_formatted_histograms(f,schema,logger,counter);
+}
+void LabeledPerfCountersCollection::with_counters(std::function<void(const LabeledPerfCountersCollectionImpl::CounterMap &)> fn) const
+{
+  std::lock_guard lck(m_lock);
+  perf_impl.with_counters(fn);
+}
+
+}
diff --git a/src/common/labeled_perf_counters_collection.h b/src/common/labeled_perf_counters_collection.h
new file mode 100644 (file)
index 0000000..6d2166b
--- /dev/null
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "common/labeled_perf_counters.h"
+#include "common/ceph_mutex.h"
+#include "include/common_fwd.h"
+
+namespace ceph::common {
+class LabeledPerfCountersCollection
+{
+  CephContext *m_cct;
+
+  /** Protects perf_impl->m_loggers */
+  mutable ceph::mutex m_lock;
+  LabeledPerfCountersCollectionImpl perf_impl;
+public:
+  LabeledPerfCountersCollection(CephContext *cct);
+  ~LabeledPerfCountersCollection();
+  void add(LabeledPerfCounters *l);
+  void remove(LabeledPerfCounters *l);
+  void clear();
+  bool reset(const std::string &name);
+
+  void dump_formatted(ceph::Formatter *f, bool schema,
+                      const std::string &logger = "",
+                      const std::string &counter = "");
+  void dump_formatted_histograms(ceph::Formatter *f, bool schema,
+                                 const std::string &logger = "",
+                                 const std::string &counter = "");
+
+  void with_counters(std::function<void(const LabeledPerfCountersCollectionImpl::CounterMap &)>) const;
+  friend class PerfCountersCollectionTest;
+};
+}
index 420ff928c06cad1ed37c029a2c343a1ebe26e65b..b4259254ee954089980701cab9f1ad343735403b 100644 (file)
@@ -175,6 +175,7 @@ void PerfCounters::inc(int idx, uint64_t amt)
   } else {
     data.u64 += amt;
   }
+  data.accessed = true;
 }
 
 void PerfCounters::dec(int idx, uint64_t amt)
@@ -451,16 +452,18 @@ void PerfCounters::dump_formatted_generic(Formatter *f, bool schema,
         d->histogram->dump_formatted(f);
         f->close_section();
       } else {
-       uint64_t v = d->u64;
-       if (d->type & PERFCOUNTER_U64) {
-         f->dump_unsigned(d->name, v);
-       } else if (d->type & PERFCOUNTER_TIME) {
-         f->dump_format_unquoted(d->name, "%" PRId64 ".%09" PRId64,
-                                 v / 1000000000ull,
-                                 v % 1000000000ull);
-       } else {
-         ceph_abort();
-       }
+        if(d->accessed) {
+          uint64_t v = d->u64;
+          if (d->type & PERFCOUNTER_U64) {
+            f->dump_unsigned(d->name, v);
+          } else if (d->type & PERFCOUNTER_TIME) {
+            f->dump_format_unquoted(d->name, "%" PRId64 ".%09" PRId64,
+                                    v / 1000000000ull,
+                                    v % 1000000000ull);
+          } else {
+            ceph_abort();
+          }
+        }
       }
     }
   }
index c5f69aa7ce31abcb911c86d29f586f951f79faf3..559b31e07cf9d05af00269cc982ef666f89b7c1a 100644 (file)
@@ -189,6 +189,7 @@ public:
     std::atomic<uint64_t> avgcount = { 0 };
     std::atomic<uint64_t> avgcount2 = { 0 };
     std::unique_ptr<PerfHistogram<>> histogram;
+    bool accessed = false;
 
     void reset()
     {
index 872e41436a6f265cd5ee4d89984ed545b00ad84a..f11af43cd27befb8d19ddc7b1acb8338ded311a7 100644 (file)
@@ -60,7 +60,8 @@ public:
       plb.add_u64_counter(l_rgw_metrics_get_b, "get_b", "Size of gets", NULL, 8, UNIT_NONE);
 
       PerfCounters *counters = plb.create_perf_counters();
-      cct->get_labeledperfcounters_collection()->add(counters);
+      //cct->get_labeledperfcounters_collection()->add(counters);
+      cct->get_perfcounters_collection()->add(counters);
       ref->perfcounters_instance = counters;
       //ref->collection = cct->get_perfcounters_collection();
       //ref->collection->add(counters);
index 5f51d7e3aa89dab213038d04feb4f04d833e5577..bc1daa5003b936ea91bca5d0744f9f7c53a56f19 100644 (file)
@@ -2323,7 +2323,7 @@ void RGWGetObj::execute(optional_yield y)
   }
 
   labels = ceph::perf_counters::cache_key("z_rgw", {{"Bucket", s->bucket_name}, {"User", s->user->get_display_name()}});
-  //ldpp_dout(this, 20) << "labels for perf counters cache: " << labels << dendl;
+  ldpp_dout(this, 20) << "labels for perf counters cache for l_rgw_metrics_get_b: " << labels << dendl;
   perf_counters_cache->add(labels);
   perf_counters_cache->inc(labels, l_rgw_metrics_get_b, s->obj_size);
 
@@ -4173,7 +4173,7 @@ void RGWPutObj::execute(optional_yield y)
   s->object->set_obj_size(ofs);
 
   std::string labels = ceph::perf_counters::cache_key("z_rgw", {{"Bucket", s->bucket_name}, {"User", s->user->get_display_name()}});
-  //ldpp_dout(this, 20) << "labels for perf counters cache: " << labels << dendl;
+  ldpp_dout(this, 20) << "labels for perf counters cache for l_rgw_metrics_put_b: " << labels << dendl;
   perf_counters_cache->add(labels);
   perf_counters_cache->inc(labels, l_rgw_metrics_put_b, s->obj_size);