152e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET/*
252e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * Copyright (C) 2015 The Android Open Source Project
352e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET *
452e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * Licensed under the Apache License, Version 2.0 (the "License");
552e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * you may not use this file except in compliance with the License.
652e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * You may obtain a copy of the License at
752e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET *
852e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET *      http://www.apache.org/licenses/LICENSE-2.0
952e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET *
1052e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * Unless required by applicable law or agreed to in writing, software
1152e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * distributed under the License is distributed on an "AS IS" BASIS,
1252e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * See the License for the specific language governing permissions and
1452e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET * limitations under the License.
1552e5b99983c1f7ff0b9a1f3b4b80d779073b21c8Bertrand SIMONNET */
16be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
17be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha// Timer - class that provides timer tracking.
18be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
19be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha#ifndef METRICS_TIMER_H_
20be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha#define METRICS_TIMER_H_
21be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
226c9fbb9a3aaee50302d54de8f27fc712c836b9eaBertrand SIMONNET#include <memory>
23be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha#include <string>
24be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
25652d6971b19c2db2d3dcd1f8db36abadfc22079eBen Chan#include <base/macros.h>
262e6543ddad0b7d64697bb2326a5cfd1ab835a489Ben Chan#include <base/time/time.h>
27be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha#include <gtest/gtest_prod.h>  // for FRIEND_TEST
28be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
29be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rochaclass MetricsLibraryInterface;
30be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
31be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rochanamespace chromeos_metrics {
32be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
33be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rochaclass TimerInterface {
34be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha public:
35be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual ~TimerInterface() {}
36be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
37be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool Start() = 0;
38be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool Stop() = 0;
39be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool Reset() = 0;
40be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool HasStarted() const = 0;
41be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha};
42be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
43be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha// Wrapper for calls to the system clock.
44be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rochaclass ClockWrapper {
45be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha public:
46be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  ClockWrapper() {}
47be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual ~ClockWrapper() {}
48be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
49be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Returns the current time from the system.
50be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual base::TimeTicks GetCurrentTime() const;
51be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
52be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha private:
53be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  DISALLOW_COPY_AND_ASSIGN(ClockWrapper);
54be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha};
55be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
56be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha// Implements a Timer.
57be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rochaclass Timer : public TimerInterface {
58be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha public:
59be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  Timer();
60be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual ~Timer() {}
61be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
62be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Starts the timer. If a timer is already running, also resets current
63be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // timer. Always returns true.
64be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool Start();
65be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
66be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Stops the timer and calculates the total time elapsed between now and when
67be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Start() was called. Note that this method needs a prior call to Start().
68be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Otherwise, it fails (returns false).
69be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool Stop();
70be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
710672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  // Pauses a timer.  If the timer is stopped, this call starts the timer in
720672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  // the paused state. Fails (returns false) if the timer is already paused.
730672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  virtual bool Pause();
740672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync
750672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  // Restarts a paused timer (or starts a stopped timer). This method fails
760672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  // (returns false) if the timer is already running; otherwise, returns true.
770672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  virtual bool Resume();
780672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync
79be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Resets the timer, erasing the current duration being tracked. Always
80be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // returns true.
81be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool Reset();
82be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
83be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Returns whether the timer has started or not.
84be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool HasStarted() const;
85be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
86be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Stores the current elapsed time in |elapsed_time|. If timer is stopped,
87be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // stores the elapsed time from when Stop() was last called. Otherwise,
88be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // calculates and stores the elapsed time since the last Start().
89be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Returns false if the timer was never Start()'ed or if called with a null
90be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // pointer argument.
91be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool GetElapsedTime(base::TimeDelta* elapsed_time) const;
92be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
93be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha private:
940672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  enum TimerState { kTimerStopped, kTimerRunning, kTimerPaused };
95be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  friend class TimerTest;
96be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  friend class TimerReporterTest;
970672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerReporterTest, StartStopReport);
980672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, InvalidElapsedTime);
990672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, InvalidStop);
1000672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, PauseResumeStop);
1010672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, PauseStartStopResume);
1020672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, PauseStop);
103be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  FRIEND_TEST(TimerTest, Reset);
1040672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, ReStart);
1050672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, ResumeStartStopPause);
106be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  FRIEND_TEST(TimerTest, SeparatedTimers);
1070672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, StartPauseResumePauseResumeStop);
1080672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, StartPauseResumePauseStop);
1090672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, StartPauseResumeStop);
1100672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, StartPauseStop);
1110672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, StartResumeStop);
1120672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  FRIEND_TEST(TimerTest, StartStop);
113be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
114be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Elapsed time of the last use of the timer.
115be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  base::TimeDelta elapsed_time_;
116be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
117be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Starting time value.
118be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  base::TimeTicks start_time_;
119be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
1200672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  // Whether the timer is running, stopped, or paused.
1210672655fa66deb6dd772a584b82e2c5bbf4cf847repo sync  TimerState timer_state_;
122be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
123be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Wrapper for the calls to the system clock.
1246c9fbb9a3aaee50302d54de8f27fc712c836b9eaBertrand SIMONNET  std::unique_ptr<ClockWrapper> clock_wrapper_;
125be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
126be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  DISALLOW_COPY_AND_ASSIGN(Timer);
127be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha};
128be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
129be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha// Extends the Timer class to report the elapsed time in milliseconds through
130be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha// the UMA metrics library.
131be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rochaclass TimerReporter : public Timer {
132be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha public:
133be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Initializes the timer by providing a |histogram_name| to report to with
134be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // |min|, |max| and |num_buckets| attributes for the histogram.
135be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  TimerReporter(const std::string& histogram_name, int min, int max,
136be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha                int num_buckets);
137be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual ~TimerReporter() {}
138be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
139be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Sets the metrics library used by all instances of this class.
140be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  static void set_metrics_lib(MetricsLibraryInterface* metrics_lib) {
141be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha    metrics_lib_ = metrics_lib;
142be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  }
143be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
144be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Reports the current duration to UMA, in milliseconds. Returns false if
1451bc9ce0294a0107b6d087e73164eb786cc658704repo sync  // there is nothing to report, e.g. a metrics library is not set.
146be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  virtual bool ReportMilliseconds() const;
147be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
148be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  // Accessor methods.
149be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  const std::string& histogram_name() const { return histogram_name_; }
150be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  int min() const { return min_; }
151be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  int max() const { return max_; }
152be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  int num_buckets() const { return num_buckets_; }
153be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
154be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha private:
155be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  friend class TimerReporterTest;
156be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  FRIEND_TEST(TimerReporterTest, StartStopReport);
157be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  FRIEND_TEST(TimerReporterTest, InvalidReport);
158be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
159be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  static MetricsLibraryInterface* metrics_lib_;
160be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  std::string histogram_name_;
161be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  int min_;
162be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  int max_;
163be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  int num_buckets_;
164be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
165be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha  DISALLOW_COPY_AND_ASSIGN(TimerReporter);
166be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha};
167be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
168be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha}  // namespace chromeos_metrics
169be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha
170be388f301b9fef2e4ecd0cd9612dfe9216b5b266Bruno Rocha#endif  // METRICS_TIMER_H_
171