[PATCH] D36847: [Support] Add "reference-counted" Timer
Justin Bogner via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 17 15:07:21 PDT 2017
Brian Gesiak via Phabricator via llvm-commits
<llvm-commits at lists.llvm.org> writes:
> modocache created this revision.
>
> In Clang's `lib/CodeGen/CodeGenAction.cpp`, a timer is used to measure
> the amount of time spent generating LLVM IR. The timer is started and
> stopped in a method, `BackendConsumer::HandleTopLevelDecl`, that is called
> recursively. `llvm::Timer` does not allow starting a timer twice, so to
> prevent a runtime assertion that would occur if the timer is started
> a second time as the method recurses, it's guarded by a "reference
> count" variable: if the reference count is incremented from 0 to 1, the
> timer is started. Subsequent calls to start the timer increment the
> reference count, but do not call `startTimer()`. `stopTimer()` is called when
> the reference count goes from 1 to 0.
>
> This pattern is useful when timing any recursive method, such as in
> https://reviews.llvm.org/D36492.
>
> Add a `RefCntTimer` that can be used for situations such as these.
> Unlike the base `Timer` class, multiple calls to `startTimer()` are
> fine, as long as `stopTimer()` is called an equal number of times.
Would a name like `ReentrantTimer` be clearer?
> https://reviews.llvm.org/D36847
>
> Files:
> include/llvm/Support/Timer.h
> lib/Support/Timer.cpp
> unittests/Support/TimerTest.cpp
>
> 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
> 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: 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
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list