| // 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_ |