X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcommon%2Fperf_counters.cc;fp=src%2Fceph%2Fsrc%2Fcommon%2Fperf_counters.cc;h=048c93a64334a20ef59abdbc4eff08d167979ad7;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/common/perf_counters.cc b/src/ceph/src/common/perf_counters.cc new file mode 100644 index 0000000..048c93a --- /dev/null +++ b/src/ceph/src/common/perf_counters.cc @@ -0,0 +1,565 @@ +// -*- 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/perf_counters.h" +#include "common/dout.h" +#include "common/valgrind.h" + +using std::ostringstream; + +PerfCountersCollection::PerfCountersCollection(CephContext *cct) + : m_cct(cct), + m_lock("PerfCountersCollection") +{ +} + +PerfCountersCollection::~PerfCountersCollection() +{ + clear(); +} + +void PerfCountersCollection::add(class PerfCounters *l) +{ + Mutex::Locker lck(m_lock); + + // make sure the name is unique + 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) { + PerfCounters::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 PerfCountersCollection::remove(class PerfCounters *l) +{ + Mutex::Locker lck(m_lock); + + for (unsigned int i = 0; i < l->m_data.size(); ++i) { + PerfCounters::perf_counter_data_any_d &data = l->m_data[i]; + + std::string path = l->get_name(); + path += "."; + path += data.name; + + by_path.erase(path); + } + + perf_counters_set_t::iterator i = m_loggers.find(l); + assert(i != m_loggers.end()); + m_loggers.erase(i); +} + +void PerfCountersCollection::clear() +{ + Mutex::Locker lck(m_lock); + perf_counters_set_t::iterator i = m_loggers.begin(); + perf_counters_set_t::iterator i_end = m_loggers.end(); + for (; i != i_end; ) { + m_loggers.erase(i++); + } + + by_path.clear(); +} + +bool PerfCountersCollection::reset(const std::string &name) +{ + bool result = false; + Mutex::Locker lck(m_lock); + perf_counters_set_t::iterator i = m_loggers.begin(); + 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 + * PerfCounters 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 PerfCountersCollection::dump_formatted_generic( + Formatter *f, + bool schema, + bool histograms, + const std::string &logger, + const std::string &counter) +{ + Mutex::Locker lck(m_lock); + f->open_object_section("perfcounter_collection"); + + for (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 PerfCountersCollection::with_counters(std::function fn) const +{ + Mutex::Locker lck(m_lock); + + fn(by_path); +} + +// --------------------------- + +PerfCounters::~PerfCounters() +{ +} + +void PerfCounters::inc(int idx, uint64_t amt) +{ + if (!m_cct->_conf->perf) + return; + + assert(idx > m_lower_bound); + 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; + } +} + +void PerfCounters::dec(int idx, uint64_t amt) +{ + if (!m_cct->_conf->perf) + return; + + assert(idx > m_lower_bound); + assert(idx < m_upper_bound); + perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); + assert(!(data.type & PERFCOUNTER_LONGRUNAVG)); + if (!(data.type & PERFCOUNTER_U64)) + return; + data.u64 -= amt; +} + +void PerfCounters::set(int idx, uint64_t amt) +{ + if (!m_cct->_conf->perf) + return; + + assert(idx > m_lower_bound); + 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 PerfCounters::get(int idx) const +{ + if (!m_cct->_conf->perf) + return 0; + + assert(idx > m_lower_bound); + 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 PerfCounters::tinc(int idx, utime_t amt, uint32_t avgcount) +{ + if (!m_cct->_conf->perf) + return; + + assert(idx > m_lower_bound); + 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 PerfCounters::tinc(int idx, ceph::timespan amt, uint32_t avgcount) +{ + if (!m_cct->_conf->perf) + return; + + assert(idx > m_lower_bound); + 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 PerfCounters::tset(int idx, utime_t amt) +{ + if (!m_cct->_conf->perf) + return; + + assert(idx > m_lower_bound); + 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 PerfCounters::tget(int idx) const +{ + if (!m_cct->_conf->perf) + return utime_t(); + + assert(idx > m_lower_bound); + 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 PerfCounters::hinc(int idx, int64_t x, int64_t y) +{ + if (!m_cct->_conf->perf) + return; + + assert(idx > m_lower_bound); + assert(idx < m_upper_bound); + + perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]); + assert(data.type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64)); + assert(data.histogram); + + data.histogram->inc(x, y); +} + +pair PerfCounters::get_tavg_ms(int idx) const +{ + if (!m_cct->_conf->perf) + return make_pair(0, 0); + + assert(idx > m_lower_bound); + 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 a = data.read_avg(); + return make_pair(a.second, a.first / 1000000ull); +} + +void PerfCounters::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 PerfCounters::dump_formatted_generic(Formatter *f, bool schema, + bool histograms, const std::string &counter) +{ + 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)); + f->close_section(); + } else { + if (d->type & PERFCOUNTER_LONGRUNAVG) { + f->open_object_section(d->name); + pair 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) { + assert(d->type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64)); + assert(d->histogram); + f->open_object_section(d->name); + 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(); + } + } + } + } + f->close_section(); +} + +const std::string &PerfCounters::get_name() const +{ + return m_name; +} + +PerfCounters::PerfCounters(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.c_str()), + m_lock_name(std::string("PerfCounters::") + name.c_str()), + m_lock(m_lock_name.c_str()) +{ + m_data.resize(upper_bound - lower_bound - 1); +} + +PerfCountersBuilder::PerfCountersBuilder(CephContext *cct, const std::string &name, + int first, int last) + : m_perf_counters(new PerfCounters(cct, name, first, last)) +{ +} + +PerfCountersBuilder::~PerfCountersBuilder() +{ + if (m_perf_counters) + delete m_perf_counters; + m_perf_counters = NULL; +} + +void PerfCountersBuilder::add_u64_counter( + int idx, const char *name, + const char *description, const char *nick, int prio) +{ + add_impl(idx, name, description, nick, prio, + PERFCOUNTER_U64 | PERFCOUNTER_COUNTER); +} + +void PerfCountersBuilder::add_u64( + int idx, const char *name, + const char *description, const char *nick, int prio) +{ + add_impl(idx, name, description, nick, prio, PERFCOUNTER_U64); +} + +void PerfCountersBuilder::add_u64_avg( + int idx, const char *name, + const char *description, const char *nick, int prio) +{ + add_impl(idx, name, description, nick, prio, + PERFCOUNTER_U64 | PERFCOUNTER_LONGRUNAVG); +} + +void PerfCountersBuilder::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 PerfCountersBuilder::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 PerfCountersBuilder::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) +{ + add_impl(idx, name, description, nick, prio, + PERFCOUNTER_U64 | PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER, + unique_ptr>{new PerfHistogram<>{x_axis_config, y_axis_config}}); +} + +void PerfCountersBuilder::add_impl( + int idx, const char *name, + const char *description, const char *nick, int prio, int ty, + unique_ptr> histogram) +{ + assert(idx > m_perf_counters->m_lower_bound); + assert(idx < m_perf_counters->m_upper_bound); + PerfCounters::perf_counter_data_vec_t &vec(m_perf_counters->m_data); + PerfCounters::perf_counter_data_any_d + &data(vec[idx - m_perf_counters->m_lower_bound - 1]); + assert(data.type == PERFCOUNTER_NONE); + data.name = name; + data.description = description; + // nick must be <= 4 chars + if (nick) { + assert(strlen(nick) <= 4); + } + data.nick = nick; + data.prio = prio ? prio : prio_default; + data.type = (enum perfcounter_type_d)ty; + data.histogram = std::move(histogram); +} + +PerfCounters *PerfCountersBuilder::create_perf_counters() +{ + PerfCounters::perf_counter_data_vec_t::const_iterator d = m_perf_counters->m_data.begin(); + PerfCounters::perf_counter_data_vec_t::const_iterator d_end = m_perf_counters->m_data.end(); + for (; d != d_end; ++d) { + assert(d->type != PERFCOUNTER_NONE); + assert(d->type & (PERFCOUNTER_U64 | PERFCOUNTER_TIME)); + } + + PerfCounters *ret = m_perf_counters; + m_perf_counters = NULL; + return ret; +} +