blob: 6eb617b195fa190517e70cca7d82d2015751f927 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file provides a ScopedTimerImpl class which measures its lifetime using
// different time providers, and can report the measurement via user-defined
// callbacks. The class comes with ScopedTimerImplFactory which has convenient
// factory methods returning timer instances.
//
// Although the classes can be used directly, the most common usages are covered
// by the ScopedTimers and ScopedThreadTimers type aliases. See comments to
// these aliases below.
//
// TODO(pkalinnikov): Consider moving this file to "base/metrics/".
#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_
#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_
#include <type_traits>
#include <utility>
#include "base/macros.h"
#include "base/time/time.h"
namespace subresource_filter {
namespace impl {
// ScopedTimerImpl is a multi-purpose scoped timer. It measures time delta from
// its construction until its destruction. For example, by putting an instance
// of this class to the beginning of a scope it is possible to measure how long
// the scope is being executed.
//
// The obtained time measurement is reported via ExportFunctor, which takes
// base::TimeDelta as a parameter.
//
// Time is obtained by means of the TimeProvider static interface:
// * static bool IsSupported();
// - Idempotently returns whether the system supports such type of provider.
// * static void WaitUntilInitialized();
// - Waits until the provider can be used.
// * static TimeType Now();
// - Returns the current time of some TimeType, e.g., base::TimeTicks.
//
// The ExportFunctor is invoked exactly once, upon destruction, if both
// |activate| and TimeProvider::IsSupported() are true. Otherwise, the
// ExportFunctor is not called and no time measurements are performed, making
// the overhead of an instance practically zero.
template <typename TimeProvider, typename ExportFunctor>
class ScopedTimerImpl {
public:
// Constructs a timer reporting its measurement to |export_functor|. The timer
// will be activated iff |activate| && TimeProvider::IsSupported().
explicit ScopedTimerImpl(ExportFunctor&& export_functor, bool activate = true)
: export_functor_(std::forward<ExportFunctor>(export_functor)),
activated_(activate && TimeProvider::IsSupported()) {
if (activated_) {
TimeProvider::WaitUntilInitialized();
construction_time_ = TimeProvider::Now();
}
}
// The class is moveable. The |rhs| becomes deactivated when it is moved from,
// so that no time measurement will be reported upon its destruction.
ScopedTimerImpl(ScopedTimerImpl&& rhs)
: export_functor_(std::forward<ExportFunctor>(rhs.export_functor_)),
construction_time_(std::move(rhs.construction_time_)),
activated_(rhs.activated_) {
rhs.activated_ = false;
}
// If |this| was activated before assignment, it reports its measurement
// before stealing the one from |rhs|.
ScopedTimerImpl& operator=(ScopedTimerImpl&& rhs) {
if (&rhs != this) {
this->~ScopedTimerImpl();
::new (this) ScopedTimerImpl(std::move(rhs));
}
return *this;
}
~ScopedTimerImpl() {
if (activated_)
export_functor_(TimeProvider::Now() - construction_time_);
}
private:
using TimeType =
typename std::remove_reference<decltype(TimeProvider::Now())>::type;
ExportFunctor export_functor_;
TimeType construction_time_;
bool activated_ = false;
DISALLOW_COPY_AND_ASSIGN(ScopedTimerImpl);
};
// TimeProvider implementations ------------------------------------------------
class TimeTicksProvider {
public:
static bool IsSupported() { return true; }
static void WaitUntilInitialized() {}
static base::TimeTicks Now() { return base::TimeTicks::Now(); }
};
using ThreadTicksProvider = base::ThreadTicks;
// ScopedTimerImpl factories ---------------------------------------------------
// The class used to produce scoped timers using a certain |TimeProvider|.
template <typename TimeProvider>
class ScopedTimerImplFactory {
public:
// Returns a scoped timer which uses |export_functor| to report its
// measurement. The timer is activated iff TimeProvider::IsSupported().
template <typename ExportFunctor>
static ScopedTimerImpl<TimeProvider, ExportFunctor> Start(
ExportFunctor&& export_functor) {
return ScopedTimerImpl<TimeProvider, ExportFunctor>(
std::forward<ExportFunctor>(export_functor));
}
// Similar to the Start method above, but the timer is activated iff
// |condition| && TimeProvider::IsSupported().
template <typename ExportFunctor>
static ScopedTimerImpl<TimeProvider, ExportFunctor> StartIf(
bool condition,
ExportFunctor&& export_functor) {
return ScopedTimerImpl<TimeProvider, ExportFunctor>(
std::forward<ExportFunctor>(export_functor), condition);
}
static bool IsSupported() { return TimeProvider::IsSupported(); }
};
} // namespace impl
// A factory to produce scoped timers that measure time by means of TimeTicks.
//
// Example usage:
// void foo() {
// auto scoped_timer = ScopedTimers::Start([](base::TimeDelta duration) {
// LOG(INFO) << "Duration: " << duration.InMicroseconds() << " us";
// });
// ... Some time-consuming code goes here ...
// }
using ScopedTimers = impl::ScopedTimerImplFactory<impl::TimeTicksProvider>;
// Similar to ScopedTimers, but the produced timers use ThreadTicks.
using ScopedThreadTimers =
impl::ScopedTimerImplFactory<impl::ThreadTicksProvider>;
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_