GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/util/statistics_registry.h Lines: 31 32 96.9 %
Date: 2021-05-22 Branches: 55 188 29.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Gereon Kremer
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * Central statistics registry.
14
 *
15
 * The StatisticsRegistry that issues statistic proxy objects.
16
 */
17
18
/**
19
 * On the design of the statistics:
20
 *
21
 * Stat is the abstract base class for all statistic values.
22
 * It stores the name and provides (fully virtual) methods
23
 * flushInformation() and safeFlushInformation().
24
 *
25
 * BackedStat is an abstract templated base class for statistic values
26
 * that store the data themselves. It takes care of printing them already
27
 * and derived classes usually only need to provide methods to set the
28
 * value.
29
 *
30
 * ReferenceStat holds a reference (conceptually, it is implemented as a
31
 * const pointer) to some data that is stored outside of the statistic.
32
 *
33
 * IntStat is a BackedStat<std::int64_t>.
34
 *
35
 * SizeStat holds a const reference to some container and provides the
36
 * size of this container.
37
 *
38
 * AverageStat is a BackedStat<double>.
39
 *
40
 * HistogramStat counts instances of some type T. It is implemented as a
41
 * std::map<T, std::uint64_t>.
42
 *
43
 * IntegralHistogramStat is a (conceptual) specialization of HistogramStat
44
 * for types that are (convertible to) integral. This allows to use a
45
 * std::vector<std::uint64_t> instead of a std::map.
46
 *
47
 * TimerStat uses std::chrono to collect timing information. It is
48
 * implemented as BackedStat<std::chrono::duration> and provides methods
49
 * start() and stop(), accumulating times it was activated. It provides
50
 * the convenience class CodeTimer to allow for RAII-style usage.
51
 *
52
 *
53
 * All statistic classes should protect their custom methods using
54
 *   if (CVC5_USE_STATISTICS) { ... }
55
 * Output methods (flushInformation() and safeFlushInformation()) are only
56
 * called when statistics are enabled and need no protection.
57
 *
58
 *
59
 * The statistic classes try to implement a consistent interface:
60
 * - if we store some generic data, we implement set()
61
 * - if we (conceptually) store a set of values, we implement operator<<()
62
 * - if there are standard operations for the stored data, we implement these
63
 *   (like operator++() or operator+=())
64
 */
65
66
#include "cvc5_private_library.h"
67
68
#ifndef CVC5__STATISTICS_REGISTRY_H
69
#define CVC5__STATISTICS_REGISTRY_H
70
71
#include <iostream>
72
#include <map>
73
#include <memory>
74
#include <typeinfo>
75
76
#include "base/check.h"
77
#include "util/statistics_stats.h"
78
#include "util/statistics_value.h"
79
80
namespace cvc5 {
81
82
struct StatisticBaseValue;
83
84
/**
85
 * The central registry for statistics.
86
 * Internally stores statistic data objects and issues corresponding proxy
87
 * objects to modules that want to expose statistics.
88
 * Provides registration methods (e.g. `registerAverage` or
89
 * `registerHistogram<T>`) that return the proxy object.
90
 * The different statistics are explained in more detail in statistics_stats.h
91
 *
92
 * Every statistic is identified by a name. If a statistic with the given
93
 * name is already registered, the registry issues another proxy object
94
 * for that name using the same data it already holds for this name.
95
 * While this makes perfect sense for most statistic types, it may lead to
96
 * unexpected (though not undefined) behaviour for others. For a reference
97
 * statistic, for example, the internal data will simply point to the object
98
 * registered last.
99
 * Note that the type of the re-registered statistic must always match
100
 * the type of the previously registered statistic with the same name.
101
 *
102
 * We generally distinguish between public (non-expert) and private (expert)
103
 * statistics. By default, `--stats` only shows public statistics. Private
104
 * ones are printed as well if `--all-statistics` is set.
105
 * All registration methods have a trailing argument `expert`, defaulting to
106
 * true.
107
 *
108
 * If statistics are disabled entirely (i.e. the cmake option
109
 * `ENABLE_STATISTICS` is not set), the registry still issues proxy objects
110
 * that can be used normally.
111
 * However, no data is stored in the registry and the modification functions
112
 * of the proxy objects do nothing.
113
 */
114
10095
class StatisticsRegistry
115
{
116
 public:
117
  friend std::ostream& operator<<(std::ostream& os,
118
                                  const StatisticsRegistry& sr);
119
120
  using Snapshot = std::map<std::string, StatExportData>;
121
122
  /**
123
   * If `registerPublic` is true, all statistics that are public are
124
   * pre-registered as such. This argument mostly exists so that unit tests
125
   * can disable this pre-registration.
126
   */
127
  StatisticsRegistry(bool registerPublic = true);
128
129
  /** Register a new running average statistic for `name` */
130
131
  AverageStat registerAverage(const std::string& name, bool expert = true);
132
  /** Register a new histogram statistic for `name` */
133
  template <typename T>
134
877960
  HistogramStat<T> registerHistogram(const std::string& name,
135
                                     bool expert = true)
136
  {
137
877960
    return registerStat<HistogramStat<T>>(name, expert);
138
  }
139
140
  /** Register a new integer statistic for `name` */
141
  IntStat registerInt(const std::string& name, bool expert = true);
142
143
  /** Register a new reference statistic for `name` */
144
  template <typename T>
145
189760
  ReferenceStat<T> registerReference(const std::string& name,
146
                                     bool expert = true)
147
  {
148
189760
    return registerStat<ReferenceStat<T>>(name, expert);
149
  }
150
  /**
151
   * Register a new reference statistic for `name` and initialize it to
152
   * refer to `t`.
153
   */
154
  template <typename T>
155
28381
  ReferenceStat<T> registerReference(const std::string& name,
156
                                     const T& t,
157
                                     bool expert = true)
158
  {
159
28381
    ReferenceStat<T> res = registerStat<ReferenceStat<T>>(name, expert);
160
28381
    res.set(t);
161
28381
    return res;
162
  }
163
164
  /**
165
   * Register a new container size statistic for `name` and initialize it
166
   * to refer to `t`.
167
   */
168
  template <typename T>
169
18903
  SizeStat<T> registerSize(const std::string& name,
170
                           const T& t,
171
                           bool expert = true)
172
  {
173
18903
    SizeStat<T> res = registerStat<SizeStat<T>>(name, expert);
174
18903
    res.set(t);
175
18903
    return res;
176
  }
177
178
  /** Register a new timer statistic for `name` */
179
  TimerStat registerTimer(const std::string& name, bool expert = true);
180
181
  /** Register a new value statistic for `name`. */
182
  template <typename T>
183
30282
  ValueStat<T> registerValue(const std::string& name, bool expert = true)
184
  {
185
30282
    return registerStat<ValueStat<T>>(name, expert);
186
  }
187
188
  /** Register a new value statistic for `name` and set it to `init`. */
189
  template <typename T>
190
11762
  ValueStat<T> registerValue(const std::string& name,
191
                             const T& init,
192
                             bool expert = true)
193
  {
194
11762
    ValueStat<T> res = registerStat<ValueStat<T>>(name, expert);
195
11762
    res.set(init);
196
11762
    return res;
197
  }
198
199
  /** begin iteration */
200
1
  auto begin() const { return d_stats.begin(); }
201
  /** end iteration */
202
1
  auto end() const { return d_stats.end(); }
203
204
  /**
205
   * Obtain the current state of all statistics.
206
   */
207
  void storeSnapshot();
208
209
  /**
210
   * Obtain a single statistic by name. Returns nullptr if no statistic has
211
   * been registered for this name.
212
   */
213
  StatisticBaseValue* get(const std::string& name) const;
214
215
  /**
216
   * Print all statistics to the given output stream.
217
   */
218
  void print(std::ostream& os) const;
219
  /**
220
   * Print all statistics in a safe manner to the given file descriptor.
221
   */
222
  void printSafe(int fd) const;
223
  /**
224
   * Print all statistics as a diff to the last stored snapshot.
225
   */
226
  void printDiff(std::ostream& os) const;
227
228
 private:
229
  /**
230
   * Helper method to register a new statistic.
231
   * If the name was already used, a new proxy object is created.
232
   * We check whether the type matches the type of the originally registered
233
   * statistic using `typeid`.
234
   */
235
  template <typename Stat>
236
5308407
  Stat registerStat(const std::string& name, bool expert)
237
  {
238
    if constexpr (Configuration::isStatisticsBuild())
239
    {
240
5308407
      auto it = d_stats.find(name);
241
5308407
      if (it == d_stats.end())
242
      {
243
4963890
        it = d_stats.emplace(name, std::make_unique<typename Stat::stat_type>())
244
9927780
                 .first;
245
4963890
        it->second->d_expert = expert;
246
      }
247
5308407
      auto* ptr = it->second.get();
248
5308407
      Assert(typeid(*ptr) == typeid(typename Stat::stat_type))
249
          << "Statistic value " << name
250
          << " was registered again with a different type.";
251
5308407
      it->second->d_expert = it->second->d_expert && expert;
252
5308407
      return Stat(static_cast<typename Stat::stat_type*>(ptr));
253
    }
254
    return Stat(nullptr);
255
  }
256
257
  /**
258
   * Holds (and owns) all statistic values, indexed by the name they were
259
   * registered for.
260
   */
261
  std::map<std::string, std::unique_ptr<StatisticBaseValue>> d_stats;
262
263
  std::unique_ptr<Snapshot> d_lastSnapshot;
264
};
265
266
/** Calls `sr.print(os)`. */
267
std::ostream& operator<<(std::ostream& os, const StatisticsRegistry& sr);
268
269
}  // namespace cvc5
270
271
#endif /* CVC5__STATISTICS_REGISTRY_H */