Index: include/llvm/Support/Timer.h =================================================================== --- include/llvm/Support/Timer.h +++ include/llvm/Support/Timer.h @@ -78,8 +78,8 @@ TimeRecord StartTime; ///< The time startTimer() was last called. std::string Name; ///< The name of this time variable. std::string Description; ///< Description of this time variable. - bool Running; ///< Is the timer currently running? bool Triggered; ///< Has the timer ever been triggered? + unsigned StartCount; ///< Number of times started without being stopped. TimerGroup *TG = nullptr; ///< The TimerGroup this Timer is in. Timer **Prev; ///< Pointer to \p Next of previous timer in group. @@ -110,19 +110,37 @@ bool isInitialized() const { return TG != nullptr; } /// Check if the timer is currently running. - bool isRunning() const { return Running; } + bool isRunning() const { return StartCount > 0; } /// Check if startTimer() has ever been called on this timer. bool hasTriggered() const { return Triggered; } /// Start the timer running. Time between calls to startTimer/stopTimer is /// counted by the Timer class. Note that these calls must be correctly - /// paired. + /// paired. It is an error to call this method on a Timer that has been + /// started via a call to startReentrantTimer. void startTimer(); - /// Stop the timer. + /// Start the tumer running or, if it is already running from a prior call to + /// startRentrantTimer, increase the number of times stopReentrantTimer must + /// be called. Any number of calls to startReentrantTimer are allowed, so + /// long as the same number of calls are eventually made to + /// stopReentrantTimer. Time between the first call to startReentrantTimer + /// and the last call to stopReentrantTimer is counted by the Timer class. + /// It is an error to call this method on a Timer that has been started via + /// a call to startTimer. + void startReentrantTimer(); + + /// Stop the timer. It is an error to call this method directly on a timer + /// that has been started with startReentrantTimer. void stopTimer(); + /// Stop the timer or, if startReentrantTimer has been called more than once, + /// decrement the number of times stopReentrantTimer must be called in order + /// to stop the timer. It is an error to call this method without ever having + /// called startReentrantTimer. + void stopReentrantTimer(); + /// Clear the timer state. void clear(); Index: lib/Support/Timer.cpp =================================================================== --- lib/Support/Timer.cpp +++ lib/Support/Timer.cpp @@ -94,7 +94,8 @@ assert(!TG && "Timer already initialized"); this->Name.assign(Name.begin(), Name.end()); this->Description.assign(Description.begin(), Description.end()); - Running = Triggered = false; + Triggered = false; + StartCount = 0; TG = &tg; TG->addTimer(*this); } @@ -130,20 +131,42 @@ } void Timer::startTimer() { - assert(!Running && "Cannot start a running timer"); - Running = Triggered = true; + assert(!isRunning() && "Cannot start a running timer"); + Triggered = true; + StartCount += 1; StartTime = TimeRecord::getCurrentTime(true); } +void Timer::startReentrantTimer() { + if (StartCount == 0) + startTimer(); + else + StartCount += 1; +} + void Timer::stopTimer() { - assert(Running && "Cannot stop a paused timer"); - Running = false; + assert(isRunning() && "Cannot stop a paused timer"); + assert(StartCount == 1 && + "startReentrantTimer must be matched with the same number of calls " + "to stopReentrantTimer"); + StartCount -= 1; Time += TimeRecord::getCurrentTime(false); Time -= StartTime; } +void Timer::stopReentrantTimer() { + assert(StartCount > 0 && + "stopReentrantTimer cannot be called more times than " + "startReentrantTimer"); + if (StartCount == 1) + stopTimer(); + else + StartCount -= 1; +} + void Timer::clear() { - Running = Triggered = false; + Triggered = false; + StartCount = 0; Time = StartTime = TimeRecord(); } Index: unittests/Support/TimerTest.cpp =================================================================== --- unittests/Support/TimerTest.cpp +++ unittests/Support/TimerTest.cpp @@ -62,4 +62,26 @@ EXPECT_FALSE(T1.hasTriggered()); } +class Recurser { +public: + Timer T; + Recurser() : T("RCT1", "RCT1") {} + void Recurse(unsigned Depth) { + T.startReentrantTimer(); + if (Depth < 1) + Recurse(Depth + 1); + T.stopReentrantTimer(); + } +}; + +TEST(Timer, Reentrant) { + Recurser R; + ASSERT_FALSE(R.T.hasTriggered()); + ASSERT_FALSE(R.T.isRunning()); + + R.Recurse(0); + ASSERT_TRUE(R.T.hasTriggered()); + ASSERT_FALSE(R.T.isRunning()); +} + } // end anon namespace