Index: tools/telemetry/telemetry/web_perf/metrics/trace_event_aggregator.py |
diff --git a/tools/telemetry/telemetry/web_perf/metrics/trace_event_aggregator.py b/tools/telemetry/telemetry/web_perf/metrics/trace_event_aggregator.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6627e822db1be76633cb56ded760842bdf6316ca |
--- /dev/null |
+++ b/tools/telemetry/telemetry/web_perf/metrics/trace_event_aggregator.py |
@@ -0,0 +1,100 @@ |
+# Copyright 2015 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. |
+ |
+from telemetry.value import list_of_scalar_values |
+from telemetry.value import scalar |
+from telemetry.web_perf.metrics import timeline_based_metric |
+ |
+class TraceEventAggregatorInput(object): |
cmumford
2015/08/03 17:31:34
This class doesn't seem to do anything. Why not si
dmurph
2015/08/05 15:30:33
I'm going to defer to you and Ned for this. It see
|
+ """Input for the TraceEventAggregator. |
+ |
+ event_name: The name of the event to track. |
+ list_metric_name: The name of the list metric name, which accumulates |
+ all of the times of the events. |
+ list_metric_description: Description of the list metric. |
+ units: Units for the list metric. |
+ count_metric_name: The name of the metric that is the count of the events. |
+ count_metric_description: The description of the count metric. |
+ process_name: The name of the process to inspect for the trace events. |
+ """ |
+ def __init__(self, event_name, list_metric_name, |
+ list_metric_description, units, count_metric_name, |
+ count_metric_description, process_name=None): |
+ self.event_name = event_name |
+ self.list_metric_name = list_metric_name |
+ self.list_metric_description = list_metric_description |
+ self.units = units |
+ self.count_metric_name = count_metric_name |
+ self.count_metric_description = count_metric_description |
+ self.process_name = process_name |
+ |
+ |
+class TraceEventAggregator(timeline_based_metric.TimelineBasedMetric): |
+ """Reports durations and counts of given trace events. |
nednguyen
2015/08/03 16:12:21
This seems similar to single_event in web_perf/met
dmurph
2015/08/05 15:30:33
yay! I tried to make it as performant as possible
|
+ """ |
+ |
+ def __init__(self, trace_event_aggregator_inputs=[]): |
+ super(TraceEventAggregator, self).__init__() |
+ self._inputs_by_process_name = dict() |
+ self._IndexNewInputs(trace_event_aggregator_inputs) |
+ |
+ def AddInput(self, trace_event_aggregator_input): |
+ self._IndexNewInputs([trace_event_aggregator_input]) |
+ |
+ def _IndexNewInputs(self, input_list): |
+ for input_obj in input_list: |
+ if input_obj.process_name not in self._inputs_by_process_name: |
+ self._inputs_by_process_name[input_obj.process_name] = list() |
+ self._inputs_by_process_name[input_obj.process_name].append(input_obj) |
+ |
+ @staticmethod |
+ def ThreadDurationIfPresent(event): |
+ if event.thread_duration: |
cmumford
2015/08/03 17:31:34
Could you ever have a thread_duration of zero?
dmurph
2015/08/05 15:30:33
I imagine so.
|
+ return event.thread_duration |
+ else: |
+ return event.end - event.start |
+ |
+ def AddResults(self, model, renderer_thread, interactions, results): |
+ assert interactions |
+ # NOTE: This means duplicate names can cause problems. |
+ for p in model.GetAllProcesses(): |
+ if (p.name is renderer_thread.name and |
+ None in self._inputs_by_process_name): |
+ self._AddResultsInternal(renderer_thread.parent.IterAllSlices(), |
+ interactions, results, |
+ self._inputs_by_process_name[None]) |
+ elif p.name in self._inputs_by_process_name: |
+ self._AddResultsInternal(p.parent.IterAllSlices(), |
+ interactions, results, |
+ self._inputs_by_process_name[p.name]) |
+ |
+ def _AddResultsInternal(self, events, interactions, results, inputs): |
+ times_by_event_name = dict([[input_obj.event_name, []] |
+ for input_obj in inputs]) |
+ inputs_by_event_name = dict([[input_obj.event_name, input_obj] |
+ for input_obj in inputs]) |
+ for event in events: |
+ if event.name not in inputs_by_event_name or not any( |
+ interaction.start <= event.start <= interaction.end |
+ for interaction in interactions): |
+ continue |
+ times_by_event_name[event.name].append( |
+ self.ThreadDurationIfPresent(event)) |
+ |
+ for (event_name, times) in times_by_event_name.iteritems(): |
+ input_for_event = inputs_by_event_name[event_name] |
+ results.AddValue(scalar.ScalarValue( |
+ page=results.current_page, |
+ name=input_for_event.count_metric_name, |
+ units='count', |
+ value=len(times), |
+ description=input_for_event.count_metric_description)) |
+ if len(times) == 0: |
cmumford
2015/08/03 17:31:34
Not pythonic. Just do:
if not times:
continue
dmurph
2015/08/05 15:30:33
Done.
|
+ continue |
+ results.AddValue(list_of_scalar_values.ListOfScalarValues( |
+ page=results.current_page, |
+ name=input_for_event.list_metric_name, |
+ units=input_for_event.units, |
+ values=times, |
+ description=input_for_event.list_metric_description)) |