diff options
Diffstat (limited to 'lib/Support/Statistic.cpp')
-rw-r--r-- | lib/Support/Statistic.cpp | 87 |
1 files changed, 72 insertions, 15 deletions
diff --git a/lib/Support/Statistic.cpp b/lib/Support/Statistic.cpp index 544ae2d0983c..d57300a75d1d 100644 --- a/lib/Support/Statistic.cpp +++ b/lib/Support/Statistic.cpp @@ -52,11 +52,14 @@ static bool Enabled; static bool PrintOnExit; namespace { -/// StatisticInfo - This class is used in a ManagedStatic so that it is created -/// on demand (when the first statistic is bumped) and destroyed only when -/// llvm_shutdown is called. We print statistics from the destructor. +/// This class is used in a ManagedStatic so that it is created on demand (when +/// the first statistic is bumped) and destroyed only when llvm_shutdown is +/// called. We print statistics from the destructor. +/// This class is also used to look up statistic values from applications that +/// use LLVM. class StatisticInfo { - std::vector<const Statistic*> Stats; + std::vector<Statistic*> Stats; + friend void llvm::PrintStatistics(); friend void llvm::PrintStatistics(raw_ostream &OS); friend void llvm::PrintStatisticsJSON(raw_ostream &OS); @@ -64,14 +67,24 @@ class StatisticInfo { /// Sort statistics by debugtype,name,description. void sort(); public: + using const_iterator = std::vector<Statistic *>::const_iterator; + StatisticInfo(); ~StatisticInfo(); - void addStatistic(const Statistic *S) { + void addStatistic(Statistic *S) { Stats.push_back(S); } + + const_iterator begin() const { return Stats.begin(); } + const_iterator end() const { return Stats.end(); } + iterator_range<const_iterator> statistics() const { + return {begin(), end()}; + } + + void reset(); }; -} +} // end anonymous namespace static ManagedStatic<StatisticInfo> StatInfo; static ManagedStatic<sys::SmartMutex<true> > StatLock; @@ -81,17 +94,24 @@ static ManagedStatic<sys::SmartMutex<true> > StatLock; void Statistic::RegisterStatistic() { // If stats are enabled, inform StatInfo that this statistic should be // printed. - sys::SmartScopedLock<true> Writer(*StatLock); - if (!Initialized) { + // llvm_shutdown calls destructors while holding the ManagedStatic mutex. + // These destructors end up calling PrintStatistics, which takes StatLock. + // Since dereferencing StatInfo and StatLock can require taking the + // ManagedStatic mutex, doing so with StatLock held would lead to a lock + // order inversion. To avoid that, we dereference the ManagedStatics first, + // and only take StatLock afterwards. + if (!Initialized.load(std::memory_order_relaxed)) { + sys::SmartMutex<true> &Lock = *StatLock; + StatisticInfo &SI = *StatInfo; + sys::SmartScopedLock<true> Writer(Lock); + // Check Initialized again after acquiring the lock. + if (Initialized.load(std::memory_order_relaxed)) + return; if (Stats || Enabled) - StatInfo->addStatistic(this); + SI.addStatistic(this); - TsanHappensBefore(this); - sys::MemoryFence(); // Remember we have been registered. - TsanIgnoreWritesBegin(); - Initialized = true; - TsanIgnoreWritesEnd(); + Initialized.store(true, std::memory_order_release); } } @@ -128,6 +148,28 @@ void StatisticInfo::sort() { }); } +void StatisticInfo::reset() { + sys::SmartScopedLock<true> Writer(*StatLock); + + // Tell each statistic that it isn't registered so it has to register + // again. We're holding the lock so it won't be able to do so until we're + // finished. Once we've forced it to re-register (after we return), then zero + // the value. + for (auto *Stat : Stats) { + // Value updates to a statistic that complete before this statement in the + // iteration for that statistic will be lost as intended. + Stat->Initialized = false; + Stat->Value = 0; + } + + // Clear the registration list and release the lock once we're done. Any + // pending updates from other threads will safely take effect after we return. + // That might not be what the user wants if they're measuring a compilation + // but it's their responsibility to prevent concurrent compilations to make + // a single compilation measurable. + Stats.clear(); +} + void llvm::PrintStatistics(raw_ostream &OS) { StatisticInfo &Stats = *StatInfo; @@ -159,6 +201,7 @@ void llvm::PrintStatistics(raw_ostream &OS) { } void llvm::PrintStatisticsJSON(raw_ostream &OS) { + sys::SmartScopedLock<true> Reader(*StatLock); StatisticInfo &Stats = *StatInfo; Stats.sort(); @@ -184,7 +227,8 @@ void llvm::PrintStatisticsJSON(raw_ostream &OS) { } void llvm::PrintStatistics() { -#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) +#if LLVM_ENABLE_STATS + sys::SmartScopedLock<true> Reader(*StatLock); StatisticInfo &Stats = *StatInfo; // Statistics not enabled? @@ -209,3 +253,16 @@ void llvm::PrintStatistics() { } #endif } + +const std::vector<std::pair<StringRef, unsigned>> llvm::GetStatistics() { + sys::SmartScopedLock<true> Reader(*StatLock); + std::vector<std::pair<StringRef, unsigned>> ReturnStats; + + for (const auto &Stat : StatInfo->statistics()) + ReturnStats.emplace_back(Stat->getName(), Stat->getValue()); + return ReturnStats; +} + +void llvm::ResetStatistics() { + StatInfo->reset(); +} |