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