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 TrackingStatistic { 50 public: 51 const char *const DebugType; 52 const char *const Name; 53 const char *const Desc; 54 55 std::atomic<unsigned> Value; 56 std::atomic<bool> Initialized; 57 TrackingStatistic(const char * DebugType,const char * Name,const char * Desc)58 constexpr TrackingStatistic(const char *DebugType, const char *Name, 59 const char *Desc) 60 : DebugType(DebugType), Name(Name), Desc(Desc), Value(0), 61 Initialized(false) {} 62 getDebugType()63 const char *getDebugType() const { return DebugType; } getName()64 const char *getName() const { return Name; } getDesc()65 const char *getDesc() const { return Desc; } 66 getValue()67 unsigned getValue() const { return Value.load(std::memory_order_relaxed); } 68 69 // Allow use of this class as the value itself. 70 operator unsigned() const { return getValue(); } 71 72 const TrackingStatistic &operator=(unsigned Val) { 73 Value.store(Val, std::memory_order_relaxed); 74 return init(); 75 } 76 77 const TrackingStatistic &operator++() { 78 Value.fetch_add(1, std::memory_order_relaxed); 79 return init(); 80 } 81 82 unsigned operator++(int) { 83 init(); 84 return Value.fetch_add(1, std::memory_order_relaxed); 85 } 86 87 const TrackingStatistic &operator--() { 88 Value.fetch_sub(1, std::memory_order_relaxed); 89 return init(); 90 } 91 92 unsigned operator--(int) { 93 init(); 94 return Value.fetch_sub(1, std::memory_order_relaxed); 95 } 96 97 const TrackingStatistic &operator+=(unsigned V) { 98 if (V == 0) 99 return *this; 100 Value.fetch_add(V, std::memory_order_relaxed); 101 return init(); 102 } 103 104 const TrackingStatistic &operator-=(unsigned V) { 105 if (V == 0) 106 return *this; 107 Value.fetch_sub(V, std::memory_order_relaxed); 108 return init(); 109 } 110 updateMax(unsigned V)111 void updateMax(unsigned V) { 112 unsigned PrevMax = Value.load(std::memory_order_relaxed); 113 // Keep trying to update max until we succeed or another thread produces 114 // a bigger max than us. 115 while (V > PrevMax && !Value.compare_exchange_weak( 116 PrevMax, V, std::memory_order_relaxed)) { 117 } 118 init(); 119 } 120 121 protected: init()122 TrackingStatistic &init() { 123 if (!Initialized.load(std::memory_order_acquire)) 124 RegisterStatistic(); 125 return *this; 126 } 127 128 void RegisterStatistic(); 129 }; 130 131 class NoopStatistic { 132 public: NoopStatistic(const char *,const char *,const char *)133 NoopStatistic(const char * /*DebugType*/, const char * /*Name*/, 134 const char * /*Desc*/) {} 135 getValue()136 unsigned getValue() const { return 0; } 137 138 // Allow use of this class as the value itself. 139 operator unsigned() const { return 0; } 140 141 const NoopStatistic &operator=(unsigned Val) { return *this; } 142 143 const NoopStatistic &operator++() { return *this; } 144 145 unsigned operator++(int) { return 0; } 146 147 const NoopStatistic &operator--() { return *this; } 148 149 unsigned operator--(int) { return 0; } 150 151 const NoopStatistic &operator+=(const unsigned &V) { return *this; } 152 153 const NoopStatistic &operator-=(const unsigned &V) { return *this; } 154 updateMax(unsigned V)155 void updateMax(unsigned V) {} 156 }; 157 158 #if LLVM_ENABLE_STATS 159 using Statistic = TrackingStatistic; 160 #else 161 using Statistic = NoopStatistic; 162 #endif 163 164 // STATISTIC - A macro to make definition of statistics really simple. This 165 // automatically passes the DEBUG_TYPE of the file into the statistic. 166 #define STATISTIC(VARNAME, DESC) \ 167 static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC} 168 169 // ALWAYS_ENABLED_STATISTIC - A macro to define a statistic like STATISTIC but 170 // it is enabled even if LLVM_ENABLE_STATS is off. 171 #define ALWAYS_ENABLED_STATISTIC(VARNAME, DESC) \ 172 static llvm::TrackingStatistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC} 173 174 /// Enable the collection and printing of statistics. 175 void EnableStatistics(bool DoPrintOnExit = true); 176 177 /// Check if statistics are enabled. 178 bool AreStatisticsEnabled(); 179 180 /// Return a file stream to print our output on. 181 std::unique_ptr<raw_fd_ostream> CreateInfoOutputFile(); 182 183 /// Print statistics to the file returned by CreateInfoOutputFile(). 184 void PrintStatistics(); 185 186 /// Print statistics to the given output stream. 187 void PrintStatistics(raw_ostream &OS); 188 189 /// Print statistics in JSON format. This does include all global timers (\see 190 /// Timer, TimerGroup). Note that the timers are cleared after printing and will 191 /// not be printed in human readable form or in a second call of 192 /// PrintStatisticsJSON(). 193 void PrintStatisticsJSON(raw_ostream &OS); 194 195 /// Get the statistics. This can be used to look up the value of 196 /// statistics without needing to parse JSON. 197 /// 198 /// This function does not prevent statistics being updated by other threads 199 /// during it's execution. It will return the value at the point that it is 200 /// read. However, it will prevent new statistics from registering until it 201 /// completes. 202 const std::vector<std::pair<StringRef, unsigned>> GetStatistics(); 203 204 /// Reset the statistics. This can be used to zero and de-register the 205 /// statistics in order to measure a compilation. 206 /// 207 /// When this function begins to call destructors prior to returning, all 208 /// statistics will be zero and unregistered. However, that might not remain the 209 /// case by the time this function finishes returning. Whether update from other 210 /// threads are lost or merely deferred until during the function return is 211 /// timing sensitive. 212 /// 213 /// Callers who intend to use this to measure statistics for a single 214 /// compilation should ensure that no compilations are in progress at the point 215 /// this function is called and that only one compilation executes until calling 216 /// GetStatistics(). 217 void ResetStatistics(); 218 219 } // end namespace llvm 220 221 #endif // LLVM_ADT_STATISTIC_H 222