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 | |
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 | |
64 | const char *getDebugType() const { return DebugType; } |
65 | const char *getName() const { return Name; } |
66 | const char *getDesc() const { return Desc; } |
67 | |
68 | uint64_t getValue() const { return Value.load(m: std::memory_order_relaxed); } |
69 | |
70 | // Allow use of this class as the value itself. |
71 | operator uint64_t() const { return getValue(); } |
72 | |
73 | const TrackingStatistic &operator=(uint64_t Val) { |
74 | Value.store(i: Val, m: std::memory_order_relaxed); |
75 | return init(); |
76 | } |
77 | |
78 | const TrackingStatistic &operator++() { |
79 | Value.fetch_add(i: 1, m: std::memory_order_relaxed); |
80 | return init(); |
81 | } |
82 | |
83 | uint64_t operator++(int) { |
84 | init(); |
85 | return Value.fetch_add(i: 1, m: std::memory_order_relaxed); |
86 | } |
87 | |
88 | const TrackingStatistic &operator--() { |
89 | Value.fetch_sub(i: 1, m: std::memory_order_relaxed); |
90 | return init(); |
91 | } |
92 | |
93 | uint64_t operator--(int) { |
94 | init(); |
95 | return Value.fetch_sub(i: 1, m: std::memory_order_relaxed); |
96 | } |
97 | |
98 | const TrackingStatistic &operator+=(uint64_t V) { |
99 | if (V == 0) |
100 | return *this; |
101 | Value.fetch_add(i: V, m: 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(i: V, m: std::memory_order_relaxed); |
109 | return init(); |
110 | } |
111 | |
112 | void updateMax(uint64_t V) { |
113 | uint64_t PrevMax = Value.load(m: 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 | i1&: PrevMax, i2: V, m: std::memory_order_relaxed)) { |
118 | } |
119 | init(); |
120 | } |
121 | |
122 | protected: |
123 | TrackingStatistic &init() { |
124 | if (!Initialized.load(m: std::memory_order_acquire)) |
125 | RegisterStatistic(); |
126 | return *this; |
127 | } |
128 | |
129 | void RegisterStatistic(); |
130 | }; |
131 | |
132 | class NoopStatistic { |
133 | public: |
134 | NoopStatistic(const char * /*DebugType*/, const char * /*Name*/, |
135 | const char * /*Desc*/) {} |
136 | |
137 | uint64_t getValue() const { return 0; } |
138 | |
139 | // Allow use of this class as the value itself. |
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 | |
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 | |