]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/perf_counters.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / common / perf_counters.cc
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
16 #include "common/perf_counters.h"
17 #include "common/dout.h"
18 #include "common/valgrind.h"
19
20 using std::ostringstream;
21
22 PerfCountersCollectionImpl::PerfCountersCollectionImpl()
23 {
24 }
25
26 PerfCountersCollectionImpl::~PerfCountersCollectionImpl()
27 {
28 clear();
29 }
30
31 void PerfCountersCollectionImpl::add(PerfCounters *l)
32 {
33 // make sure the name is unique
34 perf_counters_set_t::iterator i;
35 i = m_loggers.find(l);
36 while (i != m_loggers.end()) {
37 ostringstream ss;
38 ss << l->get_name() << "-" << (void*)l;
39 l->set_name(ss.str());
40 i = m_loggers.find(l);
41 }
42
43 m_loggers.insert(l);
44
45 for (unsigned int i = 0; i < l->m_data.size(); ++i) {
46 PerfCounters::perf_counter_data_any_d &data = l->m_data[i];
47
48 std::string path = l->get_name();
49 path += ".";
50 path += data.name;
51
52 by_path[path] = {&data, l};
53 }
54 }
55
56 void PerfCountersCollectionImpl::remove(PerfCounters *l)
57 {
58 for (unsigned int i = 0; i < l->m_data.size(); ++i) {
59 PerfCounters::perf_counter_data_any_d &data = l->m_data[i];
60
61 std::string path = l->get_name();
62 path += ".";
63 path += data.name;
64
65 by_path.erase(path);
66 }
67
68 perf_counters_set_t::iterator i = m_loggers.find(l);
69 ceph_assert(i != m_loggers.end());
70 m_loggers.erase(i);
71 }
72
73 void PerfCountersCollectionImpl::clear()
74 {
75 perf_counters_set_t::iterator i = m_loggers.begin();
76 perf_counters_set_t::iterator i_end = m_loggers.end();
77 for (; i != i_end; ) {
78 delete *i;
79 m_loggers.erase(i++);
80 }
81
82 by_path.clear();
83 }
84
85 bool PerfCountersCollectionImpl::reset(const std::string &name)
86 {
87 bool result = false;
88 perf_counters_set_t::iterator i = m_loggers.begin();
89 perf_counters_set_t::iterator i_end = m_loggers.end();
90
91 if (!strcmp(name.c_str(), "all")) {
92 while (i != i_end) {
93 (*i)->reset();
94 ++i;
95 }
96 result = true;
97 } else {
98 while (i != i_end) {
99 if (!name.compare((*i)->get_name())) {
100 (*i)->reset();
101 result = true;
102 break;
103 }
104 ++i;
105 }
106 }
107
108 return result;
109 }
110
111
112 /**
113 * Serialize current values of performance counters. Optionally
114 * output the schema instead, or filter output to a particular
115 * PerfCounters or particular named counter.
116 *
117 * @param logger name of subsystem logger, e.g. "mds_cache", may be empty
118 * @param counter name of counter within subsystem, e.g. "num_strays",
119 * may be empty.
120 * @param schema if true, output schema instead of current data.
121 * @param histograms if true, dump histogram values,
122 * if false dump all non-histogram counters
123 */
124 void PerfCountersCollectionImpl::dump_formatted_generic(
125 Formatter *f,
126 bool schema,
127 bool histograms,
128 const std::string &logger,
129 const std::string &counter)
130 {
131 f->open_object_section("perfcounter_collection");
132
133 for (perf_counters_set_t::iterator l = m_loggers.begin();
134 l != m_loggers.end(); ++l) {
135 // Optionally filter on logger name, pass through counter filter
136 if (logger.empty() || (*l)->get_name() == logger) {
137 (*l)->dump_formatted_generic(f, schema, histograms, counter);
138 }
139 }
140 f->close_section();
141 }
142
143 void PerfCountersCollectionImpl::with_counters(std::function<void(
144 const PerfCountersCollectionImpl::CounterMap &)> fn) const
145 {
146 fn(by_path);
147 }
148
149 // ---------------------------
150
151 PerfCounters::~PerfCounters()
152 {
153 }
154
155 void PerfCounters::inc(int idx, uint64_t amt)
156 {
157 #ifndef WITH_SEASTAR
158 if (!m_cct->_conf->perf)
159 return;
160 #endif
161
162 ceph_assert(idx > m_lower_bound);
163 ceph_assert(idx < m_upper_bound);
164 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
165 if (!(data.type & PERFCOUNTER_U64))
166 return;
167 if (data.type & PERFCOUNTER_LONGRUNAVG) {
168 data.avgcount++;
169 data.u64 += amt;
170 data.avgcount2++;
171 } else {
172 data.u64 += amt;
173 }
174 }
175
176 void PerfCounters::dec(int idx, uint64_t amt)
177 {
178 #ifndef WITH_SEASTAR
179 if (!m_cct->_conf->perf)
180 return;
181 #endif
182
183 ceph_assert(idx > m_lower_bound);
184 ceph_assert(idx < m_upper_bound);
185 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
186 ceph_assert(!(data.type & PERFCOUNTER_LONGRUNAVG));
187 if (!(data.type & PERFCOUNTER_U64))
188 return;
189 data.u64 -= amt;
190 }
191
192 void PerfCounters::set(int idx, uint64_t amt)
193 {
194 #ifndef WITH_SEASTAR
195 if (!m_cct->_conf->perf)
196 return;
197 #endif
198
199 ceph_assert(idx > m_lower_bound);
200 ceph_assert(idx < m_upper_bound);
201 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
202 if (!(data.type & PERFCOUNTER_U64))
203 return;
204
205 ANNOTATE_BENIGN_RACE_SIZED(&data.u64, sizeof(data.u64),
206 "perf counter atomic");
207 if (data.type & PERFCOUNTER_LONGRUNAVG) {
208 data.avgcount++;
209 data.u64 = amt;
210 data.avgcount2++;
211 } else {
212 data.u64 = amt;
213 }
214 }
215
216 uint64_t PerfCounters::get(int idx) const
217 {
218 #ifndef WITH_SEASTAR
219 if (!m_cct->_conf->perf)
220 return 0;
221 #endif
222
223 ceph_assert(idx > m_lower_bound);
224 ceph_assert(idx < m_upper_bound);
225 const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
226 if (!(data.type & PERFCOUNTER_U64))
227 return 0;
228 return data.u64;
229 }
230
231 void PerfCounters::tinc(int idx, utime_t amt)
232 {
233 #ifndef WITH_SEASTAR
234 if (!m_cct->_conf->perf)
235 return;
236 #endif
237
238 ceph_assert(idx > m_lower_bound);
239 ceph_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) {
244 data.avgcount++;
245 data.u64 += amt.to_nsec();
246 data.avgcount2++;
247 } else {
248 data.u64 += amt.to_nsec();
249 }
250 }
251
252 void PerfCounters::tinc(int idx, ceph::timespan amt)
253 {
254 #ifndef WITH_SEASTAR
255 if (!m_cct->_conf->perf)
256 return;
257 #endif
258
259 ceph_assert(idx > m_lower_bound);
260 ceph_assert(idx < m_upper_bound);
261 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
262 if (!(data.type & PERFCOUNTER_TIME))
263 return;
264 if (data.type & PERFCOUNTER_LONGRUNAVG) {
265 data.avgcount++;
266 data.u64 += amt.count();
267 data.avgcount2++;
268 } else {
269 data.u64 += amt.count();
270 }
271 }
272
273 void PerfCounters::tset(int idx, utime_t amt)
274 {
275 #ifndef WITH_SEASTAR
276 if (!m_cct->_conf->perf)
277 return;
278 #endif
279
280 ceph_assert(idx > m_lower_bound);
281 ceph_assert(idx < m_upper_bound);
282 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
283 if (!(data.type & PERFCOUNTER_TIME))
284 return;
285 data.u64 = amt.to_nsec();
286 if (data.type & PERFCOUNTER_LONGRUNAVG)
287 ceph_abort();
288 }
289
290 utime_t PerfCounters::tget(int idx) const
291 {
292 #ifndef WITH_SEASTAR
293 if (!m_cct->_conf->perf)
294 return utime_t();
295 #endif
296
297 ceph_assert(idx > m_lower_bound);
298 ceph_assert(idx < m_upper_bound);
299 const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
300 if (!(data.type & PERFCOUNTER_TIME))
301 return utime_t();
302 uint64_t v = data.u64;
303 return utime_t(v / 1000000000ull, v % 1000000000ull);
304 }
305
306 void PerfCounters::hinc(int idx, int64_t x, int64_t y)
307 {
308 #ifndef WITH_SEASTAR
309 if (!m_cct->_conf->perf)
310 return;
311 #endif
312
313 ceph_assert(idx > m_lower_bound);
314 ceph_assert(idx < m_upper_bound);
315
316 perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
317 ceph_assert(data.type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
318 ceph_assert(data.histogram);
319
320 data.histogram->inc(x, y);
321 }
322
323 pair<uint64_t, uint64_t> PerfCounters::get_tavg_ns(int idx) const
324 {
325 #ifndef WITH_SEASTAR
326 if (!m_cct->_conf->perf)
327 return make_pair(0, 0);
328 #endif
329
330 ceph_assert(idx > m_lower_bound);
331 ceph_assert(idx < m_upper_bound);
332 const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
333 if (!(data.type & PERFCOUNTER_TIME))
334 return make_pair(0, 0);
335 if (!(data.type & PERFCOUNTER_LONGRUNAVG))
336 return make_pair(0, 0);
337 pair<uint64_t,uint64_t> a = data.read_avg();
338 return make_pair(a.second, a.first);
339 }
340
341 void PerfCounters::reset()
342 {
343 perf_counter_data_vec_t::iterator d = m_data.begin();
344 perf_counter_data_vec_t::iterator d_end = m_data.end();
345
346 while (d != d_end) {
347 d->reset();
348 ++d;
349 }
350 }
351
352 void PerfCounters::dump_formatted_generic(Formatter *f, bool schema,
353 bool histograms, const std::string &counter)
354 {
355 f->open_object_section(m_name.c_str());
356
357 for (perf_counter_data_vec_t::const_iterator d = m_data.begin();
358 d != m_data.end(); ++d) {
359 if (!counter.empty() && counter != d->name) {
360 // Optionally filter on counter name
361 continue;
362 }
363
364 // Switch between normal and histogram view
365 bool is_histogram = (d->type & PERFCOUNTER_HISTOGRAM) != 0;
366 if (is_histogram != histograms) {
367 continue;
368 }
369
370 if (schema) {
371 f->open_object_section(d->name);
372 // we probably should not have exposed this raw field (with bit
373 // values), but existing plugins rely on it so we're stuck with
374 // it.
375 f->dump_int("type", d->type);
376
377 if (d->type & PERFCOUNTER_COUNTER) {
378 f->dump_string("metric_type", "counter");
379 } else {
380 f->dump_string("metric_type", "gauge");
381 }
382
383 if (d->type & PERFCOUNTER_LONGRUNAVG) {
384 if (d->type & PERFCOUNTER_TIME) {
385 f->dump_string("value_type", "real-integer-pair");
386 } else {
387 f->dump_string("value_type", "integer-integer-pair");
388 }
389 } else if (d->type & PERFCOUNTER_HISTOGRAM) {
390 if (d->type & PERFCOUNTER_TIME) {
391 f->dump_string("value_type", "real-2d-histogram");
392 } else {
393 f->dump_string("value_type", "integer-2d-histogram");
394 }
395 } else {
396 if (d->type & PERFCOUNTER_TIME) {
397 f->dump_string("value_type", "real");
398 } else {
399 f->dump_string("value_type", "integer");
400 }
401 }
402
403 f->dump_string("description", d->description ? d->description : "");
404 if (d->nick != NULL) {
405 f->dump_string("nick", d->nick);
406 } else {
407 f->dump_string("nick", "");
408 }
409 f->dump_int("priority", get_adjusted_priority(d->prio));
410
411 if (d->unit == UNIT_NONE) {
412 f->dump_string("units", "none");
413 } else if (d->unit == UNIT_BYTES) {
414 f->dump_string("units", "bytes");
415 }
416 f->close_section();
417 } else {
418 if (d->type & PERFCOUNTER_LONGRUNAVG) {
419 f->open_object_section(d->name);
420 pair<uint64_t,uint64_t> a = d->read_avg();
421 if (d->type & PERFCOUNTER_U64) {
422 f->dump_unsigned("avgcount", a.second);
423 f->dump_unsigned("sum", a.first);
424 } else if (d->type & PERFCOUNTER_TIME) {
425 f->dump_unsigned("avgcount", a.second);
426 f->dump_format_unquoted("sum", "%" PRId64 ".%09" PRId64,
427 a.first / 1000000000ull,
428 a.first % 1000000000ull);
429 uint64_t count = a.second;
430 uint64_t sum_ns = a.first;
431 if (count) {
432 uint64_t avg_ns = sum_ns / count;
433 f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64,
434 avg_ns / 1000000000ull,
435 avg_ns % 1000000000ull);
436 } else {
437 f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64, 0, 0);
438 }
439 } else {
440 ceph_abort();
441 }
442 f->close_section();
443 } else if (d->type & PERFCOUNTER_HISTOGRAM) {
444 ceph_assert(d->type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
445 ceph_assert(d->histogram);
446 f->open_object_section(d->name);
447 d->histogram->dump_formatted(f);
448 f->close_section();
449 } else {
450 uint64_t v = d->u64;
451 if (d->type & PERFCOUNTER_U64) {
452 f->dump_unsigned(d->name, v);
453 } else if (d->type & PERFCOUNTER_TIME) {
454 f->dump_format_unquoted(d->name, "%" PRId64 ".%09" PRId64,
455 v / 1000000000ull,
456 v % 1000000000ull);
457 } else {
458 ceph_abort();
459 }
460 }
461 }
462 }
463 f->close_section();
464 }
465
466 const std::string &PerfCounters::get_name() const
467 {
468 return m_name;
469 }
470
471 PerfCounters::PerfCounters(CephContext *cct, const std::string &name,
472 int lower_bound, int upper_bound)
473 : m_cct(cct),
474 m_lower_bound(lower_bound),
475 m_upper_bound(upper_bound),
476 m_name(name)
477 #ifndef WITH_SEASTAR
478 ,
479 m_lock_name(std::string("PerfCounters::") + name.c_str()),
480 m_lock(ceph::make_mutex(m_lock_name))
481 #endif
482 {
483 m_data.resize(upper_bound - lower_bound - 1);
484 }
485
486 PerfCountersBuilder::PerfCountersBuilder(CephContext *cct, const std::string &name,
487 int first, int last)
488 : m_perf_counters(new PerfCounters(cct, name, first, last))
489 {
490 }
491
492 PerfCountersBuilder::~PerfCountersBuilder()
493 {
494 if (m_perf_counters)
495 delete m_perf_counters;
496 m_perf_counters = NULL;
497 }
498
499 void PerfCountersBuilder::add_u64_counter(
500 int idx, const char *name,
501 const char *description, const char *nick, int prio, int unit)
502 {
503 add_impl(idx, name, description, nick, prio,
504 PERFCOUNTER_U64 | PERFCOUNTER_COUNTER, unit);
505 }
506
507 void PerfCountersBuilder::add_u64(
508 int idx, const char *name,
509 const char *description, const char *nick, int prio, int unit)
510 {
511 add_impl(idx, name, description, nick, prio, PERFCOUNTER_U64, unit);
512 }
513
514 void PerfCountersBuilder::add_u64_avg(
515 int idx, const char *name,
516 const char *description, const char *nick, int prio, int unit)
517 {
518 add_impl(idx, name, description, nick, prio,
519 PERFCOUNTER_U64 | PERFCOUNTER_LONGRUNAVG, unit);
520 }
521
522 void PerfCountersBuilder::add_time(
523 int idx, const char *name,
524 const char *description, const char *nick, int prio)
525 {
526 add_impl(idx, name, description, nick, prio, PERFCOUNTER_TIME);
527 }
528
529 void PerfCountersBuilder::add_time_avg(
530 int idx, const char *name,
531 const char *description, const char *nick, int prio)
532 {
533 add_impl(idx, name, description, nick, prio,
534 PERFCOUNTER_TIME | PERFCOUNTER_LONGRUNAVG);
535 }
536
537 void PerfCountersBuilder::add_u64_counter_histogram(
538 int idx, const char *name,
539 PerfHistogramCommon::axis_config_d x_axis_config,
540 PerfHistogramCommon::axis_config_d y_axis_config,
541 const char *description, const char *nick, int prio, int unit)
542 {
543 add_impl(idx, name, description, nick, prio,
544 PERFCOUNTER_U64 | PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER, unit,
545 unique_ptr<PerfHistogram<>>{new PerfHistogram<>{x_axis_config, y_axis_config}});
546 }
547
548 void PerfCountersBuilder::add_impl(
549 int idx, const char *name,
550 const char *description, const char *nick, int prio, int ty, int unit,
551 unique_ptr<PerfHistogram<>> histogram)
552 {
553 ceph_assert(idx > m_perf_counters->m_lower_bound);
554 ceph_assert(idx < m_perf_counters->m_upper_bound);
555 PerfCounters::perf_counter_data_vec_t &vec(m_perf_counters->m_data);
556 PerfCounters::perf_counter_data_any_d
557 &data(vec[idx - m_perf_counters->m_lower_bound - 1]);
558 ceph_assert(data.type == PERFCOUNTER_NONE);
559 data.name = name;
560 data.description = description;
561 // nick must be <= 4 chars
562 if (nick) {
563 ceph_assert(strlen(nick) <= 4);
564 }
565 data.nick = nick;
566 data.prio = prio ? prio : prio_default;
567 data.type = (enum perfcounter_type_d)ty;
568 data.unit = (enum unit_t) unit;
569 data.histogram = std::move(histogram);
570 }
571
572 PerfCounters *PerfCountersBuilder::create_perf_counters()
573 {
574 PerfCounters::perf_counter_data_vec_t::const_iterator d = m_perf_counters->m_data.begin();
575 PerfCounters::perf_counter_data_vec_t::const_iterator d_end = m_perf_counters->m_data.end();
576 for (; d != d_end; ++d) {
577 ceph_assert(d->type != PERFCOUNTER_NONE);
578 ceph_assert(d->type & (PERFCOUNTER_U64 | PERFCOUNTER_TIME));
579 }
580
581 PerfCounters *ret = m_perf_counters;
582 m_perf_counters = NULL;
583 return ret;
584 }
585