Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / common / perf_counters.cc
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 #include "common/perf_counters.h"
17 #include "common/dout.h"
18 #include "common/valgrind.h"
19
20 using std::ostringstream;
21
22 PerfCountersCollection::PerfCountersCollection(CephContext *cct)
23   : m_cct(cct),
24     m_lock("PerfCountersCollection")
25 {
26 }
27
28 PerfCountersCollection::~PerfCountersCollection()
29 {
30   clear();
31 }
32
33 void PerfCountersCollection::add(class PerfCounters *l)
34 {
35   Mutex::Locker lck(m_lock);
36
37   // make sure the name is unique
38   perf_counters_set_t::iterator i;
39   i = m_loggers.find(l);
40   while (i != m_loggers.end()) {
41     ostringstream ss;
42     ss << l->get_name() << "-" << (void*)l;
43     l->set_name(ss.str());
44     i = m_loggers.find(l);
45   }
46
47   m_loggers.insert(l);
48
49   for (unsigned int i = 0; i < l->m_data.size(); ++i) {
50     PerfCounters::perf_counter_data_any_d &data = l->m_data[i];
51
52     std::string path = l->get_name();
53     path += ".";
54     path += data.name;
55
56     by_path[path] = {&data, l};
57   }
58 }
59
60 void PerfCountersCollection::remove(class PerfCounters *l)
61 {
62   Mutex::Locker lck(m_lock);
63
64   for (unsigned int i = 0; i < l->m_data.size(); ++i) {
65     PerfCounters::perf_counter_data_any_d &data = l->m_data[i];
66
67     std::string path = l->get_name();
68     path += ".";
69     path += data.name;
70
71     by_path.erase(path);
72   }
73
74   perf_counters_set_t::iterator i = m_loggers.find(l);
75   assert(i != m_loggers.end());
76   m_loggers.erase(i);
77 }
78
79 void PerfCountersCollection::clear()
80 {
81   Mutex::Locker lck(m_lock);
82   perf_counters_set_t::iterator i = m_loggers.begin();
83   perf_counters_set_t::iterator i_end = m_loggers.end();
84   for (; i != i_end; ) {
85     m_loggers.erase(i++);
86   }
87
88   by_path.clear();
89 }
90
91 bool PerfCountersCollection::reset(const std::string &name)
92 {
93   bool result = false;
94   Mutex::Locker lck(m_lock);
95   perf_counters_set_t::iterator i = m_loggers.begin();
96   perf_counters_set_t::iterator i_end = m_loggers.end();
97
98   if (!strcmp(name.c_str(), "all"))  {
99     while (i != i_end) {
100       (*i)->reset();
101       ++i;
102     }
103     result = true;
104   } else {
105     while (i != i_end) {
106       if (!name.compare((*i)->get_name())) {
107         (*i)->reset();
108         result = true;
109         break;
110       }
111       ++i;
112     }
113   }
114
115   return result;
116 }
117
118
119 /**
120  * Serialize current values of performance counters.  Optionally
121  * output the schema instead, or filter output to a particular
122  * PerfCounters or particular named counter.
123  *
124  * @param logger name of subsystem logger, e.g. "mds_cache", may be empty
125  * @param counter name of counter within subsystem, e.g. "num_strays",
126  *                may be empty.
127  * @param schema if true, output schema instead of current data.
128  * @param histograms if true, dump histogram values,
129  *                   if false dump all non-histogram counters
130  */
131 void PerfCountersCollection::dump_formatted_generic(
132     Formatter *f,
133     bool schema,
134     bool histograms,
135     const std::string &logger,
136     const std::string &counter)
137 {
138   Mutex::Locker lck(m_lock);
139   f->open_object_section("perfcounter_collection");
140   
141   for (perf_counters_set_t::iterator l = m_loggers.begin();
142        l != m_loggers.end(); ++l) {
143     // Optionally filter on logger name, pass through counter filter
144     if (logger.empty() || (*l)->get_name() == logger) {
145       (*l)->dump_formatted_generic(f, schema, histograms, counter);
146     }
147   }
148   f->close_section();
149 }
150
151 void PerfCountersCollection::with_counters(std::function<void(
152       const PerfCountersCollection::CounterMap &)> fn) const
153 {
154   Mutex::Locker lck(m_lock);
155
156   fn(by_path);
157 }
158
159 // ---------------------------
160
161 PerfCounters::~PerfCounters()
162 {
163 }
164
165 void PerfCounters::inc(int idx, uint64_t amt)
166 {
167   if (!m_cct->_conf->perf)
168     return;
169
170   assert(idx > m_lower_bound);
171   assert(idx < m_upper_bound);
172   perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
173   if (!(data.type & PERFCOUNTER_U64))
174     return;
175   if (data.type & PERFCOUNTER_LONGRUNAVG) {
176     data.avgcount++;
177     data.u64 += amt;
178     data.avgcount2++;
179   } else {
180     data.u64 += amt;
181   }
182 }
183
184 void PerfCounters::dec(int idx, uint64_t amt)
185 {
186   if (!m_cct->_conf->perf)
187     return;
188
189   assert(idx > m_lower_bound);
190   assert(idx < m_upper_bound);
191   perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
192   assert(!(data.type & PERFCOUNTER_LONGRUNAVG));
193   if (!(data.type & PERFCOUNTER_U64))
194     return;
195   data.u64 -= amt;
196 }
197
198 void PerfCounters::set(int idx, uint64_t amt)
199 {
200   if (!m_cct->_conf->perf)
201     return;
202
203   assert(idx > m_lower_bound);
204   assert(idx < m_upper_bound);
205   perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
206   if (!(data.type & PERFCOUNTER_U64))
207     return;
208
209   ANNOTATE_BENIGN_RACE_SIZED(&data.u64, sizeof(data.u64),
210                              "perf counter atomic");
211   if (data.type & PERFCOUNTER_LONGRUNAVG) {
212     data.avgcount++;
213     data.u64 = amt;
214     data.avgcount2++;
215   } else {
216     data.u64 = amt;
217   }
218 }
219
220 uint64_t PerfCounters::get(int idx) const
221 {
222   if (!m_cct->_conf->perf)
223     return 0;
224
225   assert(idx > m_lower_bound);
226   assert(idx < m_upper_bound);
227   const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
228   if (!(data.type & PERFCOUNTER_U64))
229     return 0;
230   return data.u64;
231 }
232
233 void PerfCounters::tinc(int idx, utime_t amt, uint32_t avgcount)
234 {
235   if (!m_cct->_conf->perf)
236     return;
237
238   assert(idx > m_lower_bound);
239   assert(idx < m_upper_bound);
240   perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
241   if (!(data.type & PERFCOUNTER_TIME))
242     return;
243   if (data.type & PERFCOUNTER_LONGRUNAVG) {
244     data.avgcount++;
245     data.u64 += amt.to_nsec();
246     data.avgcount2++;
247   } else {
248     data.u64 += amt.to_nsec();
249   }
250 }
251
252 void PerfCounters::tinc(int idx, ceph::timespan amt, uint32_t avgcount)
253 {
254   if (!m_cct->_conf->perf)
255     return;
256
257   assert(idx > m_lower_bound);
258   assert(idx < m_upper_bound);
259   perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
260   if (!(data.type & PERFCOUNTER_TIME))
261     return;
262   if (data.type & PERFCOUNTER_LONGRUNAVG) {
263     data.avgcount++;
264     data.u64 += amt.count();
265     data.avgcount2++;
266   } else {
267     data.u64 += amt.count();
268   }
269 }
270
271 void PerfCounters::tset(int idx, utime_t amt)
272 {
273   if (!m_cct->_conf->perf)
274     return;
275
276   assert(idx > m_lower_bound);
277   assert(idx < m_upper_bound);
278   perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
279   if (!(data.type & PERFCOUNTER_TIME))
280     return;
281   data.u64 = amt.to_nsec();
282   if (data.type & PERFCOUNTER_LONGRUNAVG)
283     ceph_abort();
284 }
285
286 utime_t PerfCounters::tget(int idx) const
287 {
288   if (!m_cct->_conf->perf)
289     return utime_t();
290
291   assert(idx > m_lower_bound);
292   assert(idx < m_upper_bound);
293   const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
294   if (!(data.type & PERFCOUNTER_TIME))
295     return utime_t();
296   uint64_t v = data.u64;
297   return utime_t(v / 1000000000ull, v % 1000000000ull);
298 }
299
300 void PerfCounters::hinc(int idx, int64_t x, int64_t y)
301 {
302   if (!m_cct->_conf->perf)
303     return;
304
305   assert(idx > m_lower_bound);
306   assert(idx < m_upper_bound);
307
308   perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
309   assert(data.type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
310   assert(data.histogram);
311
312   data.histogram->inc(x, y);
313 }
314
315 pair<uint64_t, uint64_t> PerfCounters::get_tavg_ms(int idx) const
316 {
317   if (!m_cct->_conf->perf)
318     return make_pair(0, 0);
319
320   assert(idx > m_lower_bound);
321   assert(idx < m_upper_bound);
322   const perf_counter_data_any_d& data(m_data[idx - m_lower_bound - 1]);
323   if (!(data.type & PERFCOUNTER_TIME))
324     return make_pair(0, 0);
325   if (!(data.type & PERFCOUNTER_LONGRUNAVG))
326     return make_pair(0, 0);
327   pair<uint64_t,uint64_t> a = data.read_avg();
328   return make_pair(a.second, a.first / 1000000ull);
329 }
330
331 void PerfCounters::reset()
332 {
333   perf_counter_data_vec_t::iterator d = m_data.begin();
334   perf_counter_data_vec_t::iterator d_end = m_data.end();
335
336   while (d != d_end) {
337     d->reset();
338     ++d;
339   }
340 }
341
342 void PerfCounters::dump_formatted_generic(Formatter *f, bool schema,
343     bool histograms, const std::string &counter)
344 {
345   f->open_object_section(m_name.c_str());
346   
347   for (perf_counter_data_vec_t::const_iterator d = m_data.begin();
348        d != m_data.end(); ++d) {
349     if (!counter.empty() && counter != d->name) {
350       // Optionally filter on counter name
351       continue;
352     }
353
354     // Switch between normal and histogram view
355     bool is_histogram = (d->type & PERFCOUNTER_HISTOGRAM) != 0;
356     if (is_histogram != histograms) {
357       continue;
358     }
359
360     if (schema) {
361       f->open_object_section(d->name);
362       // we probably should not have exposed this raw field (with bit
363       // values), but existing plugins rely on it so we're stuck with
364       // it.
365       f->dump_int("type", d->type);
366
367       if (d->type & PERFCOUNTER_COUNTER) {
368         f->dump_string("metric_type", "counter");
369       } else {
370         f->dump_string("metric_type", "gauge");
371       }
372
373       if (d->type & PERFCOUNTER_LONGRUNAVG) {
374         if (d->type & PERFCOUNTER_TIME) {
375           f->dump_string("value_type", "real-integer-pair");
376         } else {
377           f->dump_string("value_type", "integer-integer-pair");
378         }
379       } else if (d->type & PERFCOUNTER_HISTOGRAM) {
380         if (d->type & PERFCOUNTER_TIME) {
381           f->dump_string("value_type", "real-2d-histogram");
382         } else {
383           f->dump_string("value_type", "integer-2d-histogram");
384         }
385       } else {
386         if (d->type & PERFCOUNTER_TIME) {
387           f->dump_string("value_type", "real");
388         } else {
389           f->dump_string("value_type", "integer");
390         }
391       }
392
393       f->dump_string("description", d->description ? d->description : "");
394       if (d->nick != NULL) {
395         f->dump_string("nick", d->nick);
396       } else {
397         f->dump_string("nick", "");
398       }
399       f->dump_int("priority", get_adjusted_priority(d->prio));
400       f->close_section();
401     } else {
402       if (d->type & PERFCOUNTER_LONGRUNAVG) {
403         f->open_object_section(d->name);
404         pair<uint64_t,uint64_t> a = d->read_avg();
405         if (d->type & PERFCOUNTER_U64) {
406           f->dump_unsigned("avgcount", a.second);
407           f->dump_unsigned("sum", a.first);
408         } else if (d->type & PERFCOUNTER_TIME) {
409           f->dump_unsigned("avgcount", a.second);
410           f->dump_format_unquoted("sum", "%" PRId64 ".%09" PRId64,
411                                   a.first / 1000000000ull,
412                                   a.first % 1000000000ull);
413           uint64_t count = a.second;
414           uint64_t sum_ns = a.first;
415           if (count) {
416             uint64_t avg_ns = sum_ns / count;
417             f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64,
418                                     avg_ns / 1000000000ull,
419                                     avg_ns % 1000000000ull);
420           } else {
421             f->dump_format_unquoted("avgtime", "%" PRId64 ".%09" PRId64, 0, 0);
422           }
423         } else {
424           ceph_abort();
425         }
426         f->close_section();
427       } else if (d->type & PERFCOUNTER_HISTOGRAM) {
428         assert(d->type == (PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER | PERFCOUNTER_U64));
429         assert(d->histogram);
430         f->open_object_section(d->name);
431         d->histogram->dump_formatted(f);
432         f->close_section();
433       } else {
434         uint64_t v = d->u64;
435         if (d->type & PERFCOUNTER_U64) {
436           f->dump_unsigned(d->name, v);
437         } else if (d->type & PERFCOUNTER_TIME) {
438           f->dump_format_unquoted(d->name, "%" PRId64 ".%09" PRId64,
439                                   v / 1000000000ull,
440                                   v % 1000000000ull);
441         } else {
442           ceph_abort();
443         }
444       }
445     }
446   }
447   f->close_section();
448 }
449
450 const std::string &PerfCounters::get_name() const
451 {
452   return m_name;
453 }
454
455 PerfCounters::PerfCounters(CephContext *cct, const std::string &name,
456            int lower_bound, int upper_bound)
457   : m_cct(cct),
458     m_lower_bound(lower_bound),
459     m_upper_bound(upper_bound),
460     m_name(name.c_str()),
461     m_lock_name(std::string("PerfCounters::") + name.c_str()),
462     m_lock(m_lock_name.c_str())
463 {
464   m_data.resize(upper_bound - lower_bound - 1);
465 }
466
467 PerfCountersBuilder::PerfCountersBuilder(CephContext *cct, const std::string &name,
468                   int first, int last)
469   : m_perf_counters(new PerfCounters(cct, name, first, last))
470 {
471 }
472
473 PerfCountersBuilder::~PerfCountersBuilder()
474 {
475   if (m_perf_counters)
476     delete m_perf_counters;
477   m_perf_counters = NULL;
478 }
479
480 void PerfCountersBuilder::add_u64_counter(
481   int idx, const char *name,
482   const char *description, const char *nick, int prio)
483 {
484   add_impl(idx, name, description, nick, prio,
485            PERFCOUNTER_U64 | PERFCOUNTER_COUNTER);
486 }
487
488 void PerfCountersBuilder::add_u64(
489   int idx, const char *name,
490   const char *description, const char *nick, int prio)
491 {
492   add_impl(idx, name, description, nick, prio, PERFCOUNTER_U64);
493 }
494
495 void PerfCountersBuilder::add_u64_avg(
496   int idx, const char *name,
497   const char *description, const char *nick, int prio)
498 {
499   add_impl(idx, name, description, nick, prio,
500            PERFCOUNTER_U64 | PERFCOUNTER_LONGRUNAVG);
501 }
502
503 void PerfCountersBuilder::add_time(
504   int idx, const char *name,
505   const char *description, const char *nick, int prio)
506 {
507   add_impl(idx, name, description, nick, prio, PERFCOUNTER_TIME);
508 }
509
510 void PerfCountersBuilder::add_time_avg(
511   int idx, const char *name,
512   const char *description, const char *nick, int prio)
513 {
514   add_impl(idx, name, description, nick, prio,
515            PERFCOUNTER_TIME | PERFCOUNTER_LONGRUNAVG);
516 }
517
518 void PerfCountersBuilder::add_u64_counter_histogram(
519   int idx, const char *name,
520   PerfHistogramCommon::axis_config_d x_axis_config,
521   PerfHistogramCommon::axis_config_d y_axis_config,
522   const char *description, const char *nick, int prio)
523 {
524   add_impl(idx, name, description, nick, prio,
525            PERFCOUNTER_U64 | PERFCOUNTER_HISTOGRAM | PERFCOUNTER_COUNTER,
526            unique_ptr<PerfHistogram<>>{new PerfHistogram<>{x_axis_config, y_axis_config}});
527 }
528
529 void PerfCountersBuilder::add_impl(
530   int idx, const char *name,
531   const char *description, const char *nick, int prio, int ty,
532   unique_ptr<PerfHistogram<>> histogram)
533 {
534   assert(idx > m_perf_counters->m_lower_bound);
535   assert(idx < m_perf_counters->m_upper_bound);
536   PerfCounters::perf_counter_data_vec_t &vec(m_perf_counters->m_data);
537   PerfCounters::perf_counter_data_any_d
538     &data(vec[idx - m_perf_counters->m_lower_bound - 1]);
539   assert(data.type == PERFCOUNTER_NONE);
540   data.name = name;
541   data.description = description;
542   // nick must be <= 4 chars
543   if (nick) {
544     assert(strlen(nick) <= 4);
545   }
546   data.nick = nick;
547   data.prio = prio ? prio : prio_default;
548   data.type = (enum perfcounter_type_d)ty;
549   data.histogram = std::move(histogram);
550 }
551
552 PerfCounters *PerfCountersBuilder::create_perf_counters()
553 {
554   PerfCounters::perf_counter_data_vec_t::const_iterator d = m_perf_counters->m_data.begin();
555   PerfCounters::perf_counter_data_vec_t::const_iterator d_end = m_perf_counters->m_data.end();
556   for (; d != d_end; ++d) {
557     assert(d->type != PERFCOUNTER_NONE);
558     assert(d->type & (PERFCOUNTER_U64 | PERFCOUNTER_TIME));
559   }
560
561   PerfCounters *ret = m_perf_counters;
562   m_perf_counters = NULL;
563   return ret;
564 }
565