Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Unified Diff: components/subresource_filter/core/common/scoped_timers.h

Issue 2503283003: Add high-precision timing histograms. (Closed)
Patch Set: Change measurement unit. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/subresource_filter/core/common/scoped_timers.h
diff --git a/components/subresource_filter/core/common/scoped_timers.h b/components/subresource_filter/core/common/scoped_timers.h
new file mode 100644
index 0000000000000000000000000000000000000000..58a834c29676d83e420a6a2642613682bdf6471e
--- /dev/null
+++ b/components/subresource_filter/core/common/scoped_timers.h
@@ -0,0 +1,248 @@
+// 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 tools for measuring time intervals and reporting them to
+// UMA histograms or via custom functors. It is possible to measure time both
+// with base::TimeTicks and base::ThreadTicks.
+// WARNING: *UMA_HISTOGRAM_* macros in this file are not thread-safe.
+// See also: "base/metrics/histogram_macros*.h".
+//
+// TODO(pkalinnikov): Consider moving content of this file to "base/metrics/*"
+// after some refactoring. Note that most of the code generated by the macros
+// below is not thread-safe.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_
+
+#include <type_traits>
+
+#include "base/macros.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+
+namespace subresource_filter {
+
+// Creates a scoped object that measures its lifetime using base::TimeTicks, and
+// reports the result as base::TimeDelta via provided |export_functor|. The
+// functor is copied if passed in by value.
+//
+// Example:
+// void Function() {
+// auto export_time = [](base::TimeDelta delta) {
+// LOG(INFO) << "Duration: " << delta.InMicroseconds();
+// };
+// SCOPED_TIMER(export_time);
+// ... Useful things happen here ...
+// } // |export_time| will be triggered here.
+//
+// This is recommended for when you want to measure the time it takes for a
+// method/scope to execute, including, possibly, the time spent by the thread on
+// being blocked and/or descheduled.
+#define SCOPED_TIMER(export_functor) \
+ IMPL_SCOPED_TIMER_EXPANDER(impl::TimeTicksProvider, export_functor, \
+ __COUNTER__)
+
+// Similar to SCOPED_TIMER, but uses base::ThreadTicks for measuring time.
+//
+// This is recommended for when you want to measure the time it takes for a
+// method/scope to do actual work, i.e. excluding the time spent by the thread
+// on being blocked and/or descheduled.
+#define SCOPED_THREAD_TIMER(export_functor) \
+ IMPL_SCOPED_TIMER_EXPANDER(impl::ThreadTicksProvider, export_functor, \
+ __COUNTER__)
+
+// Creates a scoped object that measures its lifetime using base::ThreadTicks,
+// and reports the result in milliseconds as a UMA statistic to a histogram with
+// the provided |name| which is expected to be a runtime constant. The histogram
+// collects times up to 10 seconds in 50 buckets.
+//
+// Under the hood there is a static base::HistogramBase* pointer initialized
+// right before the scoped object. The pointer is used by a specific
+// |export_functor| passed in to a SCOPED_THREAD_TIMER (see it above).
+//
+// Example:
+// void Function() {
+// SCOPED_UMA_HISTOGRAM_THREAD_TIMER("Component.FunctionTime");
+// ... Useful things happen here ...
+// }
+//
+// WARNING: The generated code is not thread-safe.
+#define SCOPED_UMA_HISTOGRAM_THREAD_TIMER(name) \
+ IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \
+ name, impl::ThreadTicksProvider, impl::ExportMillisecondsToHistogram, \
+ 10 * 1000, __COUNTER__)
+
+// Similar to SCOPED_UMA_HISTOGRAM_THREAD_TIMER above, but the histogram
+// collects times in microseconds, up to 1 second, and using 50 buckets.
+//
+// WARNING: The generated code is not thread-safe.
+#define SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER(name) \
+ IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \
+ name, impl::ThreadTicksProvider, impl::ExportMicrosecondsToHistogram, \
+ 1000 * 1000, __COUNTER__)
+
+// Similar to SCOPED_UMA_HISTOGRAM_TIMER in "base/metrics/histogram_macros.h",
+// but the histogram stores times in microseconds, up to 1 second, in 50
+// buckets.
+//
+// WARNING: The generated code is not thread-safe.
+#define SCOPED_UMA_HISTOGRAM_MICRO_TIMER(name) \
+ IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \
+ name, impl::TimeTicksProvider, impl::ExportMicrosecondsToHistogram, \
+ 1000 * 1000, __COUNTER__)
+
+// Similar to UMA_HISTOGRAM_TIMES in "base/metrics/histogram_macros.h", but
+// the histogram stores times in microseconds, up to 1 second, in 50 buckets.
+//
+// WARNING: The generated code is not thread-safe.
+#define UMA_HISTOGRAM_MICRO_TIMES(name, sample) \
+ UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(name, sample, \
+ base::TimeDelta::FromMicroseconds(1), \
+ base::TimeDelta::FromSeconds(1), 50)
+
+// This can be used when the default ranges are not sufficient. This macro lets
+// the metric developer customize the min and max of the sampled range, as well
+// as the number of buckets recorded.
+#define UMA_HISTOGRAM_CUSTOM_MICRO_TIMES(name, sample, min, max, bucket_count) \
+ IMPL_UMA_HISTOGRAM_ADD(name, sample.InMicroseconds(), min.InMicroseconds(), \
+ max.InMicroseconds(), bucket_count)
+
+// -----------------------------------------------------------------------------
+// Below are helpers used by other macros. Shouldn't be used directly. ---------
+
+// This is necessary to expand __COUNTER__ to an actual value.
+#define IMPL_SCOPED_TIMER_EXPANDER(time_provider, export_functor, suffix) \
+ IMPL_SCOPED_TIMER_UNIQUE(time_provider, export_functor, suffix)
+
+// Creates a scoped timer, which uses |time_provider| to measure time, and
+// |export_functor| to report it.
+#define IMPL_SCOPED_TIMER_UNIQUE(time_provider, export_functor, suffix) \
+ impl::ScopedTimer<time_provider, decltype(export_functor)> \
+ scoped_timer_##suffix(export_functor);
+
+// This is necessary to expand __COUNTER__ to an actual value.
+#define IMPL_SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER( \
+ name, time_provider, histogram_exporter, max_value, suffix) \
+ IMPL_SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE( \
+ name, time_provider, histogram_exporter, max_value, suffix)
+
+// Creates a static histogram pointer and a scoped object referring to it
+// throught the |histogram_exporter| functor. Both the pointer and the scoped
+// object are uniquely-named, using the unique |suffix| passed in.
+#define IMPL_SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE( \
+ name, time_provider, histogram_exporter, max_value, suffix) \
+ IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, 1, max_value, 50, suffix) \
+ IMPL_SCOPED_TIMER_UNIQUE(time_provider, \
+ (histogram_exporter(histogram_##suffix)), suffix)
+
+// This is necessary to expand __COUNTER__ to an actual value.
+#define IMPL_UMA_HISTOGRAM_MICRO_TIMES_EXPANDER(name, max_value, suffix, \
+ sample) \
+ IMPL_UMA_HISTOGRAM_MICRO_TIMES_UNIQUE(name, max_value, suffix, sample)
+
+// Defines a static UMA histogram pointer and writes a |sample| to it.
+#define IMPL_UMA_HISTOGRAM_ADD(name, sample, min, max, bucket_count) \
+ do { \
+ IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, min, max, bucket_count, 0) \
+ histogram_0->Add(sample); \
+ } while (0)
+
+// Defines a static pointer to a UMA histogram.
+//
+// WARNING: Static local variable initialization is deliberately *not*
+// thread-safe in Chrome builds. See the "-fno-threadsafe-statics" flag in
+// "build/config/compiler/BUILD.gn" and "/Zc:threadSafeInit-" in
+// "build/config/win/BUILD.gn" for details.
+#define IMPL_DEFINE_STATIC_UMA_HISTOGRAM_POINTER(name, min, max, bucket_count, \
+ suffix) \
+ static base::HistogramBase* histogram_##suffix = \
+ base::Histogram::FactoryGet( \
+ name, min, max, bucket_count, \
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+
+namespace impl {
+
+// ScopedTimer is a multi-purpose scoped timer. It measures time delta from its
+// construction till 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.
+//
+// Time measurement is exported exactly once, unless TimeProvider::IsSupported()
+// is false. In the latter case ExportFunctor is never called.
+template <typename TimeProvider, typename ExportFunctor>
+class ScopedTimer {
+ public:
+ ScopedTimer(ExportFunctor export_functor) : export_functor_(export_functor) {
+ if (TimeProvider::IsSupported()) {
+ TimeProvider::WaitUntilInitialized();
+ construction_time_ = TimeProvider::Now();
+ }
+ }
+
+ ~ScopedTimer() {
+ if (TimeProvider::IsSupported()) {
+ const base::TimeDelta delta = TimeProvider::Now() - construction_time_;
+ export_functor_(delta);
+ }
+ }
+
+ private:
+ using TimeType =
+ typename std::remove_reference<decltype(TimeProvider::Now())>::type;
+
+ ExportFunctor export_functor_;
+ TimeType construction_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTimer);
+};
+
+// 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;
+
+// ExportFunctor implementations -----------------------------------------------
+
+template <bool is_microsec_precision>
+class ExportTimeDeltaToHistogram {
+ public:
+ ExportTimeDeltaToHistogram(base::HistogramBase* histogram)
+ : histogram_(histogram) {}
+
+ void operator()(base::TimeDelta delta) {
+ if (is_microsec_precision)
+ histogram_->Add(delta.InMicroseconds());
+ else
+ histogram_->Add(delta.InMilliseconds());
+ }
+
+ private:
+ base::HistogramBase* histogram_;
+};
+
+using ExportMillisecondsToHistogram = ExportTimeDeltaToHistogram<false>;
+using ExportMicrosecondsToHistogram = ExportTimeDeltaToHistogram<true>;
+
+} // namespace impl
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_SCOPED_TIMERS_

Powered by Google App Engine
This is Rietveld 408576698