1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2011 New Dream Network
7 * Copyright (C) 2017 OVH
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.
17 #ifndef CEPH_COMMON_PERF_COUNTERS_H
18 #define CEPH_COMMON_PERF_COUNTERS_H
26 #include "common/perf_histogram.h"
27 #include "include/utime.h"
28 #include "common/Mutex.h"
29 #include "common/ceph_time.h"
32 class PerfCountersBuilder;
34 enum perfcounter_type_d : uint8_t
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
45 /* Class for constructing a PerfCounters object.
47 * This class performs some validation that the parameters we have supplied are
48 * correct in create_perf_counters().
50 * In the future, we will probably get rid of the first/last arguments, since
51 * PerfCountersBuilder can deduce them itself.
53 class PerfCountersBuilder
56 PerfCountersBuilder(CephContext *cct, const std::string &name,
58 ~PerfCountersBuilder();
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.
66 // 'interesting' is the default threshold for `daemonperf` output
68 // `useful` is the default threshold for transmission to ceph-mgr
69 // and inclusion in prometheus/influxdb plugin output
71 PRIO_UNINTERESTING = 2,
74 void add_u64(int key, const char *name,
75 const char *description=NULL, const char *nick = NULL,
77 void add_u64_counter(int key, const char *name,
78 const char *description=NULL,
79 const char *nick = NULL,
81 void add_u64_avg(int key, const char *name,
82 const char *description=NULL,
83 const char *nick = NULL,
85 void add_time(int key, const char *name,
86 const char *description=NULL,
87 const char *nick = NULL,
89 void add_time_avg(int key, const char *name,
90 const char *description=NULL,
91 const char *nick = NULL,
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,
101 void set_prio_default(int prio_)
103 prio_default = prio_;
106 PerfCounters* create_perf_counters();
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);
114 PerfCounters *m_perf_counters;
116 int prio_default = 0;
120 * A PerfCounters object is usually associated with a single subsystem.
121 * It contains counters which we modify to track performance and throughput
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
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.)
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.
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.
147 /** Represents a PerfCounters data element. */
148 struct perf_counter_data_any_d {
149 perf_counter_data_any_d()
153 type(PERFCOUNTER_NONE)
155 perf_counter_data_any_d(const perf_counter_data_any_d& other)
157 description(other.description),
160 u64(other.u64.load()) {
161 pair<uint64_t,uint64_t> a = other.read_avg();
164 avgcount2 = a.second;
165 if (other.histogram) {
166 histogram.reset(new PerfHistogram<>(*other.histogram));
171 const char *description;
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;
182 if (type != PERFCOUNTER_U64) {
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 {
200 } while (avgcount2 != count);
201 return make_pair(sum, count);
205 template <typename T>
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)
213 return (cur.second - last.second) / (cur.first - last.first);
215 void consume_next(const pair<uint64_t, T> &next) {
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;
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;
233 void hinc(int idx, int64_t x, int64_t y);
236 void dump_formatted(ceph::Formatter *f, bool schema,
237 const std::string &counter = "") {
238 dump_formatted_generic(f, schema, false, counter);
240 void dump_formatted_histograms(ceph::Formatter *f, bool schema,
241 const std::string &counter = "") {
242 dump_formatted_generic(f, schema, true, counter);
244 pair<uint64_t, uint64_t> get_tavg_ms(int idx) const;
246 const std::string& get_name() const;
247 void set_name(std::string s) {
251 /// adjust priority values by some value
252 void set_prio_adjust(int p) {
256 int get_adjusted_priority(int p) const {
257 return std::max(std::min(p + prio_adjust,
258 (int)PerfCountersBuilder::PRIO_CRITICAL),
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 = "");
270 typedef std::vector<perf_counter_data_any_d> perf_counter_data_vec_t;
276 const std::string m_lock_name;
280 /** Protects m_data */
281 mutable Mutex m_lock;
283 perf_counter_data_vec_t m_data;
285 friend class PerfCountersBuilder;
286 friend class PerfCountersCollection;
289 class SortPerfCountersByName {
291 bool operator()(const PerfCounters* lhs, const PerfCounters* rhs) const {
292 return (lhs->get_name() < rhs->get_name());
296 typedef std::set <PerfCounters*, SortPerfCountersByName> perf_counters_set_t;
299 * PerfCountersCollection manages PerfCounters objects for a Ceph process.
301 class PerfCountersCollection
304 PerfCountersCollection(CephContext *cct);
305 ~PerfCountersCollection();
306 void add(class PerfCounters *l);
307 void remove(class PerfCounters *l);
309 bool reset(const std::string &name);
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);
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);
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
329 PerfCounters::perf_counter_data_any_d *data;
330 PerfCounters *perf_counters;
332 typedef std::map<std::string,
333 PerfCounterRef> CounterMap;
335 void with_counters(std::function<void(const CounterMap &)>) const;
338 void dump_formatted_generic(ceph::Formatter *f, bool schema, bool histograms,
339 const std::string &logger = "",
340 const std::string &counter = "");
344 /** Protects m_loggers */
345 mutable Mutex m_lock;
347 perf_counters_set_t m_loggers;
351 friend class PerfCountersCollectionTest;