/// 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);
/// Sort statistics by debugtype,name,description.
void sort();
public:
- using const_iterator = std::vector<const Statistic *>::const_iterator;
+ using const_iterator = std::vector<Statistic *>::const_iterator;
StatisticInfo();
~StatisticInfo();
- void addStatistic(const Statistic *S) {
+ void addStatistic(Statistic *S) {
Stats.push_back(S);
}
iterator_range<const_iterator> statistics() const {
return {begin(), end()};
}
+
+ void reset();
};
} // end anonymous namespace
});
}
+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;
ReturnStats.emplace_back(Stat->getName(), Stat->getValue());
return ReturnStats;
}
+
+void llvm::ResetStatistics() {
+ StatInfo->reset();
+}
#include "gtest/gtest.h"
using namespace llvm;
+using OptionalStatistic = Optional<std::pair<StringRef, unsigned>>;
+
namespace {
#define DEBUG_TYPE "unittest"
STATISTIC(Counter, "Counts things");
STATISTIC(Counter2, "Counts other things");
+static void
+extractCounters(const std::vector<std::pair<StringRef, unsigned>> &Range,
+ OptionalStatistic &S1, OptionalStatistic &S2) {
+ for (const auto &S : Range) {
+ if (S.first == "Counter")
+ S1 = S;
+ if (S.first == "Counter2")
+ S2 = S;
+ }
+}
+
TEST(StatisticTest, Count) {
EnableStatistics();
#endif
#if LLVM_ENABLE_STATS
- const auto Range1 = GetStatistics();
- EXPECT_NE(Range1.begin(), Range1.end());
- EXPECT_EQ(Range1.begin() + 1, Range1.end());
-
- Optional<std::pair<StringRef, unsigned>> S1;
- Optional<std::pair<StringRef, unsigned>> S2;
- for (const auto &S : Range1) {
- if (std::string(S.first) == "Counter")
- S1 = S;
- if (std::string(S.first) == "Counter2")
- S2 = S;
- }
+ {
+ const auto Range1 = GetStatistics();
+ EXPECT_NE(Range1.begin(), Range1.end());
+ EXPECT_EQ(Range1.begin() + 1, Range1.end());
+
+ OptionalStatistic S1;
+ OptionalStatistic S2;
+ extractCounters(Range1, S1, S2);
- EXPECT_NE(S1.hasValue(), false);
- EXPECT_EQ(S2.hasValue(), false);
+ EXPECT_EQ(S1.hasValue(), true);
+ EXPECT_EQ(S2.hasValue(), false);
+ }
// Counter2 will be registered when it's first touched.
Counter2++;
- const auto Range2 = GetStatistics();
- EXPECT_NE(Range2.begin(), Range2.end());
- EXPECT_EQ(Range2.begin() + 2, Range2.end());
+ {
+ const auto Range = GetStatistics();
+ EXPECT_NE(Range.begin(), Range.end());
+ EXPECT_EQ(Range.begin() + 2, Range.end());
- S1 = None;
- S2 = None;
- for (const auto &S : Range2) {
- if (std::string(S.first) == "Counter")
- S1 = S;
- if (std::string(S.first) == "Counter2")
- S2 = S;
- }
+ OptionalStatistic S1;
+ OptionalStatistic S2;
+ extractCounters(Range, S1, S2);
- EXPECT_NE(S1.hasValue(), false);
- EXPECT_NE(S2.hasValue(), false);
+ EXPECT_EQ(S1.hasValue(), true);
+ EXPECT_EQ(S2.hasValue(), true);
- EXPECT_EQ(S1->first, "Counter");
- EXPECT_EQ(S1->second, 2u);
+ EXPECT_EQ(S1->first, "Counter");
+ EXPECT_EQ(S1->second, 2u);
- EXPECT_EQ(S2->first, "Counter2");
- EXPECT_EQ(S2->second, 1u);
+ EXPECT_EQ(S2->first, "Counter2");
+ EXPECT_EQ(S2->second, 1u);
+ }
#else
Counter2++;
auto &Range = GetStatistics();
EXPECT_EQ(Range.begin(), Range.end());
#endif
+
+#if LLVM_ENABLE_STATS
+ // Check that resetting the statistics works correctly.
+ // It should empty the list and zero the counters.
+ ResetStatistics();
+ {
+ auto &Range = GetStatistics();
+ EXPECT_EQ(Range.begin(), Range.end());
+ EXPECT_EQ(Counter, 0u);
+ EXPECT_EQ(Counter2, 0u);
+ OptionalStatistic S1;
+ OptionalStatistic S2;
+ extractCounters(Range, S1, S2);
+ EXPECT_EQ(S1.hasValue(), false);
+ EXPECT_EQ(S2.hasValue(), false);
+ }
+
+ // Now check that they successfully re-register and count.
+ Counter++;
+ Counter2++;
+
+ {
+ auto &Range = GetStatistics();
+ EXPECT_EQ(Range.begin() + 2, Range.end());
+ EXPECT_EQ(Counter, 1u);
+ EXPECT_EQ(Counter2, 1u);
+
+ OptionalStatistic S1;
+ OptionalStatistic S2;
+ extractCounters(Range, S1, S2);
+
+ EXPECT_EQ(S1.hasValue(), true);
+ EXPECT_EQ(S2.hasValue(), true);
+
+ EXPECT_EQ(S1->first, "Counter");
+ EXPECT_EQ(S1->second, 1u);
+
+ EXPECT_EQ(S2->first, "Counter2");
+ EXPECT_EQ(S2->second, 1u);
+ }
+#else
+ // No need to test the output ResetStatistics(), there's nothing to reset so
+ // we can't tell if it failed anyway.
+ ResetStatistics();
+#endif
}
} // end anonymous namespace