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.
17 #ifndef CEPH_COMMON_PERF_COUNTERS_H
18 #define CEPH_COMMON_PERF_COUNTERS_H
26 #include "common/perf_histogram.h"
27 #include "include/utime.h"
28 #include "include/common_fwd.h"
29 #include "common/ceph_mutex.h"
30 #include "common/ceph_time.h"
32 namespace TOPNSPC::common
{
34 class PerfCountersBuilder
;
38 enum perfcounter_type_d
: uint8_t
41 PERFCOUNTER_TIME
= 0x1, // float (measuring seconds)
42 PERFCOUNTER_U64
= 0x2, // integer (note: either TIME or U64 *must* be set)
43 PERFCOUNTER_LONGRUNAVG
= 0x4, // paired counter + sum (time)
44 PERFCOUNTER_COUNTER
= 0x8, // counter (vs gauge)
45 PERFCOUNTER_HISTOGRAM
= 0x10, // histogram (vector) of values
54 /* Class for constructing a PerfCounters object.
56 * This class performs some validation that the parameters we have supplied are
57 * correct in create_perf_counters().
59 * In the future, we will probably get rid of the first/last arguments, since
60 * PerfCountersBuilder can deduce them itself.
62 namespace TOPNSPC::common
{
63 class PerfCountersBuilder
66 PerfCountersBuilder(CephContext
*cct
, const std::string
&name
,
68 ~PerfCountersBuilder();
70 // prio values: higher is better, and higher values get included in
71 // 'ceph daemonperf' (and similar) results.
72 // Use of priorities enables us to add large numbers of counters
73 // internally without necessarily overwhelming consumers.
76 // 'interesting' is the default threshold for `daemonperf` output
78 // `useful` is the default threshold for transmission to ceph-mgr
79 // and inclusion in prometheus/influxdb plugin output
81 PRIO_UNINTERESTING
= 2,
84 void add_u64(int key
, const char *name
,
85 const char *description
=NULL
, const char *nick
= NULL
,
86 int prio
=0, int unit
=UNIT_NONE
);
87 void add_u64_counter(int key
, const char *name
,
88 const char *description
=NULL
,
89 const char *nick
= NULL
,
90 int prio
=0, int unit
=UNIT_NONE
);
91 void add_u64_avg(int key
, const char *name
,
92 const char *description
=NULL
,
93 const char *nick
= NULL
,
94 int prio
=0, int unit
=UNIT_NONE
);
95 void add_time(int key
, const char *name
,
96 const char *description
=NULL
,
97 const char *nick
= NULL
,
99 void add_time_avg(int key
, const char *name
,
100 const char *description
=NULL
,
101 const char *nick
= NULL
,
103 void add_u64_counter_histogram(
104 int key
, const char* name
,
105 PerfHistogramCommon::axis_config_d x_axis_config
,
106 PerfHistogramCommon::axis_config_d y_axis_config
,
107 const char *description
=NULL
,
108 const char* nick
= NULL
,
109 int prio
=0, int unit
=UNIT_NONE
);
111 void set_prio_default(int prio_
)
113 prio_default
= prio_
;
116 PerfCounters
* create_perf_counters();
118 PerfCountersBuilder(const PerfCountersBuilder
&rhs
);
119 PerfCountersBuilder
& operator=(const PerfCountersBuilder
&rhs
);
120 void add_impl(int idx
, const char *name
,
121 const char *description
, const char *nick
, int prio
, int ty
, int unit
=UNIT_NONE
,
122 std::unique_ptr
<PerfHistogram
<>> histogram
= nullptr);
124 PerfCounters
*m_perf_counters
;
126 int prio_default
= 0;
130 * A PerfCounters object is usually associated with a single subsystem.
131 * It contains counters which we modify to track performance and throughput
134 * PerfCounters can track several different types of values:
135 * 1) integer values & counters
136 * 2) floating-point values & counters
137 * 3) floating-point averages
138 * 4) 2D histograms of quantized value pairs
140 * The difference between values, counters and histograms is in how they are initialized
141 * and accessed. For a counter, use the inc(counter, amount) function (note
142 * that amount defaults to 1 if you don't set it). For a value, use the
143 * set(index, value) function. For histogram use the hinc(value1, value2) function.
144 * (For time, use the tinc and tset variants.)
146 * If for some reason you would like to reset your counters, you can do so using
147 * the set functions even if they are counters, and you can also
148 * increment your values if for some reason you wish to.
150 * For the time average, it returns the current value and
151 * the "avgcount" member when read off. avgcount is incremented when you call
152 * tinc. Calling tset on an average is an error and will assert out.
157 /** Represents a PerfCounters data element. */
158 struct perf_counter_data_any_d
{
159 perf_counter_data_any_d()
163 type(PERFCOUNTER_NONE
),
166 perf_counter_data_any_d(const perf_counter_data_any_d
& other
)
168 description(other
.description
),
172 u64(other
.u64
.load()) {
173 auto a
= other
.read_avg();
176 avgcount2
= a
.second
;
177 if (other
.histogram
) {
178 histogram
.reset(new PerfHistogram
<>(*other
.histogram
));
183 const char *description
;
186 enum perfcounter_type_d type
;
188 std::atomic
<uint64_t> u64
= { 0 };
189 std::atomic
<uint64_t> avgcount
= { 0 };
190 std::atomic
<uint64_t> avgcount2
= { 0 };
191 std::unique_ptr
<PerfHistogram
<>> histogram
;
195 if (type
!= PERFCOUNTER_U64
) {
205 // read <sum, count> safely by making sure the post- and pre-count
206 // are identical; in other words the whole loop needs to be run
207 // without any intervening calls to inc, set, or tinc.
208 std::pair
<uint64_t,uint64_t> read_avg() const {
213 } while (avgcount
!= count
);
214 return { sum
, count
};
218 template <typename T
>
220 std::pair
<uint64_t, T
> last
;
221 std::pair
<uint64_t, T
> cur
;
222 avg_tracker() : last(0, 0), cur(0, 0) {}
223 T
current_avg() const {
224 if (cur
.first
== last
.first
)
226 return (cur
.second
- last
.second
) / (cur
.first
- last
.first
);
228 void consume_next(const std::pair
<uint64_t, T
> &next
) {
236 void inc(int idx
, uint64_t v
= 1);
237 void dec(int idx
, uint64_t v
= 1);
238 void set(int idx
, uint64_t v
);
239 uint64_t get(int idx
) const;
241 void tset(int idx
, utime_t v
);
242 void tinc(int idx
, utime_t v
);
243 void tinc(int idx
, ceph::timespan v
);
244 utime_t
tget(int idx
) const;
246 void hinc(int idx
, int64_t x
, int64_t y
);
249 void dump_formatted(ceph::Formatter
*f
, bool schema
,
250 const std::string
&counter
= "") const {
251 dump_formatted_generic(f
, schema
, false, counter
);
253 void dump_formatted_histograms(ceph::Formatter
*f
, bool schema
,
254 const std::string
&counter
= "") const {
255 dump_formatted_generic(f
, schema
, true, counter
);
257 std::pair
<uint64_t, uint64_t> get_tavg_ns(int idx
) const;
259 const std::string
& get_name() const;
260 void set_name(std::string s
) {
264 /// adjust priority values by some value
265 void set_prio_adjust(int p
) {
269 int get_adjusted_priority(int p
) const {
270 return std::max(std::min(p
+ prio_adjust
,
271 (int)PerfCountersBuilder::PRIO_CRITICAL
),
276 PerfCounters(CephContext
*cct
, const std::string
&name
,
277 int lower_bound
, int upper_bound
);
278 PerfCounters(const PerfCounters
&rhs
);
279 PerfCounters
& operator=(const PerfCounters
&rhs
);
280 void dump_formatted_generic(ceph::Formatter
*f
, bool schema
, bool histograms
,
281 const std::string
&counter
= "") const;
283 typedef std::vector
<perf_counter_data_any_d
> perf_counter_data_vec_t
;
292 #if !defined(WITH_SEASTAR) || defined(WITH_ALIEN)
293 const std::string m_lock_name
;
294 /** Protects m_data */
298 perf_counter_data_vec_t m_data
;
300 friend class PerfCountersBuilder
;
301 friend class PerfCountersCollectionImpl
;
304 class SortPerfCountersByName
{
306 bool operator()(const PerfCounters
* lhs
, const PerfCounters
* rhs
) const {
307 return (lhs
->get_name() < rhs
->get_name());
311 typedef std::set
<PerfCounters
*, SortPerfCountersByName
> perf_counters_set_t
;
314 * PerfCountersCollectionImp manages PerfCounters objects for a Ceph process.
316 class PerfCountersCollectionImpl
319 PerfCountersCollectionImpl();
320 ~PerfCountersCollectionImpl();
321 void add(PerfCounters
*l
);
322 void remove(PerfCounters
*l
);
324 bool reset(const std::string
&name
);
326 void dump_formatted(ceph::Formatter
*f
, bool schema
,
327 const std::string
&logger
= "",
328 const std::string
&counter
= "") const {
329 dump_formatted_generic(f
, schema
, false, logger
, counter
);
332 void dump_formatted_histograms(ceph::Formatter
*f
, bool schema
,
333 const std::string
&logger
= "",
334 const std::string
&counter
= "") const {
335 dump_formatted_generic(f
, schema
, true, logger
, counter
);
338 // A reference to a perf_counter_data_any_d, with an accompanying
339 // pointer to the enclosing PerfCounters, in order that the consumer
340 // can see the prio_adjust
344 PerfCounters::perf_counter_data_any_d
*data
;
345 PerfCounters
*perf_counters
;
347 typedef std::map
<std::string
,
348 PerfCounterRef
> CounterMap
;
350 void with_counters(std::function
<void(const CounterMap
&)>) const;
353 void dump_formatted_generic(ceph::Formatter
*f
, bool schema
, bool histograms
,
354 const std::string
&logger
= "",
355 const std::string
&counter
= "") const;
357 perf_counters_set_t m_loggers
;
364 const ceph::real_clock::time_point start
;
365 PerfCounters
* const counters
;
369 PerfGuard(PerfCounters
* const counters
,
371 : start(ceph::real_clock::now()),
377 counters
->tinc(event
, ceph::real_clock::now() - start
);