1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
7 * Copyright (C) 2017 OVH
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
16 #include "common/perf_counters.h"
17 #include "common/dout.h"
18 #include "common/valgrind.h"
20 using std::ostringstream;
22 PerfCountersCollection::PerfCountersCollection(CephContext *cct)
24 m_lock("PerfCountersCollection")
28 PerfCountersCollection::~PerfCountersCollection()
33 void PerfCountersCollection::add(class PerfCounters *l)
35 Mutex::Locker lck(m_lock);
37 // make sure the name is unique
38 perf_counters_set_t::iterator i;
39 i = m_loggers.find(l);
40 while (i != m_loggers.end()) {
42 ss << l->get_name() << "-" << (void*)l;
43 l->set_name(ss.str());
44 i = m_loggers.find(l);
49 for (unsigned int i = 0; i < l->m_data.size(); ++i) {
50 PerfCounters::perf_counter_data_any_d &data = l->m_data[i];
52 std::string path = l->get_name();
56 by_path[path] = {&data, l};
60 void PerfCountersCollection::remove(class PerfCounters *l)
62 Mutex::Locker lck(m_lock);
64 for (unsigned int i = 0; i < l->m_data.size(); ++i) {
65 PerfCounters::perf_counter_data_any_d &data = l->m_data[i];
67 std::string path = l->get_name();
74 perf_counters_set_t::iterator i = m_loggers.find(l);
75 assert(i != m_loggers.end());
79 void PerfCountersCollection::clear()
81 Mutex::Locker lck(m_lock);
82 perf_counters_set_t::iterator i = m_loggers.begin();
83 perf_counters_set_t::iterator i_end = m_loggers.end();
84 for (; i != i_end; ) {
91 bool PerfCountersCollection::reset(const std::string &name)
94 Mutex::Locker lck(m_lock);
95 perf_counters_set_t::iterator i = m_loggers.begin();
96 perf_counters_set_t::iterator i_end = m_loggers.end();
98 if (!strcmp(name.c_str(), "all")) {
106 if (!name.compare((*i)->get_name())) {
120 * Serialize current values of performance counters. Optionally
121 * output the schema instead, or filter output to a particular
122 * PerfCounters or particular named counter.
124 * @param logger name of subsystem logger, e.g. "mds_cache", may be empty
125 * @param counter name of counter within subsystem, e.g. "num_strays",
127 * @param schema if true, output schema instead of current data.
128 * @param histograms if true, dump histogram values,
129 * if false dump all non-histogram counters
131 void PerfCountersCollection::dump_formatted_generic(
135 const std::string &logger,
136 const std::string &counter)
138 Mutex::Locker lck(m_lock);
139 f->open_object_section("perfcounter_collection");
141 for (perf_counters_set_t::iterator l = m_loggers.begin();
142 l != m_loggers.end(); ++l) {
143 // Optionally filter on logger name, pass through counter filter
144 if (logger.empty() || (*l)->get_name() == logger) {
145 (*l)->dump_formatted_generic(f, schema, histograms, counter);
151 void PerfCountersCollection::with_counters(std::function<void(
152 const PerfCountersCollection::CounterMap &)> fn) const
154 Mutex::Locker lck(m_lock);
159 // ---------------------------
161 PerfCounters::~PerfCounters()
165 void PerfCounters::inc(int idx, uint64_t amt)
167 if (!m_cct->_conf->perf)
170 assert(idx > m_lower_bound);
171 assert(idx < m_upper_bound);
172 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
173 if (!(data.type & PERFCOUNTER_U64))
175 if (data.type & PERFCOUNTER_LONGRUNAVG) {
184 void PerfCounters::dec(int idx, uint64_t amt)
186 if (!m_cct->_conf->perf)
189 assert(idx > m_lower_bound);
190 assert(idx < m_upper_bound);
191 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
192 assert(!(data.type & PERFCOUNTER_LONGRUNAVG));
193 if (!(data.type & PERFCOUNTER_U64))
198 void PerfCounters::set(int idx, uint64_t amt)
200 if (!m_cct->_conf->perf)
203 assert(idx > m_lower_bound);
204 assert(idx < m_upper_bound);
205 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
206 if (!(data.type & PERFCOUNTER_U64))
209 ANNOTATE_BENIGN_RACE_SIZED(&data.u64, sizeof(data.u64),
210 "perf counter atomic");
211 if (data.type & PERFCOUNTER_LONGRUNAVG) {
220 uint64_t PerfCounters::get(int idx) const
222 if (!m_cct->_conf->perf)
225 assert(idx > m_lower_bound);
226 assert(idx < m_upper_bound);
227 const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
228 if (!(data.type & PERFCOUNTER_U64))
233 void PerfCounters::tinc(int idx, utime_t amt, uint32_t avgcount)
235 if (!m_cct->_conf->perf)
238 assert(idx > m_lower_bound);
239 assert(idx < m_upper_bound);
240 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
241 if (!(data.type & PERFCOUNTER_TIME))
243 if (data.type & PERFCOUNTER_LONGRUNAVG) {
245 data.u64 += amt.to_nsec();
248 data.u64 += amt.to_nsec();
252 void PerfCounters::tinc(int idx, ceph::timespan amt, uint32_t avgcount)
254 if (!m_cct->_conf->perf)
257 assert(idx > m_lower_bound);
258 assert(idx < m_upper_bound);
259 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
260 if (!(data.type & PERFCOUNTER_TIME))
262 if (data.type & PERFCOUNTER_LONGRUNAVG) {
264 data.u64 += amt.count();
267 data.u64 += amt.count();
271 void PerfCounters::tset(int idx, utime_t amt)
273 if (!m_cct->_conf->perf)
276 assert(idx > m_lower_bound);
277 assert(idx < m_upper_bound);
278 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
279 if (!(data.type & PERFCOUNTER_TIME))
281 data.u64 = amt.to_nsec();
282 if (data.type & PERFCOUNTER_LONGRUNAVG)
286 utime_t PerfCounters::tget(int idx) const
288 if (!m_cct->_conf->perf)
291 assert(idx > m_lower_bound);
292 assert(idx < m_upper_bound);
293 const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
294 if (!(data.type & PERFCOUNTER_TIME))
296 uint64_t v = data.u64;
297 return utime_t(v / 1000000000ull, v % 1000000000ull);
300 void PerfCounters::hinc(int idx, int64_t x, int64_t y)
302 if (!m_cct->_conf->perf)
305 assert(idx > m_lower_bound);
306 assert(idx < m_upper_bound);
308 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
309 assert(data.type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
310 assert(data.histogram);
312 data.histogram->inc(x, y);
315 pair<uint64_t, uint64_t> PerfCounters::get_tavg_ms(int idx) const
317 if (!m_cct->_conf->perf)
318 return make_pair(0, 0);
320 assert(idx > m_lower_bound);
321 assert(idx < m_upper_bound);
322 const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
323 if (!(data.type & PERFCOUNTER_TIME))
324 return make_pair(0, 0);
325 if (!(data.type & PERFCOUNTER_LONGRUNAVG))
326 return make_pair(0, 0);
327 pair<uint64_t,uint64_t> a = data.read_avg();
328 return make_pair(a.second, a.first / 1000000ull);
331 void PerfCounters::reset()
333 perf_counter_data_vec_t::iterator d = m_data.begin();
334 perf_counter_data_vec_t::iterator d_end = m_data.end();
342 void PerfCounters::dump_formatted_generic(Formatter *f, bool schema,
343 bool histograms, const std::string &counter)
345 f->open_object_section(m_name.c_str());
347 for (perf_counter_data_vec_t::const_iterator d = m_data.begin();
348 d != m_data.end(); ++d) {
349 if (!counter.empty() && counter != d->name) {
350 // Optionally filter on counter name
354 // Switch between normal and histogram view
355 bool is_histogram = (d->type & PERFCOUNTER_HISTOGRAM) != 0;
356 if (is_histogram != histograms) {
361 f->open_object_section(d->name);
362 // we probably should not have exposed this raw field (with bit
363 // values), but existing plugins rely on it so we're stuck with
365 f->dump_int("type", d->type);
367 if (d->type & PERFCOUNTER_COUNTER) {
368 f->dump_string("metric_type", "counter");
370 f->dump_string("metric_type", "gauge");
373 if (d->type & PERFCOUNTER_LONGRUNAVG) {
374 if (d->type & PERFCOUNTER_TIME) {
375 f->dump_string("value_type", "real-integer-pair");
377 f->dump_string("value_type", "integer-integer-pair");
379 } else if (d->type & PERFCOUNTER_HISTOGRAM) {
380 if (d->type & PERFCOUNTER_TIME) {
381 f->dump_string("value_type", "real-2d-histogram");
383 f->dump_string("value_type", "integer-2d-histogram");
386 if (d->type & PERFCOUNTER_TIME) {
387 f->dump_string("value_type", "real");
389 f->dump_string("value_type", "integer");
393 f->dump_string("description", d->description ? d->description : "");
394 if (d->nick != NULL) {
395 f->dump_string("nick", d->nick);
397 f->dump_string("nick", "");
399 f->dump_int("priority", get_adjusted_priority(d->prio));
402 if (d->type & PERFCOUNTER_LONGRUNAVG) {
403 f->open_object_section(d->name);
404 pair<uint64_t,uint64_t> a = d->read_avg();
405 if (d->type & PERFCOUNTER_U64) {
406 f->dump_unsigned("avgcount", a.second);
407 f->dump_unsigned("sum", a.first);
408 } else if (d->type & PERFCOUNTER_TIME) {
409 f->dump_unsigned("avgcount", a.second);
410 f->dump_format_unquoted("sum", "%" PRId64 ".%09" PRId64,
411 a.first / 1000000000ull,
412 a.first % 1000000000ull);
413 uint64_t count = a.second;
414 uint64_t sum_ns = a.first;
416 uint64_t avg_ns = sum_ns / count;
417 f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64,
418 avg_ns / 1000000000ull,
419 avg_ns % 1000000000ull);
421 f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64, 0, 0);
427 } else if (d->type & PERFCOUNTER_HISTOGRAM) {
428 assert(d->type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
429 assert(d->histogram);
430 f->open_object_section(d->name);
431 d->histogram->dump_formatted(f);
435 if (d->type & PERFCOUNTER_U64) {
436 f->dump_unsigned(d->name, v);
437 } else if (d->type & PERFCOUNTER_TIME) {
438 f->dump_format_unquoted(d->name, "%" PRId64 ".%09" PRId64,
450 const std::string &PerfCounters::get_name() const
455 PerfCounters::PerfCounters(CephContext *cct, const std::string &name,
456 int lower_bound, int upper_bound)
458 m_lower_bound(lower_bound),
459 m_upper_bound(upper_bound),
460 m_name(name.c_str()),
461 m_lock_name(std::string("PerfCounters::") + name.c_str()),
462 m_lock(m_lock_name.c_str())
464 m_data.resize(upper_bound - lower_bound - 1);
467 PerfCountersBuilder::PerfCountersBuilder(CephContext *cct, const std::string &name,
469 : m_perf_counters(new PerfCounters(cct, name, first, last))
473 PerfCountersBuilder::~PerfCountersBuilder()
476 delete m_perf_counters;
477 m_perf_counters = NULL;
480 void PerfCountersBuilder::add_u64_counter(
481 int idx, const char *name,
482 const char *description, const char *nick, int prio)
484 add_impl(idx, name, description, nick, prio,
485 PERFCOUNTER_U64 | PERFCOUNTER_COUNTER);
488 void PerfCountersBuilder::add_u64(
489 int idx, const char *name,
490 const char *description, const char *nick, int prio)
492 add_impl(idx, name, description, nick, prio, PERFCOUNTER_U64);
495 void PerfCountersBuilder::add_u64_avg(
496 int idx, const char *name,
497 const char *description, const char *nick, int prio)
499 add_impl(idx, name, description, nick, prio,
500 PERFCOUNTER_U64 | PERFCOUNTER_LONGRUNAVG);
503 void PerfCountersBuilder::add_time(
504 int idx, const char *name,
505 const char *description, const char *nick, int prio)
507 add_impl(idx, name, description, nick, prio, PERFCOUNTER_TIME);
510 void PerfCountersBuilder::add_time_avg(
511 int idx, const char *name,
512 const char *description, const char *nick, int prio)
514 add_impl(idx, name, description, nick, prio,
515 PERFCOUNTER_TIME | PERFCOUNTER_LONGRUNAVG);
518 void PerfCountersBuilder::add_u64_counter_histogram(
519 int idx, const char *name,
520 PerfHistogramCommon::axis_config_d x_axis_config,
521 PerfHistogramCommon::axis_config_d y_axis_config,
522 const char *description, const char *nick, int prio)
524 add_impl(idx, name, description, nick, prio,
525 PERFCOUNTER_U64 | PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER,
526 unique_ptr<PerfHistogram<>>{new PerfHistogram<>{x_axis_config, y_axis_config}});
529 void PerfCountersBuilder::add_impl(
530 int idx, const char *name,
531 const char *description, const char *nick, int prio, int ty,
532 unique_ptr<PerfHistogram<>> histogram)
534 assert(idx > m_perf_counters->m_lower_bound);
535 assert(idx < m_perf_counters->m_upper_bound);
536 PerfCounters::perf_counter_data_vec_t &vec(m_perf_counters->m_data);
537 PerfCounters::perf_counter_data_any_d
538 &data(vec[idx - m_perf_counters->m_lower_bound - 1]);
539 assert(data.type == PERFCOUNTER_NONE);
541 data.description = description;
542 // nick must be <= 4 chars
544 assert(strlen(nick) <= 4);
547 data.prio = prio ? prio : prio_default;
548 data.type = (enum perfcounter_type_d)ty;
549 data.histogram = std::move(histogram);
552 PerfCounters *PerfCountersBuilder::create_perf_counters()
554 PerfCounters::perf_counter_data_vec_t::const_iterator d = m_perf_counters->m_data.begin();
555 PerfCounters::perf_counter_data_vec_t::const_iterator d_end = m_perf_counters->m_data.end();
556 for (; d != d_end; ++d) {
557 assert(d->type != PERFCOUNTER_NONE);
558 assert(d->type & (PERFCOUNTER_U64 | PERFCOUNTER_TIME));
561 PerfCounters *ret = m_perf_counters;
562 m_perf_counters = NULL;