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