[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