blob: aa338ccff19a6696a91b77de7fcf8965ce1ff18e [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===-- llvm/ADT/Statistic.h - Easy way to expose stats ---------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
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
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020039#else
40#define LLVM_ENABLE_STATS 0
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010041#endif
42
43namespace llvm {
44
45class raw_ostream;
46class raw_fd_ostream;
47class StringRef;
48
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020049class StatisticBase {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010050public:
51 const char *DebugType;
52 const char *Name;
53 const char *Desc;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010054
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020055 StatisticBase(const char *DebugType, const char *Name, const char *Desc)
56 : DebugType(DebugType), Name(Name), Desc(Desc) {}
57
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010058 const char *getDebugType() const { return DebugType; }
59 const char *getName() const { return Name; }
60 const char *getDesc() const { return Desc; }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020061};
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010062
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020063class TrackingStatistic : public StatisticBase {
64public:
65 std::atomic<unsigned> Value;
66 std::atomic<bool> Initialized;
67
68 TrackingStatistic(const char *DebugType, const char *Name, const char *Desc)
69 : StatisticBase(DebugType, Name, Desc), Value(0), Initialized(false) {}
70
71 unsigned getValue() const { return Value.load(std::memory_order_relaxed); }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010072
73 // Allow use of this class as the value itself.
74 operator unsigned() const { return getValue(); }
75
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020076 const TrackingStatistic &operator=(unsigned Val) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010077 Value.store(Val, std::memory_order_relaxed);
78 return init();
79 }
80
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020081 const TrackingStatistic &operator++() {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010082 Value.fetch_add(1, std::memory_order_relaxed);
83 return init();
84 }
85
86 unsigned operator++(int) {
87 init();
88 return Value.fetch_add(1, std::memory_order_relaxed);
89 }
90
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020091 const TrackingStatistic &operator--() {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010092 Value.fetch_sub(1, std::memory_order_relaxed);
93 return init();
94 }
95
96 unsigned operator--(int) {
97 init();
98 return Value.fetch_sub(1, std::memory_order_relaxed);
99 }
100
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200101 const TrackingStatistic &operator+=(unsigned V) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100102 if (V == 0)
103 return *this;
104 Value.fetch_add(V, std::memory_order_relaxed);
105 return init();
106 }
107
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200108 const TrackingStatistic &operator-=(unsigned V) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100109 if (V == 0)
110 return *this;
111 Value.fetch_sub(V, std::memory_order_relaxed);
112 return init();
113 }
114
115 void updateMax(unsigned V) {
116 unsigned PrevMax = Value.load(std::memory_order_relaxed);
117 // Keep trying to update max until we succeed or another thread produces
118 // a bigger max than us.
119 while (V > PrevMax && !Value.compare_exchange_weak(
120 PrevMax, V, std::memory_order_relaxed)) {
121 }
122 init();
123 }
124
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100125protected:
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200126 TrackingStatistic &init() {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100127 if (!Initialized.load(std::memory_order_acquire))
128 RegisterStatistic();
129 return *this;
130 }
131
132 void RegisterStatistic();
133};
134
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200135class NoopStatistic : public StatisticBase {
136public:
137 using StatisticBase::StatisticBase;
138
139 unsigned getValue() const { return 0; }
140
141 // Allow use of this class as the value itself.
142 operator unsigned() const { return 0; }
143
144 const NoopStatistic &operator=(unsigned Val) { return *this; }
145
146 const NoopStatistic &operator++() { return *this; }
147
148 unsigned operator++(int) { return 0; }
149
150 const NoopStatistic &operator--() { return *this; }
151
152 unsigned operator--(int) { return 0; }
153
154 const NoopStatistic &operator+=(const unsigned &V) { return *this; }
155
156 const NoopStatistic &operator-=(const unsigned &V) { return *this; }
157
158 void updateMax(unsigned V) {}
159};
160
161#if LLVM_ENABLE_STATS
162using Statistic = TrackingStatistic;
163#else
164using Statistic = NoopStatistic;
165#endif
166
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100167// STATISTIC - A macro to make definition of statistics really simple. This
168// automatically passes the DEBUG_TYPE of the file into the statistic.
169#define STATISTIC(VARNAME, DESC) \
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200170 static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC}
171
172// ALWAYS_ENABLED_STATISTIC - A macro to define a statistic like STATISTIC but
173// it is enabled even if LLVM_ENABLE_STATS is off.
174#define ALWAYS_ENABLED_STATISTIC(VARNAME, DESC) \
175 static llvm::TrackingStatistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC}
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100176
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100177/// Enable the collection and printing of statistics.
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200178void EnableStatistics(bool DoPrintOnExit = true);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100179
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100180/// Check if statistics are enabled.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100181bool AreStatisticsEnabled();
182
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100183/// Return a file stream to print our output on.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100184std::unique_ptr<raw_fd_ostream> CreateInfoOutputFile();
185
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100186/// Print statistics to the file returned by CreateInfoOutputFile().
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100187void PrintStatistics();
188
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100189/// Print statistics to the given output stream.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100190void PrintStatistics(raw_ostream &OS);
191
192/// Print statistics in JSON format. This does include all global timers (\see
193/// Timer, TimerGroup). Note that the timers are cleared after printing and will
194/// not be printed in human readable form or in a second call of
195/// PrintStatisticsJSON().
196void PrintStatisticsJSON(raw_ostream &OS);
197
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100198/// Get the statistics. This can be used to look up the value of
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100199/// statistics without needing to parse JSON.
200///
201/// This function does not prevent statistics being updated by other threads
202/// during it's execution. It will return the value at the point that it is
203/// read. However, it will prevent new statistics from registering until it
204/// completes.
205const std::vector<std::pair<StringRef, unsigned>> GetStatistics();
206
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100207/// Reset the statistics. This can be used to zero and de-register the
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100208/// statistics in order to measure a compilation.
209///
210/// When this function begins to call destructors prior to returning, all
211/// statistics will be zero and unregistered. However, that might not remain the
212/// case by the time this function finishes returning. Whether update from other
213/// threads are lost or merely deferred until during the function return is
214/// timing sensitive.
215///
216/// Callers who intend to use this to measure statistics for a single
217/// compilation should ensure that no compilations are in progress at the point
218/// this function is called and that only one compilation executes until calling
219/// GetStatistics().
220void ResetStatistics();
221
222} // end namespace llvm
223
224#endif // LLVM_ADT_STATISTIC_H