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