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
;
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", "");
400 int p
= std::max(std::min(d
->prio
+ prio_adjust
,
401 (int)PerfCountersBuilder::PRIO_CRITICAL
),
403 f
->dump_int("priority", p
);
407 if (d
->type
& PERFCOUNTER_LONGRUNAVG
) {
408 f
->open_object_section(d
->name
);
409 pair
<uint64_t,uint64_t> a
= d
->read_avg();
410 if (d
->type
& PERFCOUNTER_U64
) {
411 f
->dump_unsigned("avgcount", a
.second
);
412 f
->dump_unsigned("sum", a
.first
);
413 } else if (d
->type
& PERFCOUNTER_TIME
) {
414 f
->dump_unsigned("avgcount", a
.second
);
415 f
->dump_format_unquoted("sum", "%" PRId64
".%09" PRId64
,
416 a
.first
/ 1000000000ull,
417 a
.first
% 1000000000ull);
418 uint64_t count
= a
.second
;
419 uint64_t sum_ns
= a
.first
;
421 uint64_t avg_ns
= sum_ns
/ count
;
422 f
->dump_format_unquoted("avgtime", "%" PRId64
".%09" PRId64
,
423 avg_ns
/ 1000000000ull,
424 avg_ns
% 1000000000ull);
426 f
->dump_format_unquoted("avgtime", "%" PRId64
".%09" PRId64
, 0, 0);
432 } else if (d
->type
& PERFCOUNTER_HISTOGRAM
) {
433 assert(d
->type
== (PERFCOUNTER_HISTOGRAM
| PERFCOUNTER_COUNTER
| PERFCOUNTER_U64
));
434 assert(d
->histogram
);
435 f
->open_object_section(d
->name
);
436 d
->histogram
->dump_formatted(f
);
440 if (d
->type
& PERFCOUNTER_U64
) {
441 f
->dump_unsigned(d
->name
, v
);
442 } else if (d
->type
& PERFCOUNTER_TIME
) {
443 f
->dump_format_unquoted(d
->name
, "%" PRId64
".%09" PRId64
,
455 const std::string
&PerfCounters::get_name() const
460 PerfCounters::PerfCounters(CephContext
*cct
, const std::string
&name
,
461 int lower_bound
, int upper_bound
)
463 m_lower_bound(lower_bound
),
464 m_upper_bound(upper_bound
),
465 m_name(name
.c_str()),
466 m_lock_name(std::string("PerfCounters::") + name
.c_str()),
467 m_lock(m_lock_name
.c_str())
469 m_data
.resize(upper_bound
- lower_bound
- 1);
472 PerfCountersBuilder::PerfCountersBuilder(CephContext
*cct
, const std::string
&name
,
474 : m_perf_counters(new PerfCounters(cct
, name
, first
, last
))
478 PerfCountersBuilder::~PerfCountersBuilder()
481 delete m_perf_counters
;
482 m_perf_counters
= NULL
;
485 void PerfCountersBuilder::add_u64_counter(
486 int idx
, const char *name
,
487 const char *description
, const char *nick
, int prio
)
489 add_impl(idx
, name
, description
, nick
, prio
,
490 PERFCOUNTER_U64
| PERFCOUNTER_COUNTER
);
493 void PerfCountersBuilder::add_u64(
494 int idx
, const char *name
,
495 const char *description
, const char *nick
, int prio
)
497 add_impl(idx
, name
, description
, nick
, prio
, PERFCOUNTER_U64
);
500 void PerfCountersBuilder::add_u64_avg(
501 int idx
, const char *name
,
502 const char *description
, const char *nick
, int prio
)
504 add_impl(idx
, name
, description
, nick
, prio
,
505 PERFCOUNTER_U64
| PERFCOUNTER_LONGRUNAVG
);
508 void PerfCountersBuilder::add_time(
509 int idx
, const char *name
,
510 const char *description
, const char *nick
, int prio
)
512 add_impl(idx
, name
, description
, nick
, prio
, PERFCOUNTER_TIME
);
515 void PerfCountersBuilder::add_time_avg(
516 int idx
, const char *name
,
517 const char *description
, const char *nick
, int prio
)
519 add_impl(idx
, name
, description
, nick
, prio
,
520 PERFCOUNTER_TIME
| PERFCOUNTER_LONGRUNAVG
);
523 void PerfCountersBuilder::add_u64_counter_histogram(
524 int idx
, const char *name
,
525 PerfHistogramCommon::axis_config_d x_axis_config
,
526 PerfHistogramCommon::axis_config_d y_axis_config
,
527 const char *description
, const char *nick
, int prio
)
529 add_impl(idx
, name
, description
, nick
, prio
,
530 PERFCOUNTER_U64
| PERFCOUNTER_HISTOGRAM
| PERFCOUNTER_COUNTER
,
531 unique_ptr
<PerfHistogram
<>>{new PerfHistogram
<>{x_axis_config
, y_axis_config
}});
534 void PerfCountersBuilder::add_impl(
535 int idx
, const char *name
,
536 const char *description
, const char *nick
, int prio
, int ty
,
537 unique_ptr
<PerfHistogram
<>> histogram
)
539 assert(idx
> m_perf_counters
->m_lower_bound
);
540 assert(idx
< m_perf_counters
->m_upper_bound
);
541 PerfCounters::perf_counter_data_vec_t
&vec(m_perf_counters
->m_data
);
542 PerfCounters::perf_counter_data_any_d
543 &data(vec
[idx
- m_perf_counters
->m_lower_bound
- 1]);
544 assert(data
.type
== PERFCOUNTER_NONE
);
546 data
.description
= description
;
547 // nick must be <= 4 chars
549 assert(strlen(nick
) <= 4);
553 data
.type
= (enum perfcounter_type_d
)ty
;
554 data
.histogram
= std::move(histogram
);
557 PerfCounters
*PerfCountersBuilder::create_perf_counters()
559 PerfCounters::perf_counter_data_vec_t::const_iterator d
= m_perf_counters
->m_data
.begin();
560 PerfCounters::perf_counter_data_vec_t::const_iterator d_end
= m_perf_counters
->m_data
.end();
561 for (; d
!= d_end
; ++d
) {
562 assert(d
->type
!= PERFCOUNTER_NONE
);
563 assert(d
->type
& (PERFCOUNTER_U64
| PERFCOUNTER_TIME
));
566 PerfCounters
*ret
= m_perf_counters
;
567 m_perf_counters
= NULL
;