133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright 2014 The Chromium Authors. All rights reserved.
233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Use of this source code is governed by a BSD-style license that can be
333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# found in the LICENSE file.
433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport csv
633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.internal.results import output_formatter
833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.value import scalar
933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.value import trace
1033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass CsvPivotTableOutputFormatter(output_formatter.OutputFormatter):
1333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  """Output the results as CSV suitable for reading into a spreadsheet.
1433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  This will write a header row, and one row for each value. Each value row
1633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  contains the value and unit, identifies the value (story_set, page, name), and
1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  (optionally) data from --output-trace-tag. This format matches what
1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  spreadsheet programs expect as input for a "pivot table".
1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  A trace tag (--output-trace-tag) can be used to tag each value, to allow
2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  easy combination of the resulting CSVs from several runs.
2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  If the trace_tag contains a comma, it will be written as several
2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  comma-separated values.
2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  This class only processes scalar values.
2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  """
2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  FIELDS = ['story_set', 'page', 'name', 'value', 'units', 'run_index']
2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def __init__(self, output_stream, trace_tag=''):
3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    super(CsvPivotTableOutputFormatter, self).__init__(output_stream)
3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._trace_tag = trace_tag
3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def Format(self, page_test_results):
3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    csv_writer = csv.writer(self.output_stream)
3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    # Observe trace_tag. Use comma to split up the trace tag.
3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    tag_values = self._trace_tag.split(',')
3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    tag_values = [x for x in tag_values if x] # filter empty list entries
4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    tag_headers = ['trace_tag_%d' % i for i in range(len(tag_values))]
4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    # Write header.
4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    csv_writer.writerow(self.FIELDS + tag_headers)
4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    # Write all values. Each row contains a value + page-level metadata.
4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    for run in page_test_results.all_page_runs:
4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      run_index = page_test_results.all_page_runs.index(run)
4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      page_dict = {
4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          'page': run.story.display_name,
5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          'story_set': run.story.page_set.Name(),
5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          'run_index': run_index,
5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      }
5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      for value in run.values:
5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        if (isinstance(value, scalar.ScalarValue) or
5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            isinstance(value, trace.TraceValue)):
5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          value_dict = {
5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            'name': value.name,
5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            'value': value.value,
5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck            'units': value.units,
6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          }
6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          value_dict.update(page_dict.items())
6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck          csv_writer.writerow(
6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck              [value_dict[field] for field in self.FIELDS] + tag_values)
64