Index: tools/telemetry/telemetry/web_perf/timeline_based_measurement.py |
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py |
index b41d2b65729f8e21a53f1716350de04355786d6e..7ff61c092bbfdf24c532546a415985ac2e3d5283 100644 |
--- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py |
+++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py |
@@ -30,19 +30,24 @@ ALL_OVERHEAD_LEVELS = [ |
DEBUG_OVERHEAD_LEVEL |
] |
+DEFAULT_METRICS = { |
+ tir_module.IS_FAST: fast_metric.FastMetric, |
+ tir_module.IS_SMOOTH: smoothness.SmoothnessMetric, |
+ tir_module.IS_RESPONSIVE: responsiveness_metric.ResponsivenessMetric, |
+} |
class InvalidInteractions(Exception): |
pass |
-def _GetMetricFromMetricType(metric_type): |
- if metric_type == tir_module.IS_FAST: |
- return fast_metric.FastMetric() |
- if metric_type == tir_module.IS_SMOOTH: |
- return smoothness.SmoothnessMetric() |
- if metric_type == tir_module.IS_RESPONSIVE: |
- return responsiveness_metric.ResponsivenessMetric() |
- raise Exception('Unrecognized metric type: %s' % metric_type) |
+def _GetMetricsFromFlags(record_custom_flags): |
+ flags_set = set(record_custom_flags) |
+ unknown_flags = flags_set.difference(DEFAULT_METRICS) |
+ if unknown_flags: |
+ raise Exception("Unknown metric flags: %s" % sorted(unknown_flags)) |
+ |
+ return [metric() for flag, metric in DEFAULT_METRICS.iteritems() |
+ if flag in flags_set] |
# TODO(nednguyen): Get rid of this results wrapper hack after we add interaction |
@@ -63,6 +68,7 @@ class _ResultsWrapper(object): |
value.name = self._GetResultName(value.name) |
self._results.AddValue(value) |
+ |
def _GetRendererThreadsToInteractionRecordsMap(model): |
threads_to_records_map = defaultdict(list) |
interaction_labels_of_previous_threads = set() |
@@ -82,14 +88,15 @@ def _GetRendererThreadsToInteractionRecordsMap(model): |
return threads_to_records_map |
+ |
class _TimelineBasedMetrics(object): |
def __init__(self, model, renderer_thread, interaction_records, |
- get_metric_from_metric_type_callback): |
+ get_metrics_from_flags_callback): |
self._model = model |
self._renderer_thread = renderer_thread |
self._interaction_records = interaction_records |
- self._get_metric_from_metric_type_callback = \ |
- get_metric_from_metric_type_callback |
+ self._get_metrics_from_flags_callback = \ |
+ get_metrics_from_flags_callback |
def AddResults(self, results): |
interactions_by_label = defaultdict(list) |
@@ -105,17 +112,18 @@ class _TimelineBasedMetrics(object): |
self.UpdateResultsByMetric(interactions, wrapped_results) |
def UpdateResultsByMetric(self, interactions, wrapped_results): |
- for metric_type in tir_module.METRICS: |
- # For each metric type, either all or none of the interactions should |
- # have that metric. |
- interactions_with_metric = [i for i in interactions if |
- i.HasMetric(metric_type)] |
- if not interactions_with_metric: |
- continue |
- if len(interactions_with_metric) != len(interactions): |
+ if not interactions: |
+ return |
+ |
+ # Either all or none of the interactions should have that metric flags. |
+ records_custom_flags = set(interactions[0].GetUserDefinedFlags()) |
+ for interaction in interactions[1:]: |
+ if records_custom_flags != set(interaction.GetUserDefinedFlags()): |
raise InvalidInteractions('Interaction records with the same logical ' |
'name must have the same flags.') |
- metric = self._get_metric_from_metric_type_callback(metric_type) |
+ |
+ metrics_list = self._get_metrics_from_flags_callback(records_custom_flags) |
+ for metric in metrics_list: |
metric.AddResults(self._model, self._renderer_thread, |
interactions, wrapped_results) |
@@ -127,22 +135,45 @@ class Options(object): |
Benchmark.CreateTimelineBasedMeasurementOptions. |
""" |
- def __init__(self, overhead_level=NO_OVERHEAD_LEVEL): |
- """Save the overhead level. |
- |
- As the amount of instrumentation increases, so does the overhead. |
+ def __init__(self, overhead_level=NO_OVERHEAD_LEVEL, |
+ get_metrics_from_flags_callback=_GetMetricsFromFlags): |
+ """As the amount of instrumentation increases, so does the overhead. |
The user of the measurement chooses the overhead level that is appropriate, |
and the tracing is filtered accordingly. |
- overhead_level: one of NO_OVERHEAD_LEVEL, V8_OVERHEAD_LEVEL, |
- MINIMAL_OVERHEAD_LEVEL, or DEBUG_OVERHEAD_LEVEL. |
- The v8 overhead level is a temporary solution that may be removed. |
+ overhead_level: Can either be a custom TracingCategoryFilter object or |
+ one of NO_OVERHEAD_LEVEL, V8_OVERHEAD_LEVEL, MINIMAL_OVERHEAD_LEVEL, |
+ or DEBUG_OVERHEAD_LEVEL. The v8 overhead level is a temporary solution |
+ that may be removed. |
+ get_metrics_from_flags_callback: Callback function which returns a |
+ a list of metrics based on timeline record flags. See the default |
+ _GetMetricsFromFlags() as an example. |
""" |
+ if (not isinstance(overhead_level, |
+ tracing_category_filter.TracingCategoryFilter) and |
+ overhead_level not in ALL_OVERHEAD_LEVELS): |
+ raise Exception("Overhead level must be a TracingCategoryFilter object" |
+ " or valid overhead level string." |
+ " Given overhead level: %s" % overhead_level) |
+ |
self._overhead_level = overhead_level |
- self._category_filters = [] |
+ self._extra_category_filters = [] |
+ self._get_metrics_from_flags_callback = get_metrics_from_flags_callback |
def ExtendTraceCategoryFilters(self, filters): |
- self._category_filters.extend(filters) |
+ self._extra_category_filters.extend(filters) |
+ |
+ @property |
+ def extra_category_filters(self): |
+ return self._extra_category_filters |
+ |
+ @property |
+ def overhead_level(self): |
+ return self._overhead_level |
+ |
+ @property |
+ def get_metrics_from_flags_callback(self): |
+ return self._get_metrics_from_flags_callback |
class TimelineBasedMeasurement(object): |
@@ -168,8 +199,7 @@ class TimelineBasedMeasurement(object): |
perf.metrics.timeline_interaction_record module. |
""" |
def __init__(self, options): |
- self._overhead_level = options._overhead_level |
- self._category_filters = options._category_filters |
+ self._tbm_options = options |
def WillRunUserStory(self, tracing_controller, |
synthetic_delay_categories=None): |
@@ -184,20 +214,27 @@ class TimelineBasedMeasurement(object): |
""" |
if not tracing_controller.IsChromeTracingSupported(): |
raise Exception('Not supported') |
- assert self._overhead_level in ALL_OVERHEAD_LEVELS |
- if self._overhead_level == NO_OVERHEAD_LEVEL: |
- category_filter = tracing_category_filter.CreateNoOverheadFilter() |
- # TODO(ernstm): Remove this overhead level when benchmark relevant v8 events |
- # become available in the 'benchmark' category. |
- elif self._overhead_level == V8_OVERHEAD_LEVEL: |
- category_filter = tracing_category_filter.CreateNoOverheadFilter() |
- category_filter.AddIncludedCategory('v8') |
- elif self._overhead_level == MINIMAL_OVERHEAD_LEVEL: |
- category_filter = tracing_category_filter.CreateMinimalOverheadFilter() |
- else: |
- category_filter = tracing_category_filter.CreateDebugOverheadFilter() |
- for new_category_filter in self._category_filters: |
+ if isinstance(self._tbm_options.overhead_level, |
+ tracing_category_filter.TracingCategoryFilter): |
+ category_filter = self._tbm_options.overhead_level |
+ else: |
+ assert self._tbm_options.overhead_level in ALL_OVERHEAD_LEVELS, ( |
+ "Invalid TBM Overhead Level: %s" % self._tbm_options.overhead_level) |
+ |
+ if self._tbm_options.overhead_level == NO_OVERHEAD_LEVEL: |
+ category_filter = tracing_category_filter.CreateNoOverheadFilter() |
+ # TODO(ernstm): Remove this overhead level when benchmark relevant v8 |
+ # events become available in the 'benchmark' category. |
+ elif self._tbm_options.overhead_level == V8_OVERHEAD_LEVEL: |
+ category_filter = tracing_category_filter.CreateNoOverheadFilter() |
+ category_filter.AddIncludedCategory('v8') |
+ elif self._tbm_options.overhead_level == MINIMAL_OVERHEAD_LEVEL: |
+ category_filter = tracing_category_filter.CreateMinimalOverheadFilter() |
+ else: |
+ category_filter = tracing_category_filter.CreateDebugOverheadFilter() |
+ |
+ for new_category_filter in self._tbm_options.extra_category_filters: |
category_filter.AddIncludedCategory(new_category_filter) |
# TODO(slamm): Move synthetic_delay_categories to the TBM options. |
@@ -217,7 +254,8 @@ class TimelineBasedMeasurement(object): |
for renderer_thread, interaction_records in ( |
threads_to_records_map.iteritems()): |
meta_metrics = _TimelineBasedMetrics( |
- model, renderer_thread, interaction_records, _GetMetricFromMetricType) |
+ model, renderer_thread, interaction_records, |
+ self._tbm_options.get_metrics_from_flags_callback) |
meta_metrics.AddResults(results) |
def DidRunUserStory(self, tracing_controller): |