Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 /* 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  */
53 class PerfCountersBuilder
54 {
55 public:
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();
107 private:
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
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  */
144 class PerfCounters
145 {
146 public:
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),
153             type(PERFCOUNTER_NONE)
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),
160         u64(other.u64.load()) {
161       pair<uint64_t,uint64_t> a = other.read_avg();
162       u64 = a.first;
163       avgcount = a.second;
164       avgcount2 = a.second;
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;
173     uint8_t prio = 0;
174     enum perfcounter_type_d type;
175     std::atomic<uint64_t> u64 = { 0 };
176     std::atomic<uint64_t> avgcount = { 0 };
177     std::atomic<uint64_t> avgcount2 = { 0 };
178     std::unique_ptr<PerfHistogram<>> histogram;
179
180     void reset()
181     {
182       if (type != PERFCOUNTER_U64) {
183             u64 = 0;
184             avgcount = 0;
185             avgcount2 = 0;
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 {
198         count = avgcount;
199         sum = u64;
200       } while (avgcount2 != count);
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) {}
210     T current_avg() const {
211       if (cur.first == last.first)
212         return 0;
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
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
262 private:
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
289 class SortPerfCountersByName {
290 public:
291   bool operator()(const PerfCounters* lhs, const PerfCounters* rhs) const {
292     return (lhs->get_name() < rhs->get_name());
293   }
294 };
295
296 typedef std::set <PerfCounters*, SortPerfCountersByName> perf_counters_set_t;
297
298 /*
299  * PerfCountersCollection manages PerfCounters objects for a Ceph process.
300  */
301 class PerfCountersCollection
302 {
303 public:
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
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   };
332   typedef std::map<std::string,
333           PerfCounterRef> CounterMap;
334
335   void with_counters(std::function<void(const CounterMap &)>) const;
336
337 private:
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
349   CounterMap by_path; 
350
351   friend class PerfCountersCollectionTest;
352 };
353
354
355
356 #endif