Index: include/llvm/Support/DebugCounter.h =================================================================== --- include/llvm/Support/DebugCounter.h +++ include/llvm/Support/DebugCounter.h @@ -51,6 +51,10 @@ #include "llvm/Support/raw_ostream.h" #include +#if LLVM_ENABLE_THREADS +#include +#endif + namespace llvm { class DebugCounter { @@ -151,10 +155,30 @@ } // Struct to store counter info. struct CounterInfo { + #if LLVM_ENABLE_THREADS + CounterInfo() = default; + CounterInfo(const CounterInfo &Other) { *this = Other; } + CounterInfo &operator =(const CounterInfo &Other) { + Count = Other.Count.load(); + Skip = Other.Skip.load(); + StopAfter = Other.StopAfter.load(); + IsSet = Other.IsSet.load(); + Desc = Other.Desc; + return *this; + } + + // We use atomics merely to silence TSAN warnings. DebugCounter does not + // well-defined semantics for multi-threaded programs. + std::atomic Count{0}; + std::atomic Skip{0}; + std::atomic StopAfter{-1}; + std::atomic IsSet{false}; + #else int64_t Count = 0; int64_t Skip = 0; int64_t StopAfter = -1; bool IsSet = false; + #endif // LLVM_ENABLE_THREADS std::string Desc; }; DenseMap Counters; Index: unittests/Support/DebugCounterTest.cpp =================================================================== --- unittests/Support/DebugCounterTest.cpp +++ unittests/Support/DebugCounterTest.cpp @@ -11,6 +11,13 @@ #include "gtest/gtest.h" #include + +#if LLVM_ENABLE_THREADS +#include +#include +#include +#endif + using namespace llvm; #ifndef NDEBUG @@ -39,4 +46,46 @@ DebugCounter::setCounterValue(TestCounter, 100); EXPECT_FALSE(DebugCounter::shouldExecute(TestCounter)); } -#endif + +#if LLVM_ENABLE_THREADS +TEST(DebugCounterTest, MultipleThreads) { + constexpr int ThreadCount = 3; + constexpr int Iterations = 1000; + + std::mutex Mut; + std::condition_variable Cond; + int ThreadsWaiting = 0; + bool StartRunning = false; + + auto Run = [&]() { + { + std::unique_lock Lock(Mut); + ++ThreadsWaiting; + Cond.notify_all(); + Cond.wait(Lock, [&]() { return StartRunning; }); + } + for (int I = 0; I < Iterations; ++I) + DebugCounter::shouldExecute(TestCounter); + }; + + // This test is here to make sure TSAN does not show warnings about data races. + // DebugCounter should not be used in multi-threaded environments. + std::vector Threads; + for (int I = 0; I < ThreadCount; ++I) { + Threads.emplace_back(Run); + } + + { + std::unique_lock Lock(Mut); + // Wait for the threads to start. + Cond.wait(Lock, [&]() { return ThreadsWaiting == ThreadCount; }); + StartRunning = true; + // Indicate they can start running. + Cond.notify_all(); + } + + for (auto & T : Threads) + T.join(); +} +#endif // LLVM_ENABLE_THREADS +#endif // NDEBUG