Index: include/llvm/Support/Timer.h =================================================================== --- include/llvm/Support/Timer.h +++ include/llvm/Support/Timer.h @@ -98,7 +98,7 @@ assert(!TG && !T.TG && "Can only assign uninit timers"); return *this; } - ~Timer(); + virtual ~Timer(); /// Create an uninitialized timer, client must use 'init'. explicit Timer() {} @@ -118,10 +118,10 @@ /// Start the timer running. Time between calls to startTimer/stopTimer is /// counted by the Timer class. Note that these calls must be correctly /// paired. - void startTimer(); + virtual void startTimer(); /// Stop the timer. - void stopTimer(); + virtual void stopTimer(); /// Clear the timer state. void clear(); @@ -133,6 +133,26 @@ friend class TimerGroup; }; +/// Whereas the Timer class enforces that calls to startTimer must be followed +/// by a call to stopTimer, this "reference-counted" RefCntTimer allows +/// multiple calls to startTimer, as long as they are paired with the same +/// number of calls to stopTimer. This is useful when, for example, timing a +/// function that calls itself recursively. +class RefCntTimer : public Timer { + unsigned RefCount = 0; +public: + using Timer::Timer; + + /// Start the timer running. Time between calls to startTimer/stopTimer is + /// counted by the RefCntTimer class. You may call startTimer multiple times + /// in succession, but stopTimer must also eventually be called the same + /// number of times. + void startTimer(); + + /// Stop the timer. + void stopTimer(); +}; + /// The TimeRegion class is used as a helper class to call the startTimer() and /// stopTimer() methods of the Timer class. When the object is constructed, it /// starts the timer specified as its argument. When it is destroyed, it stops Index: lib/Support/Timer.cpp =================================================================== --- lib/Support/Timer.cpp +++ lib/Support/Timer.cpp @@ -142,6 +142,17 @@ Time -= StartTime; } +void RefCntTimer::startTimer() { + if (RefCount == 0) Timer::startTimer(); + RefCount += 1; +} + +void RefCntTimer::stopTimer() { + assert(RefCount != 0 && "Cannot stop a reference counted timer more times than it has been started"); + RefCount -= 1; + if (RefCount == 0) Timer::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: + RefCntTimer T; + Recurser() : T("RCT1", "RCT1") {} + void Recurse(unsigned Depth) { + T.startTimer(); + if (Depth < 1) + Recurse(Depth + 1); + T.stopTimer(); + } +}; + +TEST(RefCntTimer, Recurse) { + 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