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