1 //===-- llvm/ADT/Statistic.h - Easy way to expose stats ---------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file defines the 'Statistic' class, which is designed to be an easy way
11 /// to expose various metrics from passes.  These statistics are printed at the
12 /// end of a run (from llvm_shutdown), when the -stats command line option is
13 /// passed on the command line.
14 ///
15 /// This is useful for reporting information like the number of instructions
16 /// simplified, optimized or removed by various transformations, like this:
17 ///
18 /// static Statistic NumInstsKilled("gcse", "Number of instructions killed");
19 ///
20 /// Later, in the code: ++NumInstsKilled;
21 ///
22 /// NOTE: Statistics *must* be declared as global variables.
23 ///
24 //===----------------------------------------------------------------------===//
25 
26 #ifndef LLVM_ADT_STATISTIC_H
27 #define LLVM_ADT_STATISTIC_H
28 
29 #include "llvm/Config/llvm-config.h"
30 #include "llvm/Support/Compiler.h"
31 #include <atomic>
32 #include <memory>
33 #include <vector>
34 
35 // Determine whether statistics should be enabled. We must do it here rather
36 // than in CMake because multi-config generators cannot determine this at
37 // configure time.
38 #if !defined(NDEBUG) || LLVM_FORCE_ENABLE_STATS
39 #define LLVM_ENABLE_STATS 1
40 #else
41 #define LLVM_ENABLE_STATS 0
42 #endif
43 
44 namespace llvm {
45 
46 class raw_ostream;
47 class raw_fd_ostream;
48 class StringRef;
49 
50 class TrackingStatistic {
51 public:
52   const char *const DebugType;
53   const char *const Name;
54   const char *const Desc;
55 
56   std::atomic<uint64_t> Value;
57   std::atomic<bool> Initialized;
58 
TrackingStatistic(const char * DebugType,const char * Name,const char * Desc)59   constexpr TrackingStatistic(const char *DebugType, const char *Name,
60                               const char *Desc)
61       : DebugType(DebugType), Name(Name), Desc(Desc), Value(0),
62         Initialized(false) {}
63 
getDebugType()64   const char *getDebugType() const { return DebugType; }
getName()65   const char *getName() const { return Name; }
getDesc()66   const char *getDesc() const { return Desc; }
67 
getValue()68   uint64_t getValue() const { return Value.load(std::memory_order_relaxed); }
69 
70   // Allow use of this class as the value itself.
uint64_t()71   operator uint64_t() const { return getValue(); }
72 
73   const TrackingStatistic &operator=(uint64_t Val) {
74     Value.store(Val, std::memory_order_relaxed);
75     return init();
76   }
77 
78   const TrackingStatistic &operator++() {
79     Value.fetch_add(1, std::memory_order_relaxed);
80     return init();
81   }
82 
83   uint64_t operator++(int) {
84     init();
85     return Value.fetch_add(1, std::memory_order_relaxed);
86   }
87 
88   const TrackingStatistic &operator--() {
89     Value.fetch_sub(1, std::memory_order_relaxed);
90     return init();
91   }
92 
93   uint64_t operator--(int) {
94     init();
95     return Value.fetch_sub(1, std::memory_order_relaxed);
96   }
97 
98   const TrackingStatistic &operator+=(uint64_t V) {
99     if (V == 0)
100       return *this;
101     Value.fetch_add(V, std::memory_order_relaxed);
102     return init();
103   }
104 
105   const TrackingStatistic &operator-=(uint64_t V) {
106     if (V == 0)
107       return *this;
108     Value.fetch_sub(V, std::memory_order_relaxed);
109     return init();
110   }
111 
updateMax(uint64_t V)112   void updateMax(uint64_t V) {
113     uint64_t PrevMax = Value.load(std::memory_order_relaxed);
114     // Keep trying to update max until we succeed or another thread produces
115     // a bigger max than us.
116     while (V > PrevMax && !Value.compare_exchange_weak(
117                               PrevMax, V, std::memory_order_relaxed)) {
118     }
119     init();
120   }
121 
122 protected:
init()123   TrackingStatistic &init() {
124     if (!Initialized.load(std::memory_order_acquire))
125       RegisterStatistic();
126     return *this;
127   }
128 
129   void RegisterStatistic();
130 };
131 
132 class NoopStatistic {
133 public:
NoopStatistic(const char *,const char *,const char *)134   NoopStatistic(const char * /*DebugType*/, const char * /*Name*/,
135                 const char * /*Desc*/) {}
136 
getValue()137   uint64_t getValue() const { return 0; }
138 
139   // Allow use of this class as the value itself.
uint64_t()140   operator uint64_t() const { return 0; }
141 
142   const NoopStatistic &operator=(uint64_t Val) { return *this; }
143 
144   const NoopStatistic &operator++() { return *this; }
145 
146   uint64_t operator++(int) { return 0; }
147 
148   const NoopStatistic &operator--() { return *this; }
149 
150   uint64_t operator--(int) { return 0; }
151 
152   const NoopStatistic &operator+=(const uint64_t &V) { return *this; }
153 
154   const NoopStatistic &operator-=(const uint64_t &V) { return *this; }
155 
updateMax(uint64_t V)156   void updateMax(uint64_t V) {}
157 };
158 
159 #if LLVM_ENABLE_STATS
160 using Statistic = TrackingStatistic;
161 #else
162 using Statistic = NoopStatistic;
163 #endif
164 
165 // STATISTIC - A macro to make definition of statistics really simple.  This
166 // automatically passes the DEBUG_TYPE of the file into the statistic.
167 #define STATISTIC(VARNAME, DESC)                                               \
168   static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC}
169 
170 // ALWAYS_ENABLED_STATISTIC - A macro to define a statistic like STATISTIC but
171 // it is enabled even if LLVM_ENABLE_STATS is off.
172 #define ALWAYS_ENABLED_STATISTIC(VARNAME, DESC)                                \
173   static llvm::TrackingStatistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC}
174 
175 /// Enable the collection and printing of statistics.
176 void EnableStatistics(bool DoPrintOnExit = true);
177 
178 /// Check if statistics are enabled.
179 bool AreStatisticsEnabled();
180 
181 /// Return a file stream to print our output on.
182 std::unique_ptr<raw_fd_ostream> CreateInfoOutputFile();
183 
184 /// Print statistics to the file returned by CreateInfoOutputFile().
185 void PrintStatistics();
186 
187 /// Print statistics to the given output stream.
188 void PrintStatistics(raw_ostream &OS);
189 
190 /// Print statistics in JSON format. This does include all global timers (\see
191 /// Timer, TimerGroup). Note that the timers are cleared after printing and will
192 /// not be printed in human readable form or in a second call of
193 /// PrintStatisticsJSON().
194 void PrintStatisticsJSON(raw_ostream &OS);
195 
196 /// Get the statistics. This can be used to look up the value of
197 /// statistics without needing to parse JSON.
198 ///
199 /// This function does not prevent statistics being updated by other threads
200 /// during it's execution. It will return the value at the point that it is
201 /// read. However, it will prevent new statistics from registering until it
202 /// completes.
203 std::vector<std::pair<StringRef, uint64_t>> GetStatistics();
204 
205 /// Reset the statistics. This can be used to zero and de-register the
206 /// statistics in order to measure a compilation.
207 ///
208 /// When this function begins to call destructors prior to returning, all
209 /// statistics will be zero and unregistered. However, that might not remain the
210 /// case by the time this function finishes returning. Whether update from other
211 /// threads are lost or merely deferred until during the function return is
212 /// timing sensitive.
213 ///
214 /// Callers who intend to use this to measure statistics for a single
215 /// compilation should ensure that no compilations are in progress at the point
216 /// this function is called and that only one compilation executes until calling
217 /// GetStatistics().
218 void ResetStatistics();
219 
220 } // end namespace llvm
221 
222 #endif // LLVM_ADT_STATISTIC_H
223