hostname.cc
ipaddr.cc
iso_8601.cc
+ labeled_perf_counters.cc
+ labeled_perf_counters_collection.cc
mempool.cc
mime.c
numa.cc
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();
}
_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);
return _perf_counters_collection;
}
-PerfCountersCollection *CephContext::get_labeledperfcounters_collection()
+LabeledPerfCountersCollection *CephContext::get_labeledperfcounters_collection()
{
return _labeled_perf_counters_collection;
}
#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;
/* 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;
/* 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;
--- /dev/null
+// -*- 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;
+}
+
+}
--- /dev/null
+// -*- 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
--- /dev/null
+#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);
+}
+
+}
--- /dev/null
+#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;
+};
+}
} else {
data.u64 += amt;
}
+ data.accessed = true;
}
void PerfCounters::dec(int idx, uint64_t amt)
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();
+ }
+ }
}
}
}
std::atomic<uint64_t> avgcount = { 0 };
std::atomic<uint64_t> avgcount2 = { 0 };
std::unique_ptr<PerfHistogram<>> histogram;
+ bool accessed = false;
void reset()
{
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);
}
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);
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);