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