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 #else 40 #define LLVM_ENABLE_STATS 0 41 #endif 42 43 namespace llvm { 44 45 class raw_ostream; 46 class raw_fd_ostream; 47 class StringRef; 48 49 class StatisticBase { 50 public: 51 const char *DebugType; 52 const char *Name; 53 const char *Desc; 54 55 StatisticBase(const char *DebugType, const char *Name, const char *Desc) 56 : DebugType(DebugType), Name(Name), Desc(Desc) {} 57 58 const char *getDebugType() const { return DebugType; } 59 const char *getName() const { return Name; } 60 const char *getDesc() const { return Desc; } 61 }; 62 63 class TrackingStatistic : public StatisticBase { 64 public: 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); } 72 73 // Allow use of this class as the value itself. 74 operator unsigned() const { return getValue(); } 75 76 const TrackingStatistic &operator=(unsigned Val) { 77 Value.store(Val, std::memory_order_relaxed); 78 return init(); 79 } 80 81 const TrackingStatistic &operator++() { 82 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 91 const TrackingStatistic &operator--() { 92 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 101 const TrackingStatistic &operator+=(unsigned V) { 102 if (V == 0) 103 return *this; 104 Value.fetch_add(V, std::memory_order_relaxed); 105 return init(); 106 } 107 108 const TrackingStatistic &operator-=(unsigned V) { 109 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 125 protected: 126 TrackingStatistic &init() { 127 if (!Initialized.load(std::memory_order_acquire)) 128 RegisterStatistic(); 129 return *this; 130 } 131 132 void RegisterStatistic(); 133 }; 134 135 class NoopStatistic : public StatisticBase { 136 public: 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 162 using Statistic = TrackingStatistic; 163 #else 164 using Statistic = NoopStatistic; 165 #endif 166 167 // 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) \ 170 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} 176 177 /// Enable the collection and printing of statistics. 178 void EnableStatistics(bool DoPrintOnExit = true); 179 180 /// Check if statistics are enabled. 181 bool AreStatisticsEnabled(); 182 183 /// Return a file stream to print our output on. 184 std::unique_ptr<raw_fd_ostream> CreateInfoOutputFile(); 185 186 /// Print statistics to the file returned by CreateInfoOutputFile(). 187 void PrintStatistics(); 188 189 /// Print statistics to the given output stream. 190 void 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(). 196 void PrintStatisticsJSON(raw_ostream &OS); 197 198 /// Get the statistics. This can be used to look up the value of 199 /// 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. 205 const std::vector<std::pair<StringRef, unsigned>> GetStatistics(); 206 207 /// Reset the statistics. This can be used to zero and de-register the 208 /// 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(). 220 void ResetStatistics(); 221 222 } // end namespace llvm 223 224 #endif // LLVM_ADT_STATISTIC_H 225