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