]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/perf_counters.h
update sources to 12.2.8
[ceph.git] / ceph / src / common / perf_counters.h
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
17 #ifndef CEPH_COMMON_PERF_COUNTERS_H
18 #define CEPH_COMMON_PERF_COUNTERS_H
19
20 #include <string>
21 #include <vector>
22 #include <memory>
23 #include <atomic>
24 #include <cstdint>
25
26 #include "common/perf_histogram.h"
27 #include "include/utime.h"
28 #include "common/Mutex.h"
29 #include "common/ceph_time.h"
30
31 class CephContext;
32 class PerfCountersBuilder;
33
34 enum perfcounter_type_d : uint8_t
35 {
36 PERFCOUNTER_NONE = 0,
37 PERFCOUNTER_TIME = 0x1, // float (measuring seconds)
38 PERFCOUNTER_U64 = 0x2, // integer (note: either TIME or U64 *must* be set)
39 PERFCOUNTER_LONGRUNAVG = 0x4, // paired counter + sum (time)
40 PERFCOUNTER_COUNTER = 0x8, // counter (vs guage)
41 PERFCOUNTER_HISTOGRAM = 0x10, // histogram (vector) of values
42 };
43
44 enum unit_t : uint8_t
45 {
46 BYTES,
47 NONE
48 };
49
50 /* Class for constructing a PerfCounters object.
51 *
52 * This class performs some validation that the parameters we have supplied are
53 * correct in create_perf_counters().
54 *
55 * In the future, we will probably get rid of the first/last arguments, since
56 * PerfCountersBuilder can deduce them itself.
57 */
58 class PerfCountersBuilder
59 {
60 public:
61 PerfCountersBuilder(CephContext *cct, const std::string &name,
62 int first, int last);
63 ~PerfCountersBuilder();
64
65 // prio values: higher is better, and higher values get included in
66 // 'ceph daemonperf' (and similar) results.
67 // Use of priorities enables us to add large numbers of counters
68 // internally without necessarily overwhelming consumers.
69 enum {
70 PRIO_CRITICAL = 10,
71 // 'interesting' is the default threshold for `daemonperf` output
72 PRIO_INTERESTING = 8,
73 // `useful` is the default threshold for transmission to ceph-mgr
74 // and inclusion in prometheus/influxdb plugin output
75 PRIO_USEFUL = 5,
76 PRIO_UNINTERESTING = 2,
77 PRIO_DEBUGONLY = 0,
78 };
79 void add_u64(int key, const char *name,
80 const char *description=NULL, const char *nick = NULL,
81 int prio=0, int unit=NONE);
82 void add_u64_counter(int key, const char *name,
83 const char *description=NULL,
84 const char *nick = NULL,
85 int prio=0, int unit=NONE);
86 void add_u64_avg(int key, const char *name,
87 const char *description=NULL,
88 const char *nick = NULL,
89 int prio=0, int unit=NONE);
90 void add_time(int key, const char *name,
91 const char *description=NULL,
92 const char *nick = NULL,
93 int prio=0);
94 void add_time_avg(int key, const char *name,
95 const char *description=NULL,
96 const char *nick = NULL,
97 int prio=0);
98 void add_u64_counter_histogram(
99 int key, const char* name,
100 PerfHistogramCommon::axis_config_d x_axis_config,
101 PerfHistogramCommon::axis_config_d y_axis_config,
102 const char *description=NULL,
103 const char* nick = NULL,
104 int prio=0, int unit=NONE);
105
106 void set_prio_default(int prio_)
107 {
108 prio_default = prio_;
109 }
110
111 PerfCounters* create_perf_counters();
112 private:
113 PerfCountersBuilder(const PerfCountersBuilder &rhs);
114 PerfCountersBuilder& operator=(const PerfCountersBuilder &rhs);
115 void add_impl(int idx, const char *name,
116 const char *description, const char *nick, int prio, int ty, int unit=NONE,
117 unique_ptr<PerfHistogram<>> histogram = nullptr);
118
119 PerfCounters *m_perf_counters;
120
121 int prio_default = 0;
122 };
123
124 /*
125 * A PerfCounters object is usually associated with a single subsystem.
126 * It contains counters which we modify to track performance and throughput
127 * over time.
128 *
129 * PerfCounters can track several different types of values:
130 * 1) integer values & counters
131 * 2) floating-point values & counters
132 * 3) floating-point averages
133 * 4) 2D histograms of quantized value pairs
134 *
135 * The difference between values, counters and histograms is in how they are initialized
136 * and accessed. For a counter, use the inc(counter, amount) function (note
137 * that amount defaults to 1 if you don't set it). For a value, use the
138 * set(index, value) function. For histogram use the hinc(value1, value2) function.
139 * (For time, use the tinc and tset variants.)
140 *
141 * If for some reason you would like to reset your counters, you can do so using
142 * the set functions even if they are counters, and you can also
143 * increment your values if for some reason you wish to.
144 *
145 * For the time average, it returns the current value and
146 * the "avgcount" member when read off. avgcount is incremented when you call
147 * tinc. Calling tset on an average is an error and will assert out.
148 */
149 class PerfCounters
150 {
151 public:
152 /** Represents a PerfCounters data element. */
153 struct perf_counter_data_any_d {
154 perf_counter_data_any_d()
155 : name(NULL),
156 description(NULL),
157 nick(NULL),
158 type(PERFCOUNTER_NONE),
159 unit(NONE)
160 {}
161 perf_counter_data_any_d(const perf_counter_data_any_d& other)
162 : name(other.name),
163 description(other.description),
164 nick(other.nick),
165 type(other.type),
166 unit(other.unit),
167 u64(other.u64.load()) {
168 pair<uint64_t,uint64_t> a = other.read_avg();
169 u64 = a.first;
170 avgcount = a.second;
171 avgcount2 = a.second;
172 if (other.histogram) {
173 histogram.reset(new PerfHistogram<>(*other.histogram));
174 }
175 }
176
177 const char *name;
178 const char *description;
179 const char *nick;
180 uint8_t prio = 0;
181 enum perfcounter_type_d type;
182 enum unit_t unit;
183 std::atomic<uint64_t> u64 = { 0 };
184 std::atomic<uint64_t> avgcount = { 0 };
185 std::atomic<uint64_t> avgcount2 = { 0 };
186 std::unique_ptr<PerfHistogram<>> histogram;
187
188 void reset()
189 {
190 if (type != PERFCOUNTER_U64) {
191 u64 = 0;
192 avgcount = 0;
193 avgcount2 = 0;
194 }
195 if (histogram) {
196 histogram->reset();
197 }
198 }
199
200 // read <sum, count> safely by making sure the post- and pre-count
201 // are identical; in other words the whole loop needs to be run
202 // without any intervening calls to inc, set, or tinc.
203 pair<uint64_t,uint64_t> read_avg() const {
204 uint64_t sum, count;
205 do {
206 count = avgcount;
207 sum = u64;
208 } while (avgcount2 != count);
209 return make_pair(sum, count);
210 }
211 };
212
213 template <typename T>
214 struct avg_tracker {
215 pair<uint64_t, T> last;
216 pair<uint64_t, T> cur;
217 avg_tracker() : last(0, 0), cur(0, 0) {}
218 T current_avg() const {
219 if (cur.first == last.first)
220 return 0;
221 return (cur.second - last.second) / (cur.first - last.first);
222 }
223 void consume_next(const pair<uint64_t, T> &next) {
224 last = cur;
225 cur = next;
226 }
227 };
228
229 ~PerfCounters();
230
231 void inc(int idx, uint64_t v = 1);
232 void dec(int idx, uint64_t v = 1);
233 void set(int idx, uint64_t v);
234 uint64_t get(int idx) const;
235
236 void tset(int idx, utime_t v);
237 void tinc(int idx, utime_t v, uint32_t avgcount = 1);
238 void tinc(int idx, ceph::timespan v, uint32_t avgcount = 1);
239 utime_t tget(int idx) const;
240
241 void hinc(int idx, int64_t x, int64_t y);
242
243 void reset();
244 void dump_formatted(ceph::Formatter *f, bool schema,
245 const std::string &counter = "") {
246 dump_formatted_generic(f, schema, false, counter);
247 }
248 void dump_formatted_histograms(ceph::Formatter *f, bool schema,
249 const std::string &counter = "") {
250 dump_formatted_generic(f, schema, true, counter);
251 }
252 pair<uint64_t, uint64_t> get_tavg_ms(int idx) const;
253
254 const std::string& get_name() const;
255 void set_name(std::string s) {
256 m_name = s;
257 }
258
259 /// adjust priority values by some value
260 void set_prio_adjust(int p) {
261 prio_adjust = p;
262 }
263
264 int get_adjusted_priority(int p) const {
265 return std::max(std::min(p + prio_adjust,
266 (int)PerfCountersBuilder::PRIO_CRITICAL),
267 0);
268 }
269
270 private:
271 PerfCounters(CephContext *cct, const std::string &name,
272 int lower_bound, int upper_bound);
273 PerfCounters(const PerfCounters &rhs);
274 PerfCounters& operator=(const PerfCounters &rhs);
275 void dump_formatted_generic(ceph::Formatter *f, bool schema, bool histograms,
276 const std::string &counter = "");
277
278 typedef std::vector<perf_counter_data_any_d> perf_counter_data_vec_t;
279
280 CephContext *m_cct;
281 int m_lower_bound;
282 int m_upper_bound;
283 std::string m_name;
284 const std::string m_lock_name;
285
286 int prio_adjust = 0;
287
288 /** Protects m_data */
289 mutable Mutex m_lock;
290
291 perf_counter_data_vec_t m_data;
292
293 friend class PerfCountersBuilder;
294 friend class PerfCountersCollection;
295 };
296
297 class SortPerfCountersByName {
298 public:
299 bool operator()(const PerfCounters* lhs, const PerfCounters* rhs) const {
300 return (lhs->get_name() < rhs->get_name());
301 }
302 };
303
304 typedef std::set <PerfCounters*, SortPerfCountersByName> perf_counters_set_t;
305
306 /*
307 * PerfCountersCollection manages PerfCounters objects for a Ceph process.
308 */
309 class PerfCountersCollection
310 {
311 public:
312 PerfCountersCollection(CephContext *cct);
313 ~PerfCountersCollection();
314 void add(class PerfCounters *l);
315 void remove(class PerfCounters *l);
316 void clear();
317 bool reset(const std::string &name);
318
319 void dump_formatted(ceph::Formatter *f, bool schema,
320 const std::string &logger = "",
321 const std::string &counter = "") {
322 dump_formatted_generic(f, schema, false, logger, counter);
323 }
324
325 void dump_formatted_histograms(ceph::Formatter *f, bool schema,
326 const std::string &logger = "",
327 const std::string &counter = "") {
328 dump_formatted_generic(f, schema, true, logger, counter);
329 }
330
331 // A reference to a perf_counter_data_any_d, with an accompanying
332 // pointer to the enclosing PerfCounters, in order that the consumer
333 // can see the prio_adjust
334 class PerfCounterRef
335 {
336 public:
337 PerfCounters::perf_counter_data_any_d *data;
338 PerfCounters *perf_counters;
339 };
340 typedef std::map<std::string,
341 PerfCounterRef> CounterMap;
342
343 void with_counters(std::function<void(const CounterMap &)>) const;
344
345 private:
346 void dump_formatted_generic(ceph::Formatter *f, bool schema, bool histograms,
347 const std::string &logger = "",
348 const std::string &counter = "");
349
350 CephContext *m_cct;
351
352 /** Protects m_loggers */
353 mutable Mutex m_lock;
354
355 perf_counters_set_t m_loggers;
356
357 CounterMap by_path;
358
359 friend class PerfCountersCollectionTest;
360 };
361
362
363
364 #endif