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 PerfCountersCollectionImpl::PerfCountersCollectionImpl()
26 PerfCountersCollectionImpl::~PerfCountersCollectionImpl()
31 void PerfCountersCollectionImpl::add(PerfCounters
*l
)
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()) {
38 ss
<< l
->get_name() << "-" << (void*)l
;
39 l
->set_name(ss
.str());
40 i
= m_loggers
.find(l
);
45 for (unsigned int i
= 0; i
< l
->m_data
.size(); ++i
) {
46 PerfCounters::perf_counter_data_any_d
&data
= l
->m_data
[i
];
48 std::string path
= l
->get_name();
52 by_path
[path
] = {&data
, l
};
56 void PerfCountersCollectionImpl::remove(PerfCounters
*l
)
58 for (unsigned int i
= 0; i
< l
->m_data
.size(); ++i
) {
59 PerfCounters::perf_counter_data_any_d
&data
= l
->m_data
[i
];
61 std::string path
= l
->get_name();
68 perf_counters_set_t::iterator i
= m_loggers
.find(l
);
69 ceph_assert(i
!= m_loggers
.end());
73 void PerfCountersCollectionImpl::clear()
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
; ) {
85 bool PerfCountersCollectionImpl::reset(const std::string
&name
)
88 perf_counters_set_t::iterator i
= m_loggers
.begin();
89 perf_counters_set_t::iterator i_end
= m_loggers
.end();
91 if (!strcmp(name
.c_str(), "all")) {
99 if (!name
.compare((*i
)->get_name())) {
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.
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",
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
124 void PerfCountersCollectionImpl::dump_formatted_generic(
128 const std::string
&logger
,
129 const std::string
&counter
)
131 f
->open_object_section("perfcounter_collection");
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
);
143 void PerfCountersCollectionImpl::with_counters(std::function
<void(
144 const PerfCountersCollectionImpl::CounterMap
&)> fn
) const
149 // ---------------------------
151 PerfCounters::~PerfCounters()
155 void PerfCounters::inc(int idx
, uint64_t amt
)
158 if (!m_cct
->_conf
->perf
)
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
))
167 if (data
.type
& PERFCOUNTER_LONGRUNAVG
) {
176 void PerfCounters::dec(int idx
, uint64_t amt
)
179 if (!m_cct
->_conf
->perf
)
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
))
192 void PerfCounters::set(int idx
, uint64_t amt
)
195 if (!m_cct
->_conf
->perf
)
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
))
205 ANNOTATE_BENIGN_RACE_SIZED(&data
.u64
, sizeof(data
.u64
),
206 "perf counter atomic");
207 if (data
.type
& PERFCOUNTER_LONGRUNAVG
) {
216 uint64_t PerfCounters::get(int idx
) const
219 if (!m_cct
->_conf
->perf
)
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
))
231 void PerfCounters::tinc(int idx
, utime_t amt
)
234 if (!m_cct
->_conf
->perf
)
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
))
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
)
255 if (!m_cct
->_conf
->perf
)
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
))
264 if (data
.type
& PERFCOUNTER_LONGRUNAVG
) {
266 data
.u64
+= amt
.count();
269 data
.u64
+= amt
.count();
273 void PerfCounters::tset(int idx
, utime_t amt
)
276 if (!m_cct
->_conf
->perf
)
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
))
285 data
.u64
= amt
.to_nsec();
286 if (data
.type
& PERFCOUNTER_LONGRUNAVG
)
290 utime_t
PerfCounters::tget(int idx
) const
293 if (!m_cct
->_conf
->perf
)
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
))
302 uint64_t v
= data
.u64
;
303 return utime_t(v
/ 1000000000ull, v
% 1000000000ull);
306 void PerfCounters::hinc(int idx
, int64_t x
, int64_t y
)
309 if (!m_cct
->_conf
->perf
)
313 ceph_assert(idx
> m_lower_bound
);
314 ceph_assert(idx
< m_upper_bound
);
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
);
320 data
.histogram
->inc(x
, y
);
323 pair
<uint64_t, uint64_t> PerfCounters::get_tavg_ns(int idx
) const
326 if (!m_cct
->_conf
->perf
)
327 return make_pair(0, 0);
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
);
341 void PerfCounters::reset()
343 perf_counter_data_vec_t::iterator d
= m_data
.begin();
344 perf_counter_data_vec_t::iterator d_end
= m_data
.end();
352 void PerfCounters::dump_formatted_generic(Formatter
*f
, bool schema
,
353 bool histograms
, const std::string
&counter
)
355 f
->open_object_section(m_name
.c_str());
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
364 // Switch between normal and histogram view
365 bool is_histogram
= (d
->type
& PERFCOUNTER_HISTOGRAM
) != 0;
366 if (is_histogram
!= histograms
) {
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
375 f
->dump_int("type", d
->type
);
377 if (d
->type
& PERFCOUNTER_COUNTER
) {
378 f
->dump_string("metric_type", "counter");
380 f
->dump_string("metric_type", "gauge");
383 if (d
->type
& PERFCOUNTER_LONGRUNAVG
) {
384 if (d
->type
& PERFCOUNTER_TIME
) {
385 f
->dump_string("value_type", "real-integer-pair");
387 f
->dump_string("value_type", "integer-integer-pair");
389 } else if (d
->type
& PERFCOUNTER_HISTOGRAM
) {
390 if (d
->type
& PERFCOUNTER_TIME
) {
391 f
->dump_string("value_type", "real-2d-histogram");
393 f
->dump_string("value_type", "integer-2d-histogram");
396 if (d
->type
& PERFCOUNTER_TIME
) {
397 f
->dump_string("value_type", "real");
399 f
->dump_string("value_type", "integer");
403 f
->dump_string("description", d
->description
? d
->description
: "");
404 if (d
->nick
!= NULL
) {
405 f
->dump_string("nick", d
->nick
);
407 f
->dump_string("nick", "");
409 f
->dump_int("priority", get_adjusted_priority(d
->prio
));
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");
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
;
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);
437 f
->dump_format_unquoted("avgtime", "%" PRId64
".%09" PRId64
, 0, 0);
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
);
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
,
466 const std::string
&PerfCounters::get_name() const
471 PerfCounters::PerfCounters(CephContext
*cct
, const std::string
&name
,
472 int lower_bound
, int upper_bound
)
474 m_lower_bound(lower_bound
),
475 m_upper_bound(upper_bound
),
479 m_lock_name(std::string("PerfCounters::") + name
.c_str()),
480 m_lock(ceph::make_mutex(m_lock_name
))
483 m_data
.resize(upper_bound
- lower_bound
- 1);
486 PerfCountersBuilder::PerfCountersBuilder(CephContext
*cct
, const std::string
&name
,
488 : m_perf_counters(new PerfCounters(cct
, name
, first
, last
))
492 PerfCountersBuilder::~PerfCountersBuilder()
495 delete m_perf_counters
;
496 m_perf_counters
= NULL
;
499 void PerfCountersBuilder::add_u64_counter(
500 int idx
, const char *name
,
501 const char *description
, const char *nick
, int prio
, int unit
)
503 add_impl(idx
, name
, description
, nick
, prio
,
504 PERFCOUNTER_U64
| PERFCOUNTER_COUNTER
, unit
);
507 void PerfCountersBuilder::add_u64(
508 int idx
, const char *name
,
509 const char *description
, const char *nick
, int prio
, int unit
)
511 add_impl(idx
, name
, description
, nick
, prio
, PERFCOUNTER_U64
, unit
);
514 void PerfCountersBuilder::add_u64_avg(
515 int idx
, const char *name
,
516 const char *description
, const char *nick
, int prio
, int unit
)
518 add_impl(idx
, name
, description
, nick
, prio
,
519 PERFCOUNTER_U64
| PERFCOUNTER_LONGRUNAVG
, unit
);
522 void PerfCountersBuilder::add_time(
523 int idx
, const char *name
,
524 const char *description
, const char *nick
, int prio
)
526 add_impl(idx
, name
, description
, nick
, prio
, PERFCOUNTER_TIME
);
529 void PerfCountersBuilder::add_time_avg(
530 int idx
, const char *name
,
531 const char *description
, const char *nick
, int prio
)
533 add_impl(idx
, name
, description
, nick
, prio
,
534 PERFCOUNTER_TIME
| PERFCOUNTER_LONGRUNAVG
);
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
)
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
}});
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
)
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
);
560 data
.description
= description
;
561 // nick must be <= 4 chars
563 ceph_assert(strlen(nick
) <= 4);
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
);
572 PerfCounters
*PerfCountersBuilder::create_perf_counters()
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
));
581 PerfCounters
*ret
= m_perf_counters
;
582 m_perf_counters
= NULL
;