Index: include/llvm/Support/Timer.h =================================================================== --- include/llvm/Support/Timer.h +++ include/llvm/Support/Timer.h @@ -80,6 +80,7 @@ std::string Description; ///< Description of this time variable. bool Running; ///< Is the timer currently running? bool Triggered; ///< Has the timer ever been triggered? + unsigned RefCount = 0; ///< 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. @@ -117,12 +118,30 @@ /// 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 @@ -135,13 +135,29 @@ StartTime = TimeRecord::getCurrentTime(true); } +void Timer::startReentrantTimer() { + if (RefCount == 0) startTimer(); + RefCount += 1; +} + void Timer::stopTimer() { assert(Running && "Cannot stop a paused timer"); + assert(RefCount == 0 && + "startReentrantTimer must be matched with the same number of calls " + "to stopReentrantTimer"); Running = false; Time += TimeRecord::getCurrentTime(false); Time -= StartTime; } +void Timer::stopReentrantTimer() { + assert(RefCount > 0 && + "stopReentrantTimer cannot be called more times than " + "startReentrantTimer"); + RefCount -= 1; + if (RefCount == 0) stopTimer(); +} + void Timer::clear() { Running = Triggered = false; 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