Skip to content

Commit

Permalink
Support resetting STATISTIC() values using llvm::ResetStatistics()
Browse files Browse the repository at this point in the history
Summary:
Most of the time, compiler statistics can be obtained using a process that
performs a single compilation and terminates such as llc. However, this isn't
always the case. JITs for example, perform multiple compilations over their
lifetime and STATISTIC() will record cumulative values across all of them.

Provide tools like this with the facilities needed to measure individual
compilations by allowing them to reset the STATISTIC() values back to zero using
llvm::ResetStatistics(). It's still the tools responsibility to ensure that they
perform compilations in such a way that the results are meaningful to their
intended use.

Reviewers: qcolombet, rtereshin, bogner, aditya_nandakumar

Reviewed By: bogner

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D44181

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@326981 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
dsandersllvm committed Mar 8, 2018
1 parent a385fd7 commit 50adb3d
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 34 deletions.
15 changes: 15 additions & 0 deletions include/llvm/ADT/Statistic.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,21 @@ void PrintStatisticsJSON(raw_ostream &OS);
/// completes.
const std::vector<std::pair<StringRef, unsigned>> GetStatistics();

/// \brief Reset the statistics. This can be used to zero and de-register the
/// statistics in order to measure a compilation.
///
/// When this function begins to call destructors prior to returning, all
/// statistics will be zero and unregistered. However, that might not remain the
/// case by the time this function finishes returning. Whether update from other
/// threads are lost or merely deferred until during the function return is
/// timing sensitive.
///
/// Callers who intend to use this to measure statistics for a single
/// compilation should ensure that no compilations are in progress at the point
/// this function is called and that only one compilation executes until calling
/// GetStatistics().
void ResetStatistics();

} // end namespace llvm

#endif // LLVM_ADT_STATISTIC_H
34 changes: 31 additions & 3 deletions lib/Support/Statistic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ namespace {
/// 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);
Expand All @@ -67,12 +67,12 @@ class StatisticInfo {
/// 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);
}

Expand All @@ -81,6 +81,8 @@ class StatisticInfo {
iterator_range<const_iterator> statistics() const {
return {begin(), end()};
}

void reset();
};
} // end anonymous namespace

Expand Down Expand Up @@ -135,6 +137,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;

Expand Down Expand Up @@ -227,3 +251,7 @@ const std::vector<std::pair<StringRef, unsigned>> llvm::GetStatistics() {
ReturnStats.emplace_back(Stat->getName(), Stat->getValue());
return ReturnStats;
}

void llvm::ResetStatistics() {
StatInfo->reset();
}
114 changes: 83 additions & 31 deletions unittests/ADT/StatisticTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,24 @@
#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();

Expand Down Expand Up @@ -56,51 +69,90 @@ TEST(StatisticTest, API) {
#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

0 comments on commit 50adb3d

Please sign in to comment.