]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/perf_counters.cc
update sources to 12.2.8
[ceph.git] / ceph / src / common / perf_counters.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2011 New Dream Network
7 * Copyright (C) 2017 OVH
8 *
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.
13 *
14 */
15
7c673cae
FG
16#include "common/perf_counters.h"
17#include "common/dout.h"
7c673cae
FG
18#include "common/valgrind.h"
19
7c673cae
FG
20using std::ostringstream;
21
22PerfCountersCollection::PerfCountersCollection(CephContext *cct)
23 : m_cct(cct),
24 m_lock("PerfCountersCollection")
25{
26}
27
28PerfCountersCollection::~PerfCountersCollection()
29{
30 clear();
31}
32
33void PerfCountersCollection::add(class PerfCounters *l)
34{
35 Mutex::Locker lck(m_lock);
36
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()) {
41 ostringstream ss;
42 ss << l->get_name() << "-" << (void*)l;
43 l->set_name(ss.str());
44 i = m_loggers.find(l);
45 }
46
47 m_loggers.insert(l);
48
49 for (unsigned int i = 0; i < l->m_data.size(); ++i) {
50 PerfCounters::perf_counter_data_any_d &data = l->m_data[i];
51
52 std::string path = l->get_name();
53 path += ".";
54 path += data.name;
55
3efd9988 56 by_path[path] = {&data, l};
7c673cae
FG
57 }
58}
59
60void PerfCountersCollection::remove(class PerfCounters *l)
61{
62 Mutex::Locker lck(m_lock);
63
64 for (unsigned int i = 0; i < l->m_data.size(); ++i) {
65 PerfCounters::perf_counter_data_any_d &data = l->m_data[i];
66
67 std::string path = l->get_name();
68 path += ".";
69 path += data.name;
70
71 by_path.erase(path);
72 }
73
74 perf_counters_set_t::iterator i = m_loggers.find(l);
75 assert(i != m_loggers.end());
76 m_loggers.erase(i);
77}
78
79void PerfCountersCollection::clear()
80{
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; ) {
85 m_loggers.erase(i++);
86 }
87
88 by_path.clear();
89}
90
91bool PerfCountersCollection::reset(const std::string &name)
92{
93 bool result = false;
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();
97
98 if (!strcmp(name.c_str(), "all")) {
99 while (i != i_end) {
100 (*i)->reset();
101 ++i;
102 }
103 result = true;
104 } else {
105 while (i != i_end) {
106 if (!name.compare((*i)->get_name())) {
107 (*i)->reset();
108 result = true;
109 break;
110 }
111 ++i;
112 }
113 }
114
115 return result;
116}
117
118
119/**
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.
123 *
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",
126 * may be empty.
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
130 */
131void PerfCountersCollection::dump_formatted_generic(
132 Formatter *f,
133 bool schema,
134 bool histograms,
135 const std::string &logger,
136 const std::string &counter)
137{
138 Mutex::Locker lck(m_lock);
139 f->open_object_section("perfcounter_collection");
140
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);
146 }
147 }
148 f->close_section();
149}
150
151void PerfCountersCollection::with_counters(std::function<void(
152 const PerfCountersCollection::CounterMap &)> fn) const
153{
154 Mutex::Locker lck(m_lock);
155
156 fn(by_path);
157}
158
159// ---------------------------
160
161PerfCounters::~PerfCounters()
162{
163}
164
165void PerfCounters::inc(int idx, uint64_t amt)
166{
167 if (!m_cct->_conf->perf)
168 return;
169
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))
174 return;
175 if (data.type & PERFCOUNTER_LONGRUNAVG) {
31f18b77
FG
176 data.avgcount++;
177 data.u64 += amt;
178 data.avgcount2++;
7c673cae 179 } else {
31f18b77 180 data.u64 += amt;
7c673cae
FG
181 }
182}
183
184void PerfCounters::dec(int idx, uint64_t amt)
185{
186 if (!m_cct->_conf->perf)
187 return;
188
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))
194 return;
31f18b77 195 data.u64 -= amt;
7c673cae
FG
196}
197
198void PerfCounters::set(int idx, uint64_t amt)
199{
200 if (!m_cct->_conf->perf)
201 return;
202
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))
207 return;
208
209 ANNOTATE_BENIGN_RACE_SIZED(&data.u64, sizeof(data.u64),
210 "perf counter atomic");
211 if (data.type & PERFCOUNTER_LONGRUNAVG) {
31f18b77
FG
212 data.avgcount++;
213 data.u64 = amt;
214 data.avgcount2++;
7c673cae 215 } else {
31f18b77 216 data.u64 = amt;
7c673cae
FG
217 }
218}
219
220uint64_t PerfCounters::get(int idx) const
221{
222 if (!m_cct->_conf->perf)
223 return 0;
224
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))
229 return 0;
31f18b77 230 return data.u64;
7c673cae
FG
231}
232
233void PerfCounters::tinc(int idx, utime_t amt, uint32_t avgcount)
234{
235 if (!m_cct->_conf->perf)
236 return;
237
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))
242 return;
243 if (data.type & PERFCOUNTER_LONGRUNAVG) {
31f18b77
FG
244 data.avgcount++;
245 data.u64 += amt.to_nsec();
246 data.avgcount2++;
7c673cae 247 } else {
31f18b77 248 data.u64 += amt.to_nsec();
7c673cae
FG
249 }
250}
251
252void PerfCounters::tinc(int idx, ceph::timespan amt, uint32_t avgcount)
253{
254 if (!m_cct->_conf->perf)
255 return;
256
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))
261 return;
262 if (data.type & PERFCOUNTER_LONGRUNAVG) {
31f18b77
FG
263 data.avgcount++;
264 data.u64 += amt.count();
265 data.avgcount2++;
7c673cae 266 } else {
31f18b77 267 data.u64 += amt.count();
7c673cae
FG
268 }
269}
270
271void PerfCounters::tset(int idx, utime_t amt)
272{
273 if (!m_cct->_conf->perf)
274 return;
275
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))
280 return;
31f18b77 281 data.u64 = amt.to_nsec();
7c673cae
FG
282 if (data.type & PERFCOUNTER_LONGRUNAVG)
283 ceph_abort();
284}
285
286utime_t PerfCounters::tget(int idx) const
287{
288 if (!m_cct->_conf->perf)
289 return utime_t();
290
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))
295 return utime_t();
31f18b77 296 uint64_t v = data.u64;
7c673cae
FG
297 return utime_t(v / 1000000000ull, v % 1000000000ull);
298}
299
300void PerfCounters::hinc(int idx, int64_t x, int64_t y)
301{
302 if (!m_cct->_conf->perf)
303 return;
304
305 assert(idx > m_lower_bound);
306 assert(idx < m_upper_bound);
307
308 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
31f18b77 309 assert(data.type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
7c673cae
FG
310 assert(data.histogram);
311
312 data.histogram->inc(x, y);
313}
314
315pair<uint64_t, uint64_t> PerfCounters::get_tavg_ms(int idx) const
316{
317 if (!m_cct->_conf->perf)
318 return make_pair(0, 0);
319
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);
329}
330
331void PerfCounters::reset()
332{
333 perf_counter_data_vec_t::iterator d = m_data.begin();
334 perf_counter_data_vec_t::iterator d_end = m_data.end();
335
336 while (d != d_end) {
337 d->reset();
338 ++d;
339 }
340}
341
342void PerfCounters::dump_formatted_generic(Formatter *f, bool schema,
343 bool histograms, const std::string &counter)
344{
345 f->open_object_section(m_name.c_str());
346
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
351 continue;
352 }
353
354 // Switch between normal and histogram view
355 bool is_histogram = (d->type & PERFCOUNTER_HISTOGRAM) != 0;
356 if (is_histogram != histograms) {
357 continue;
358 }
359
360 if (schema) {
361 f->open_object_section(d->name);
31f18b77
FG
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
364 // it.
7c673cae
FG
365 f->dump_int("type", d->type);
366
31f18b77
FG
367 if (d->type & PERFCOUNTER_COUNTER) {
368 f->dump_string("metric_type", "counter");
369 } else {
370 f->dump_string("metric_type", "gauge");
371 }
372
373 if (d->type & PERFCOUNTER_LONGRUNAVG) {
374 if (d->type & PERFCOUNTER_TIME) {
375 f->dump_string("value_type", "real-integer-pair");
376 } else {
377 f->dump_string("value_type", "integer-integer-pair");
378 }
379 } else if (d->type & PERFCOUNTER_HISTOGRAM) {
380 if (d->type & PERFCOUNTER_TIME) {
381 f->dump_string("value_type", "real-2d-histogram");
382 } else {
383 f->dump_string("value_type", "integer-2d-histogram");
384 }
7c673cae 385 } else {
31f18b77
FG
386 if (d->type & PERFCOUNTER_TIME) {
387 f->dump_string("value_type", "real");
388 } else {
389 f->dump_string("value_type", "integer");
390 }
7c673cae
FG
391 }
392
31f18b77 393 f->dump_string("description", d->description ? d->description : "");
7c673cae
FG
394 if (d->nick != NULL) {
395 f->dump_string("nick", d->nick);
396 } else {
397 f->dump_string("nick", "");
398 }
3efd9988 399 f->dump_int("priority", get_adjusted_priority(d->prio));
1adf2230
AA
400
401 if (d->unit == NONE) {
402 f->dump_string("units", "none");
403 } else if (d->unit == BYTES) {
404 f->dump_string("units", "bytes");
405 }
7c673cae
FG
406 f->close_section();
407 } else {
408 if (d->type & PERFCOUNTER_LONGRUNAVG) {
409 f->open_object_section(d->name);
410 pair<uint64_t,uint64_t> a = d->read_avg();
411 if (d->type & PERFCOUNTER_U64) {
412 f->dump_unsigned("avgcount", a.second);
413 f->dump_unsigned("sum", a.first);
414 } else if (d->type & PERFCOUNTER_TIME) {
415 f->dump_unsigned("avgcount", a.second);
416 f->dump_format_unquoted("sum", "%" PRId64 ".%09" PRId64,
417 a.first / 1000000000ull,
418 a.first % 1000000000ull);
31f18b77
FG
419 uint64_t count = a.second;
420 uint64_t sum_ns = a.first;
421 if (count) {
422 uint64_t avg_ns = sum_ns / count;
423 f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64,
424 avg_ns / 1000000000ull,
425 avg_ns % 1000000000ull);
426 } else {
427 f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64, 0, 0);
428 }
7c673cae
FG
429 } else {
430 ceph_abort();
431 }
432 f->close_section();
433 } else if (d->type & PERFCOUNTER_HISTOGRAM) {
31f18b77 434 assert(d->type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
7c673cae
FG
435 assert(d->histogram);
436 f->open_object_section(d->name);
437 d->histogram->dump_formatted(f);
438 f->close_section();
439 } else {
31f18b77 440 uint64_t v = d->u64;
7c673cae
FG
441 if (d->type & PERFCOUNTER_U64) {
442 f->dump_unsigned(d->name, v);
443 } else if (d->type & PERFCOUNTER_TIME) {
444 f->dump_format_unquoted(d->name, "%" PRId64 ".%09" PRId64,
445 v / 1000000000ull,
446 v % 1000000000ull);
447 } else {
448 ceph_abort();
449 }
450 }
451 }
452 }
453 f->close_section();
454}
455
456const std::string &PerfCounters::get_name() const
457{
458 return m_name;
459}
460
461PerfCounters::PerfCounters(CephContext *cct, const std::string &name,
462 int lower_bound, int upper_bound)
463 : m_cct(cct),
464 m_lower_bound(lower_bound),
465 m_upper_bound(upper_bound),
466 m_name(name.c_str()),
467 m_lock_name(std::string("PerfCounters::") + name.c_str()),
468 m_lock(m_lock_name.c_str())
469{
470 m_data.resize(upper_bound - lower_bound - 1);
471}
472
473PerfCountersBuilder::PerfCountersBuilder(CephContext *cct, const std::string &name,
474 int first, int last)
475 : m_perf_counters(new PerfCounters(cct, name, first, last))
476{
477}
478
479PerfCountersBuilder::~PerfCountersBuilder()
480{
481 if (m_perf_counters)
482 delete m_perf_counters;
483 m_perf_counters = NULL;
484}
485
486void PerfCountersBuilder::add_u64_counter(
487 int idx, const char *name,
1adf2230 488 const char *description, const char *nick, int prio, int unit)
7c673cae
FG
489{
490 add_impl(idx, name, description, nick, prio,
1adf2230 491 PERFCOUNTER_U64 | PERFCOUNTER_COUNTER, unit);
7c673cae
FG
492}
493
494void PerfCountersBuilder::add_u64(
495 int idx, const char *name,
1adf2230 496 const char *description, const char *nick, int prio, int unit)
7c673cae 497{
1adf2230 498 add_impl(idx, name, description, nick, prio, PERFCOUNTER_U64, unit);
7c673cae
FG
499}
500
501void PerfCountersBuilder::add_u64_avg(
502 int idx, const char *name,
1adf2230 503 const char *description, const char *nick, int prio, int unit)
7c673cae
FG
504{
505 add_impl(idx, name, description, nick, prio,
1adf2230 506 PERFCOUNTER_U64 | PERFCOUNTER_LONGRUNAVG, unit);
7c673cae
FG
507}
508
509void PerfCountersBuilder::add_time(
510 int idx, const char *name,
511 const char *description, const char *nick, int prio)
512{
513 add_impl(idx, name, description, nick, prio, PERFCOUNTER_TIME);
514}
515
516void PerfCountersBuilder::add_time_avg(
517 int idx, const char *name,
518 const char *description, const char *nick, int prio)
519{
520 add_impl(idx, name, description, nick, prio,
521 PERFCOUNTER_TIME | PERFCOUNTER_LONGRUNAVG);
522}
523
31f18b77 524void PerfCountersBuilder::add_u64_counter_histogram(
7c673cae
FG
525 int idx, const char *name,
526 PerfHistogramCommon::axis_config_d x_axis_config,
527 PerfHistogramCommon::axis_config_d y_axis_config,
1adf2230 528 const char *description, const char *nick, int prio, int unit)
7c673cae
FG
529{
530 add_impl(idx, name, description, nick, prio,
1adf2230 531 PERFCOUNTER_U64 | PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER, unit,
7c673cae
FG
532 unique_ptr<PerfHistogram<>>{new PerfHistogram<>{x_axis_config, y_axis_config}});
533}
534
535void PerfCountersBuilder::add_impl(
536 int idx, const char *name,
1adf2230 537 const char *description, const char *nick, int prio, int ty, int unit,
7c673cae
FG
538 unique_ptr<PerfHistogram<>> histogram)
539{
540 assert(idx > m_perf_counters->m_lower_bound);
541 assert(idx < m_perf_counters->m_upper_bound);
542 PerfCounters::perf_counter_data_vec_t &vec(m_perf_counters->m_data);
543 PerfCounters::perf_counter_data_any_d
544 &data(vec[idx - m_perf_counters->m_lower_bound - 1]);
545 assert(data.type == PERFCOUNTER_NONE);
546 data.name = name;
547 data.description = description;
548 // nick must be <= 4 chars
549 if (nick) {
550 assert(strlen(nick) <= 4);
551 }
552 data.nick = nick;
3efd9988 553 data.prio = prio ? prio : prio_default;
7c673cae 554 data.type = (enum perfcounter_type_d)ty;
1adf2230 555 data.unit = (enum unit_t) unit;
7c673cae
FG
556 data.histogram = std::move(histogram);
557}
558
559PerfCounters *PerfCountersBuilder::create_perf_counters()
560{
561 PerfCounters::perf_counter_data_vec_t::const_iterator d = m_perf_counters->m_data.begin();
562 PerfCounters::perf_counter_data_vec_t::const_iterator d_end = m_perf_counters->m_data.end();
31f18b77 563 for (; d != d_end; ++d) {
7c673cae 564 assert(d->type != PERFCOUNTER_NONE);
31f18b77
FG
565 assert(d->type & (PERFCOUNTER_U64 | PERFCOUNTER_TIME));
566 }
7c673cae
FG
567
568 PerfCounters *ret = m_perf_counters;
569 m_perf_counters = NULL;
570 return ret;
571}
572