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