summaryrefslogtreecommitdiff
path: root/lib/Support/Statistic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Support/Statistic.cpp')
-rw-r--r--lib/Support/Statistic.cpp87
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();
+}