Index: cmake/modules/HandleLLVMOptions.cmake =================================================================== --- cmake/modules/HandleLLVMOptions.cmake +++ cmake/modules/HandleLLVMOptions.cmake @@ -881,3 +881,7 @@ set(LLVM_DEFINITIONS "${result}" PARENT_SCOPE) endfunction() get_compile_definitions() + +# The default for LLVM_ENABLE_STATS depends on whether NDEBUG is defined or not. +# LLVM_ENABLE_ASSERTIONS controls that so re-use it as the default. +option(LLVM_ENABLE_STATS "Enable statistics collection" ${LLVM_ENABLE_ASSERTIONS}) Index: include/llvm/ADT/Statistic.h =================================================================== --- include/llvm/ADT/Statistic.h +++ include/llvm/ADT/Statistic.h @@ -60,7 +60,7 @@ // Allow use of this class as the value itself. operator unsigned() const { return getValue(); } -#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) +#if defined(LLVM_ENABLE_STATS) const Statistic &operator=(unsigned Val) { Value.store(Val, std::memory_order_relaxed); return init(); @@ -142,7 +142,7 @@ void updateMax(unsigned V) {} -#endif // !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) +#endif // defined(LLVM_ENABLE_STATS) protected: Statistic &init() { Index: include/llvm/ADT/StatisticInfo.h =================================================================== --- /dev/null +++ include/llvm/ADT/StatisticInfo.h @@ -0,0 +1,66 @@ +//===-- llvm/ADT/StatisticInfo.h - Easy way to expose stats -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the 'StatisticInfo' class, which provides access to the +// library of statistics that are collected. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STATISTICINFO_H +#define LLVM_ADT_STATISTICINFO_H + +#include "llvm/ADT/iterator_range.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace llvm { +/// 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 Stats; + + friend void llvm::PrintStatistics(); + friend void llvm::PrintStatistics(raw_ostream &OS); + friend void llvm::PrintStatisticsJSON(raw_ostream &OS); + + /// Sort statistics by debugtype,name,description. + void sort(); +public: + using const_iterator = std::vector::const_iterator; + + StatisticInfo(); + ~StatisticInfo(); + + void addStatistic(const Statistic *S) { + Stats.push_back(S); + } + + const_iterator begin() const { return Stats.begin(); } + const_iterator end() const { return Stats.end(); } + iterator_range statistics() const { + return {begin(), end()}; + } +}; + +/// \brief Get the statistics. This can be used to look up the value of +/// statistics without needing to parse JSON. +/// +/// This function does not prevent statistics being updated by other threads +/// during it's execution. It will return the value at the point that it is +/// read. However, it will prevent new statistics from registering until it +/// completes. +const std::vector> GetStatistics(); + +} // end namespace llvm + +#endif // LLVM_ADT_STATISTICINFO_H Index: include/llvm/Config/config.h.cmake =================================================================== --- include/llvm/Config/config.h.cmake +++ include/llvm/Config/config.h.cmake @@ -440,4 +440,7 @@ /* Define to the default GlobalISel coverage file prefix */ #cmakedefine LLVM_GISEL_COV_PREFIX "${LLVM_GISEL_COV_PREFIX}" +/* Whether STATISTIC() values are maintained */ +#cmakedefine01 LLVM_ENABLE_STATS + #endif Index: lib/Support/Statistic.cpp =================================================================== --- lib/Support/Statistic.cpp +++ lib/Support/Statistic.cpp @@ -22,6 +22,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StatisticInfo.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" @@ -51,28 +52,6 @@ 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. -class StatisticInfo { - std::vector Stats; - friend void llvm::PrintStatistics(); - friend void llvm::PrintStatistics(raw_ostream &OS); - friend void llvm::PrintStatisticsJSON(raw_ostream &OS); - - /// Sort statistics by debugtype,name,description. - void sort(); -public: - StatisticInfo(); - ~StatisticInfo(); - - void addStatistic(const Statistic *S) { - Stats.push_back(S); - } -}; -} - static ManagedStatic StatInfo; static ManagedStatic > StatLock; @@ -180,7 +159,7 @@ } void llvm::PrintStatistics() { -#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) +#if defined(LLVM_ENABLE_STATS) StatisticInfo &Stats = *StatInfo; // Statistics not enabled? @@ -205,3 +184,12 @@ } #endif } + +const std::vector> llvm::GetStatistics() { + sys::SmartScopedLock Reader(*StatLock); + std::vector> ReturnStats; + + for (const auto &Stat : StatInfo->statistics()) + ReturnStats.emplace_back(Stat->getName(), Stat->getValue()); + return ReturnStats; +} Index: unittests/ADT/CMakeLists.txt =================================================================== --- unittests/ADT/CMakeLists.txt +++ unittests/ADT/CMakeLists.txt @@ -56,6 +56,7 @@ SparseBitVectorTest.cpp SparseMultiSetTest.cpp SparseSetTest.cpp + StatisticTest.cpp StringExtrasTest.cpp StringMapTest.cpp StringRefTest.cpp Index: unittests/ADT/StatisticTest.cpp =================================================================== --- /dev/null +++ unittests/ADT/StatisticTest.cpp @@ -0,0 +1,108 @@ +//===- llvm/unittest/ADT/StatisticTest.cpp - Statistic unit tests ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StatisticInfo.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +using namespace llvm; + +namespace { +#define DEBUG_TYPE "unittest" +STATISTIC(Counter, "Counts things"); +STATISTIC(Counter2, "Counts other things"); + +TEST(StatisticTest, Count) { + EnableStatistics(); + + Counter = 0; + EXPECT_EQ(Counter, 0u); + Counter++; + Counter++; +#if defined(LLVM_ENABLE_STATS) + EXPECT_EQ(Counter, 2u); +#else + EXPECT_EQ(Counter, 0u); +#endif +} + +TEST(StatisticTest, Assign) { + EnableStatistics(); + + Counter = 2; +#if defined(LLVM_ENABLE_STATS) + EXPECT_EQ(Counter, 2u); +#else + EXPECT_EQ(Counter, 0u); +#endif +} + +TEST(StatisticTest, API) { + EnableStatistics(); + + Counter = 0; + EXPECT_EQ(Counter, 0u); + Counter++; + Counter++; +#if defined(LLVM_ENABLE_STATS) + EXPECT_EQ(Counter, 2u); +#else + EXPECT_EQ(Counter, 0u); +#endif + +#if defined(LLVM_ENABLE_STATS) + const auto Range1 = GetStatistics(); + EXPECT_NE(Range1.begin(), Range1.end()); + EXPECT_EQ(Range1.begin() + 1, Range1.end()); + + const Statistic *S1 = nullptr; + const Statistic *S2 = nullptr; + for (const auto *S : Range1) { + if (std::string(S->getName()) == "Counter") + S1 = S; + if (std::string(S->getName()) == "Counter2") + S2 = S; + } + + EXPECT_NE(S1, nullptr); + EXPECT_EQ(S2, nullptr); + + // 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()); + + S1 = nullptr; + for (const auto *S : Range2) { + if (std::string(S->getName()) == "Counter") + S1 = S; + if (std::string(S->getName()) == "Counter2") + S2 = S; + } + + EXPECT_NE(S1, nullptr); + EXPECT_NE(S2, nullptr); + + EXPECT_EQ(S1->getName(), "Counter"); + EXPECT_EQ(S1->getDesc(), "Counts things"); + EXPECT_EQ(S1->getValue(), 2u); + + EXPECT_EQ(S2->getName(), "Counter2"); + EXPECT_EQ(S2->getDesc(), "Counts other things"); + EXPECT_EQ(S2->getValue(), 1u); +#else + Counter2++; + auto &Range = GetStatistics(); + EXPECT_EQ(Range.begin(), Range.end()); +#endif +} + +} // end anonymous namespace