Added a timer-based report to the metrics library.
Timer encapsulates a timer with basic functionality. TimerReporter subclasses it for also sending UMA reports. BUG=chromium-os:18800 TEST=Unit test 'timer_test' has been included Change-Id: I9de9a2a7388721ba1476fe706a8d12788d2176ad Reviewed-on: http://gerrit.chromium.org/gerrit/5161 Reviewed-by: Gaurav Shah <gauravsh@chromium.org> Reviewed-by: Darin Petkov <petkov@chromium.org> Tested-by: Bruno Pontes Soares Rocha <bpontes@google.com> Reviewed-by: Bruno Pontes Soares Rocha <bpontes@google.com>
This commit is contained in:
parent
0e5debf2d5
commit
be388f301b
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
|
||||
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
#
|
||||
|
@ -17,10 +17,14 @@ LIB = libmetrics.a
|
|||
SHAREDLIB = libmetrics.so
|
||||
LIB_TEST = metrics_library_test
|
||||
COUNTER_TEST = counter_test
|
||||
TIMER_TEST = timer_test
|
||||
|
||||
TESTCOUNTER_OBJS = \
|
||||
counter.o \
|
||||
counter_test.o
|
||||
TESTTIMER_OBJS = \
|
||||
timer.o \
|
||||
timer_test.o
|
||||
CLIENT_OBJS = \
|
||||
metrics_client.o
|
||||
DAEMON_OBJS = \
|
||||
|
@ -33,11 +37,13 @@ TESTDAEMON_OBJS = \
|
|||
metrics_daemon_test.o
|
||||
LIB_OBJS = \
|
||||
c_metrics_library.o \
|
||||
metrics_library.o
|
||||
metrics_library.o \
|
||||
timer.o
|
||||
TESTLIB_OBJS = \
|
||||
metrics_library_test.o
|
||||
|
||||
TESTCOUNTER_LIBS = -lgmock -lgtest -lbase -lrt -lpthread -lglib-2.0
|
||||
TESTTIMER_LIBS = -lgmock -lgtest -lbase -lrt -lpthread -lglib-2.0
|
||||
DAEMON_LDFLAGS = $(LDFLAGS) $(LDCONFIG) -lrt -lbase -lpthread -lgflags \
|
||||
-lglib-2.0 -lrootdev -lpolicy
|
||||
TESTDAEMON_LIBS = -lgmock -lgtest
|
||||
|
@ -46,7 +52,7 @@ POLICY_LIBS = -lpolicy
|
|||
|
||||
all: $(LIB) $(SHAREDLIB) $(CLIENT) $(DAEMON)
|
||||
|
||||
tests: $(COUNTER_TEST) $(DAEMON_TEST) $(LIB_TEST)
|
||||
tests: $(COUNTER_TEST) $(DAEMON_TEST) $(LIB_TEST) $(TIMER_TEST)
|
||||
|
||||
$(CLIENT): $(CLIENT_OBJS) $(SHAREDLIB)
|
||||
$(CXX) $(LDFLAGS) $(POLICY_LIBS) -lrt $^ -o $@
|
||||
|
@ -54,6 +60,9 @@ $(CLIENT): $(CLIENT_OBJS) $(SHAREDLIB)
|
|||
$(COUNTER_TEST): $(TESTCOUNTER_OBJS)
|
||||
$(CXX) -o $@ $^ $(TESTCOUNTER_LIBS)
|
||||
|
||||
$(TIMER_TEST): $(TESTTIMER_OBJS)
|
||||
$(CXX) -o $@ $^ $(TESTTIMER_LIBS)
|
||||
|
||||
$(DAEMON): $(DAEMON_OBJS) $(SHAREDLIB)
|
||||
$(CXX) -o $@ $^ $(DAEMON_LDFLAGS)
|
||||
|
||||
|
@ -74,4 +83,4 @@ $(LIB_TEST): $(TESTLIB_OBJS) $(SHAREDLIB)
|
|||
|
||||
clean:
|
||||
rm -f $(CLIENT) $(DAEMON) $(LIB) $(SHAREDLIB) *.o
|
||||
rm -f $(COUNTER_TEST) $(DAEMON_TEST) $(LIB_TEST)
|
||||
rm -f $(COUNTER_TEST) $(DAEMON_TEST) $(LIB_TEST) $(TIMER_TEST)
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <base/memory/scoped_ptr.h>
|
||||
#include <base/time.h>
|
||||
|
||||
#include "metrics_library.h"
|
||||
|
||||
namespace chromeos_metrics {
|
||||
|
||||
base::TimeTicks ClockWrapper::GetCurrentTime() const {
|
||||
return base::TimeTicks::Now();
|
||||
}
|
||||
|
||||
Timer::Timer()
|
||||
: is_started_(false),
|
||||
clock_wrapper_(new ClockWrapper()) {}
|
||||
|
||||
bool Timer::Start() {
|
||||
start_time_ = clock_wrapper_->GetCurrentTime();
|
||||
is_started_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Timer::Stop() {
|
||||
// Check if the timer has been started.
|
||||
if (!is_started_) return false;
|
||||
is_started_ = false;
|
||||
elapsed_time_ = clock_wrapper_->GetCurrentTime() - start_time_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Timer::Reset() {
|
||||
is_started_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Timer::HasStarted() const {
|
||||
return is_started_;
|
||||
}
|
||||
|
||||
bool Timer::GetElapsedTime(base::TimeDelta* elapsed_time) const {
|
||||
if (start_time_.is_null() || !elapsed_time) return false;
|
||||
if (is_started_) {
|
||||
*elapsed_time = clock_wrapper_->GetCurrentTime() - start_time_;
|
||||
} else {
|
||||
*elapsed_time = elapsed_time_;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
MetricsLibraryInterface* TimerReporter::metrics_lib_ = NULL;
|
||||
|
||||
TimerReporter::TimerReporter(const std::string& histogram_name, int min,
|
||||
int max, int num_buckets)
|
||||
: histogram_name_(histogram_name),
|
||||
min_(min),
|
||||
max_(max),
|
||||
num_buckets_(num_buckets) {}
|
||||
|
||||
bool TimerReporter::ReportMilliseconds() const {
|
||||
base::TimeDelta elapsed_time;
|
||||
if (!metrics_lib_ || !GetElapsedTime(&elapsed_time)) return false;
|
||||
return metrics_lib_->SendToUMA(histogram_name_,
|
||||
elapsed_time.InMilliseconds(),
|
||||
min_,
|
||||
max_,
|
||||
num_buckets_);
|
||||
}
|
||||
|
||||
} // namespace chromeos_metrics
|
|
@ -0,0 +1,140 @@
|
|||
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Timer - class that provides timer tracking.
|
||||
|
||||
#ifndef METRICS_TIMER_H_
|
||||
#define METRICS_TIMER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <base/memory/scoped_ptr.h>
|
||||
#include <base/time.h>
|
||||
#include <gtest/gtest_prod.h> // for FRIEND_TEST
|
||||
|
||||
class MetricsLibraryInterface;
|
||||
|
||||
namespace chromeos_metrics {
|
||||
|
||||
class TimerInterface {
|
||||
public:
|
||||
virtual ~TimerInterface() {}
|
||||
|
||||
virtual bool Start() = 0;
|
||||
virtual bool Stop() = 0;
|
||||
virtual bool Reset() = 0;
|
||||
virtual bool HasStarted() const = 0;
|
||||
};
|
||||
|
||||
// Wrapper for calls to the system clock.
|
||||
class ClockWrapper {
|
||||
public:
|
||||
ClockWrapper() {}
|
||||
virtual ~ClockWrapper() {}
|
||||
|
||||
// Returns the current time from the system.
|
||||
virtual base::TimeTicks GetCurrentTime() const;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ClockWrapper);
|
||||
};
|
||||
|
||||
// Implements a Timer.
|
||||
class Timer : public TimerInterface {
|
||||
public:
|
||||
Timer();
|
||||
virtual ~Timer() {}
|
||||
|
||||
// Starts the timer. If a timer is already running, also resets current
|
||||
// timer. Always returns true.
|
||||
virtual bool Start();
|
||||
|
||||
// Stops the timer and calculates the total time elapsed between now and when
|
||||
// Start() was called. Note that this method needs a prior call to Start().
|
||||
// Otherwise, it fails (returns false).
|
||||
virtual bool Stop();
|
||||
|
||||
// Resets the timer, erasing the current duration being tracked. Always
|
||||
// returns true.
|
||||
virtual bool Reset();
|
||||
|
||||
// Returns whether the timer has started or not.
|
||||
virtual bool HasStarted() const;
|
||||
|
||||
// Stores the current elapsed time in |elapsed_time|. If timer is stopped,
|
||||
// stores the elapsed time from when Stop() was last called. Otherwise,
|
||||
// calculates and stores the elapsed time since the last Start().
|
||||
// Returns false if the timer was never Start()'ed or if called with a null
|
||||
// pointer argument.
|
||||
virtual bool GetElapsedTime(base::TimeDelta* elapsed_time) const;
|
||||
|
||||
private:
|
||||
friend class TimerTest;
|
||||
friend class TimerReporterTest;
|
||||
FRIEND_TEST(TimerTest, StartStop);
|
||||
FRIEND_TEST(TimerTest, ReStart);
|
||||
FRIEND_TEST(TimerTest, Reset);
|
||||
FRIEND_TEST(TimerTest, SeparatedTimers);
|
||||
FRIEND_TEST(TimerTest, InvalidStop);
|
||||
FRIEND_TEST(TimerTest, InvalidElapsedTime);
|
||||
FRIEND_TEST(TimerReporterTest, StartStopReport);
|
||||
|
||||
// Elapsed time of the last use of the timer.
|
||||
base::TimeDelta elapsed_time_;
|
||||
|
||||
// Starting time value.
|
||||
base::TimeTicks start_time_;
|
||||
|
||||
// Whether the timer has started or not.
|
||||
bool is_started_;
|
||||
|
||||
// Wrapper for the calls to the system clock.
|
||||
scoped_ptr<ClockWrapper> clock_wrapper_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Timer);
|
||||
};
|
||||
|
||||
// Extends the Timer class to report the elapsed time in milliseconds through
|
||||
// the UMA metrics library.
|
||||
class TimerReporter : public Timer {
|
||||
public:
|
||||
// Initializes the timer by providing a |histogram_name| to report to with
|
||||
// |min|, |max| and |num_buckets| attributes for the histogram.
|
||||
TimerReporter(const std::string& histogram_name, int min, int max,
|
||||
int num_buckets);
|
||||
virtual ~TimerReporter() {}
|
||||
|
||||
// Sets the metrics library used by all instances of this class.
|
||||
static void set_metrics_lib(MetricsLibraryInterface* metrics_lib) {
|
||||
metrics_lib_ = metrics_lib;
|
||||
}
|
||||
|
||||
// Reports the current duration to UMA, in milliseconds. Returns false if
|
||||
// there is nothing to report, i.e. the timer was not started or a metrics
|
||||
// library is not set.
|
||||
virtual bool ReportMilliseconds() const;
|
||||
|
||||
// Accessor methods.
|
||||
const std::string& histogram_name() const { return histogram_name_; }
|
||||
int min() const { return min_; }
|
||||
int max() const { return max_; }
|
||||
int num_buckets() const { return num_buckets_; }
|
||||
|
||||
private:
|
||||
friend class TimerReporterTest;
|
||||
FRIEND_TEST(TimerReporterTest, StartStopReport);
|
||||
FRIEND_TEST(TimerReporterTest, InvalidReport);
|
||||
|
||||
static MetricsLibraryInterface* metrics_lib_;
|
||||
std::string histogram_name_;
|
||||
int min_;
|
||||
int max_;
|
||||
int num_buckets_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TimerReporter);
|
||||
};
|
||||
|
||||
} // namespace chromeos_metrics
|
||||
|
||||
#endif // METRICS_TIMER_H_
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef METRICS_TIMER_MOCK_H_
|
||||
#define METRICS_TIMER_MOCK_H_
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <base/basictypes.h>
|
||||
#include <base/time.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
namespace chromeos_metrics {
|
||||
|
||||
class TimerMock : public Timer {
|
||||
public:
|
||||
MOCK_METHOD0(Start, bool());
|
||||
MOCK_METHOD0(Stop, bool());
|
||||
MOCK_METHOD0(Reset, bool());
|
||||
MOCK_CONST_METHOD0(HasStarted, bool());
|
||||
MOCK_CONST_METHOD1(GetElapsedTime, bool(base::TimeDelta* elapsed_time));
|
||||
};
|
||||
|
||||
class TimerReporterMock : public TimerReporter {
|
||||
public:
|
||||
MOCK_METHOD0(Start, bool());
|
||||
MOCK_METHOD0(Stop, bool());
|
||||
MOCK_METHOD0(Reset, bool());
|
||||
MOCK_CONST_METHOD0(HasStarted, bool());
|
||||
MOCK_CONST_METHOD0(GetElapsedTime, base::TimeDelta());
|
||||
MOCK_CONST_METHOD0(ReportMilliseconds, bool());
|
||||
};
|
||||
|
||||
class ClockWrapperMock : public ClockWrapper {
|
||||
public:
|
||||
MOCK_CONST_METHOD0(GetCurrentTime, base::TimeTicks());
|
||||
};
|
||||
|
||||
} // namespace chromeos_metrics
|
||||
|
||||
#endif // METRICS_TIMER_MOCK_H_
|
|
@ -0,0 +1,162 @@
|
|||
// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <base/memory/scoped_ptr.h>
|
||||
#include <base/time.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "metrics_library_mock.h"
|
||||
#include "timer.h"
|
||||
#include "timer_mock.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Return;
|
||||
|
||||
namespace chromeos_metrics {
|
||||
|
||||
class TimerTest : public testing::Test {
|
||||
public:
|
||||
TimerTest() : clock_wrapper_mock_(new ClockWrapperMock()) {}
|
||||
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
EXPECT_FALSE(timer_.is_started_);
|
||||
stime += base::TimeDelta::FromMilliseconds(1500);
|
||||
etime += base::TimeDelta::FromMilliseconds(3000);
|
||||
}
|
||||
|
||||
virtual void TearDown() {}
|
||||
|
||||
Timer timer_;
|
||||
scoped_ptr<ClockWrapperMock> clock_wrapper_mock_;
|
||||
base::TimeTicks stime, etime;
|
||||
};
|
||||
|
||||
TEST_F(TimerTest, StartStop) {
|
||||
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
|
||||
.WillOnce(Return(stime))
|
||||
.WillOnce(Return(etime));
|
||||
timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
|
||||
ASSERT_TRUE(timer_.Start());
|
||||
ASSERT_TRUE(timer_.start_time_ == stime);
|
||||
ASSERT_TRUE(timer_.HasStarted());
|
||||
ASSERT_TRUE(timer_.Stop());
|
||||
ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), 1500);
|
||||
ASSERT_FALSE(timer_.HasStarted());
|
||||
}
|
||||
|
||||
TEST_F(TimerTest, ReStart) {
|
||||
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
|
||||
.WillOnce(Return(stime))
|
||||
.WillOnce(Return(etime));
|
||||
timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
|
||||
timer_.Start();
|
||||
base::TimeTicks buffer = timer_.start_time_;
|
||||
timer_.Start();
|
||||
ASSERT_FALSE(timer_.start_time_ == buffer);
|
||||
}
|
||||
|
||||
TEST_F(TimerTest, Reset) {
|
||||
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
|
||||
.WillOnce(Return(stime));
|
||||
timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
|
||||
timer_.Start();
|
||||
ASSERT_TRUE(timer_.Reset());
|
||||
ASSERT_FALSE(timer_.HasStarted());
|
||||
}
|
||||
|
||||
TEST_F(TimerTest, SeparatedTimers) {
|
||||
base::TimeTicks stime2, etime2;
|
||||
stime2 += base::TimeDelta::FromMilliseconds(4200);
|
||||
etime2 += base::TimeDelta::FromMilliseconds(5000);
|
||||
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
|
||||
.WillOnce(Return(stime))
|
||||
.WillOnce(Return(etime))
|
||||
.WillOnce(Return(stime2))
|
||||
.WillOnce(Return(etime2));
|
||||
timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
|
||||
ASSERT_TRUE(timer_.Start());
|
||||
ASSERT_TRUE(timer_.Stop());
|
||||
ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), 1500);
|
||||
ASSERT_TRUE(timer_.Start());
|
||||
ASSERT_TRUE(timer_.start_time_ == stime2);
|
||||
ASSERT_TRUE(timer_.Stop());
|
||||
ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), 800);
|
||||
ASSERT_FALSE(timer_.HasStarted());
|
||||
}
|
||||
|
||||
TEST_F(TimerTest, InvalidStop) {
|
||||
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
|
||||
.WillOnce(Return(stime))
|
||||
.WillOnce(Return(etime));
|
||||
timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
|
||||
ASSERT_FALSE(timer_.Stop());
|
||||
// Now we try it again, but after a valid start/stop.
|
||||
timer_.Start();
|
||||
timer_.Stop();
|
||||
base::TimeDelta elapsed_time = timer_.elapsed_time_;
|
||||
ASSERT_FALSE(timer_.Stop());
|
||||
ASSERT_TRUE(elapsed_time == timer_.elapsed_time_);
|
||||
}
|
||||
|
||||
TEST_F(TimerTest, InvalidElapsedTime) {
|
||||
base::TimeDelta elapsed_time;
|
||||
ASSERT_FALSE(timer_.GetElapsedTime(&elapsed_time));
|
||||
}
|
||||
|
||||
static const char kMetricName[] = "test-timer";
|
||||
static const int kMinSample = 0;
|
||||
static const int kMaxSample = 120 * 1E6;
|
||||
static const int kNumBuckets = 50;
|
||||
|
||||
class TimerReporterTest : public testing::Test {
|
||||
public:
|
||||
TimerReporterTest() : timer_reporter_(kMetricName, kMinSample, kMaxSample,
|
||||
kNumBuckets),
|
||||
clock_wrapper_mock_(new ClockWrapperMock()) {}
|
||||
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
timer_reporter_.set_metrics_lib(&lib_);
|
||||
EXPECT_EQ(timer_reporter_.histogram_name_, kMetricName);
|
||||
EXPECT_EQ(timer_reporter_.min_, kMinSample);
|
||||
EXPECT_EQ(timer_reporter_.max_, kMaxSample);
|
||||
EXPECT_EQ(timer_reporter_.num_buckets_, kNumBuckets);
|
||||
stime += base::TimeDelta::FromMilliseconds(1500);
|
||||
etime += base::TimeDelta::FromMilliseconds(3000);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
timer_reporter_.set_metrics_lib(NULL);
|
||||
}
|
||||
|
||||
TimerReporter timer_reporter_;
|
||||
MetricsLibraryMock lib_;
|
||||
scoped_ptr<ClockWrapperMock> clock_wrapper_mock_;
|
||||
base::TimeTicks stime, etime;
|
||||
};
|
||||
|
||||
TEST_F(TimerReporterTest, StartStopReport) {
|
||||
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
|
||||
.WillOnce(Return(stime))
|
||||
.WillOnce(Return(etime));
|
||||
timer_reporter_.clock_wrapper_.reset(clock_wrapper_mock_.release());
|
||||
EXPECT_CALL(lib_, SendToUMA(kMetricName, 1500, kMinSample, kMaxSample,
|
||||
kNumBuckets)).WillOnce(Return(true));
|
||||
ASSERT_TRUE(timer_reporter_.Start());
|
||||
ASSERT_TRUE(timer_reporter_.Stop());
|
||||
ASSERT_TRUE(timer_reporter_.ReportMilliseconds());
|
||||
}
|
||||
|
||||
TEST_F(TimerReporterTest, InvalidReport) {
|
||||
ASSERT_FALSE(timer_reporter_.ReportMilliseconds());
|
||||
}
|
||||
|
||||
} // namespace chromeos_metrics
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Loading…
Reference in New Issue