Chromium Code Reviews| Index: tools/telemetry/telemetry/web_perf/metrics/trace_event_stats.py |
| diff --git a/tools/telemetry/telemetry/web_perf/metrics/trace_event_stats.py b/tools/telemetry/telemetry/web_perf/metrics/trace_event_stats.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..9b454b66c1dbb187a24451b23c7ca8e44b9d97a5 |
| --- /dev/null |
| +++ b/tools/telemetry/telemetry/web_perf/metrics/trace_event_stats.py |
| @@ -0,0 +1,126 @@ |
| +# 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. |
| + |
| +import collections |
| + |
| +from telemetry.value import list_of_scalar_values |
| +from telemetry.value import scalar |
| + |
| + |
| +class TraceEventStatsInput(object): |
| + """Input for the TraceEventStats. |
| + Using this object with TraceEventStats will include two metrics, one with a |
| + list of times of the given event, and one for the count of the events, named |
| + `metric_name + '-count'`. |
| + Args: |
| + event_category: The category of the event to track. |
| + event_name: The name of the event to track. |
| + metric_name: The name of the metric name, which accumulates all of the |
| + times of the events. |
| + metric_description: Description of the metric. |
| + units: Units for the metric. |
| + process_name: (optional) The name of the process to inspect for the trace |
| + events. Defaults to 'Renderer'. |
| + """ |
| + def __init__(self, event_category, event_name, metric_name, |
| + metric_description, units, process_name='Renderer'): |
| + self.event_category = event_category |
| + self.event_name = event_name |
| + self.metric_name = metric_name |
| + self.metric_description = metric_description |
| + self.units = units |
| + self.process_name = process_name |
| + self.event_id = TraceEventStatsInput.GetEventId(event_category, event_name) |
| + assert process_name is not None |
| + |
| + @staticmethod |
| + def GetEventId(event_category, event_name): |
| + return event_category + '^SERIALIZE-DELIM^' + event_name |
| + |
| +class TraceEventStats(object): |
| + """Reports durations and counts of given trace events. |
| + """ |
| + |
| + def __init__(self, trace_event_aggregator_inputs=[]): |
| + self._inputs_by_process_name = collections.defaultdict(list) |
| + self._metrics = set() |
| + 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: |
| + name = input_obj.metric_name |
| + # We check here to make sure we don't have a duplicate metric |
| + assert name not in self._metrics |
| + assert (name + '-count') not in self._metrics |
| + self._metrics.add(name) |
| + self._metrics.add(name + '-count') |
| + |
| + self._inputs_by_process_name[input_obj.process_name].append(input_obj) |
| + |
| + @staticmethod |
| + def ThreadDurationIfPresent(event): |
| + if event.thread_duration: |
| + return event.thread_duration |
| + else: |
| + return event.duration |
| + |
| + @staticmethod |
| + def GetEventID(event): |
|
nednguyen
2015/08/26 17:58:43
You don't need this method. Call sites can just us
dmurph
2015/08/26 20:24:54
Done.
|
| + return TraceEventStatsInput.GetEventId(event.category, event.name) |
| + |
| + def AddResults(self, model, renderer_process, interactions, results): |
| + assert interactions |
| + for p in model.GetAllProcesses(): |
| + if p.name not in self._inputs_by_process_name: |
| + continue |
| + |
| + inputs = self._inputs_by_process_name[p.name] |
| + input_ids = {i.event_id for i in inputs} |
| + |
| + self._AddResultsInternal( |
| + p.IterAllEvents( |
| + recursive=True, |
| + event_type_predicate=lambda t: True, |
| + event_predicate=lambda e: self.GetEventID(e) in input_ids), |
| + interactions, |
| + results, |
| + inputs) |
| + |
| + # We assume events have been filtered already. 'events' is an iterator. |
| + def _AddResultsInternal(self, events, interactions, results, inputs): |
| + times_by_event_id = collections.defaultdict(list) |
| + |
| + for event in events: |
| + if not any(interaction.start <= event.start <= interaction.end |
| + for interaction in interactions): |
| + continue |
| + times_by_event_id[self.GetEventID(event)].append( |
| + self.ThreadDurationIfPresent(event)) |
| + |
| + if not times_by_event_id: |
| + return |
| + |
| + inputs_by_event_id = dict([[input_obj.event_id, input_obj] |
| + for input_obj in inputs]) |
| + |
| + for (event_name, times) in times_by_event_id.iteritems(): |
| + input_for_event = inputs_by_event_id[event_name] |
| + name = input_for_event.metric_name |
| + results.AddValue(scalar.ScalarValue( |
| + page=results.current_page, |
| + name=name + '-count', |
| + units='count', |
| + value=len(times), |
| + description='The number of times ' + name + ' was recorded.')) |
| + if len(times) == 0: |
| + continue |
| + results.AddValue(list_of_scalar_values.ListOfScalarValues( |
| + page=results.current_page, |
| + name=name, |
| + units=input_for_event.units, |
| + values=times, |
| + description=input_for_event.metric_description)) |