[Support] Allow multiple paired calls to {start,stop}Timer()
authorVedant Kumar <vsk@apple.com>
Tue, 22 Dec 2015 17:36:17 +0000 (17:36 +0000)
committerVedant Kumar <vsk@apple.com>
Tue, 22 Dec 2015 17:36:17 +0000 (17:36 +0000)
Differential Revision: http://reviews.llvm.org/D15619

Reviewed-by: rafael
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256258 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/Timer.h
lib/Support/Timer.cpp
unittests/Support/CMakeLists.txt
unittests/Support/TimerTest.cpp [new file with mode: 0644]

index 2d9b0e2..499fe7b 100644 (file)
@@ -62,8 +62,8 @@ public:
     MemUsed    -= RHS.MemUsed;
   }
 
-  /// print - Print the current timer to standard error, and reset the "Started"
-  /// flag.
+  /// Print the current time record to \p OS, with a breakdown showing
+  /// contributions to the \p Total time record.
   void print(const TimeRecord &Total, raw_ostream &OS) const;
 };
 
@@ -76,9 +76,11 @@ public:
 /// if they are never started.
 ///
 class Timer {
-  TimeRecord Time;
+  TimeRecord Time;       // The total time captured
+  TimeRecord StartTime;  // The time startTimer() was last called
   std::string Name;      // The name of this time variable.
-  bool Started;          // Has this time variable ever been started?
+  bool Running;          // Is the timer currently running?
+  bool Triggered;        // Has the timer ever been triggered?
   TimerGroup *TG;        // The TimerGroup this Timer is in.
 
   Timer **Prev, *Next;   // Doubly linked list of timers in the group.
@@ -102,16 +104,23 @@ public:
   const std::string &getName() const { return Name; }
   bool isInitialized() const { return TG != nullptr; }
 
-  /// startTimer - Start the timer running.  Time between calls to
-  /// startTimer/stopTimer is counted by the Timer class.  Note that these calls
-  /// must be correctly paired.
-  ///
+  /// 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.
   void startTimer();
 
-  /// stopTimer - Stop the timer.
-  ///
+  /// Stop the timer.
   void stopTimer();
 
+  /// Clear the timer state.
+  void clear();
+
+  /// Return the duration for which this timer has been running.
+  TimeRecord getTotalTime() const { return Time; }
+
 private:
   friend class TimerGroup;
 };
index f8ab214..414f559 100644 (file)
@@ -102,7 +102,7 @@ void Timer::init(StringRef N) {
 void Timer::init(StringRef N, TimerGroup &tg) {
   assert(!TG && "Timer already initialized");
   Name.assign(N.begin(), N.end());
-  Started = false;
+  Running = Triggered = false;
   TG = &tg;
   TG->addTimer(*this);
 }
@@ -135,25 +135,22 @@ TimeRecord TimeRecord::getCurrentTime(bool Start) {
   return Result;
 }
 
-static ManagedStatic<std::vector<Timer*> > ActiveTimers;
-
 void Timer::startTimer() {
-  Started = true;
-  ActiveTimers->push_back(this);
-  Time -= TimeRecord::getCurrentTime(true);
+  assert(!Running && "Cannot start a running timer");
+  Running = Triggered = true;
+  StartTime = TimeRecord::getCurrentTime(true);
 }
 
 void Timer::stopTimer() {
+  assert(Running && "Cannot stop a paused timer");
+  Running = false;
   Time += TimeRecord::getCurrentTime(false);
+  Time -= StartTime;
+}
 
-  if (ActiveTimers->back() == this) {
-    ActiveTimers->pop_back();
-  } else {
-    std::vector<Timer*>::iterator I =
-      std::find(ActiveTimers->begin(), ActiveTimers->end(), this);
-    assert(I != ActiveTimers->end() && "stop but no startTimer?");
-    ActiveTimers->erase(I);
-  }
+void Timer::clear() {
+  Running = Triggered = false;
+  Time = StartTime = TimeRecord();
 }
 
 static void printVal(double Val, double Total, raw_ostream &OS) {
@@ -271,7 +268,7 @@ void TimerGroup::removeTimer(Timer &T) {
   sys::SmartScopedLock<true> L(*TimerLock);
   
   // If the timer was started, move its data to TimersToPrint.
-  if (T.Started)
+  if (T.hasTriggered())
     TimersToPrint.emplace_back(T.Time, T.Name);
 
   T.TG = nullptr;
@@ -357,12 +354,11 @@ void TimerGroup::print(raw_ostream &OS) {
   // See if any of our timers were started, if so add them to TimersToPrint and
   // reset them.
   for (Timer *T = FirstTimer; T; T = T->Next) {
-    if (!T->Started) continue;
+    if (!T->hasTriggered()) continue;
     TimersToPrint.emplace_back(T->Time, T->Name);
     
     // Clear out the time.
-    T->Started = 0;
-    T->Time = TimeRecord();
+    T->clear();
   }
 
   // If any timers were started, print the group.
index 9bd6857..3ab98d5 100644 (file)
@@ -42,6 +42,7 @@ add_llvm_unittest(SupportTests
   TargetRegistry.cpp
   ThreadLocalTest.cpp
   ThreadPool.cpp
+  TimerTest.cpp
   TimeValueTest.cpp
   TrailingObjectsTest.cpp
   UnicodeTest.cpp
diff --git a/unittests/Support/TimerTest.cpp b/unittests/Support/TimerTest.cpp
new file mode 100644 (file)
index 0000000..ac7c52d
--- /dev/null
@@ -0,0 +1,49 @@
+//===- unittests/TimerTest.cpp - Timer tests ------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Timer.h"
+#include "gtest/gtest.h"
+#include <chrono>
+#include <thread>
+
+using namespace llvm;
+
+namespace {
+
+TEST(Timer, Additivity) {
+  Timer T1("T1");
+
+  EXPECT_TRUE(T1.isInitialized());
+
+  T1.startTimer();
+  T1.stopTimer();
+  auto TR1 = T1.getTotalTime();
+
+  T1.startTimer();
+  std::this_thread::sleep_for(std::chrono::milliseconds(1));
+  T1.stopTimer();
+  auto TR2 = T1.getTotalTime();
+
+  EXPECT_TRUE(TR1 < TR2);
+}
+
+TEST(Timer, CheckIfTriggered) {
+  Timer T1("T1");
+
+  EXPECT_FALSE(T1.hasTriggered());
+  T1.startTimer();
+  EXPECT_TRUE(T1.hasTriggered());
+  T1.stopTimer();
+  EXPECT_TRUE(T1.hasTriggered());
+
+  T1.clear();
+  EXPECT_FALSE(T1.hasTriggered());
+}
+
+} // end anon namespace