1# Copyright 2014 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import csv
6
7from telemetry.results import output_formatter
8from telemetry.value import merge_values
9
10
11class CsvOutputFormatter(output_formatter.OutputFormatter):
12  def __init__(self, output_stream):
13    super(CsvOutputFormatter, self).__init__(output_stream)
14
15  def Format(self, page_test_results):
16    values = merge_values.MergeLikeValuesFromSamePage(
17        page_test_results.all_page_specific_values)
18    writer = csv.writer(self.output_stream)
19    header_value_names = self._OutputHeader(values, writer)
20    value_groups_by_page = merge_values.GroupStably(
21        values, lambda value: value.page.url)
22    for values_for_page in value_groups_by_page:
23      self._OutputValuesForPage(
24          header_value_names, values_for_page[0].page, values_for_page,
25          writer)
26
27  def _OutputHeader(self, values, csv_writer):
28    """Output the header rows.
29
30    This will retrieve the header string from the given values. As a
31    results, you would typically pass it all of the recorded values at
32    the end of the entire telemetry run. In cases where each page
33    produces the same set of value names, you may call this method
34    with that set of values.
35
36    Args:
37      values: A set of values from which to extract the header string,
38          which is the value name and the units.
39      writer: A csv.writer instance.
40
41    Returns:
42      The value names being output on the header, in the order of
43      output.
44    """
45    representative_values = {}
46    for value in values:
47      if value.name not in representative_values:
48        representative_values[value.name] = value
49    header_value_names = list(representative_values.keys())
50    header_value_names.sort()
51
52    row = ['page_name']
53    for value_name in header_value_names:
54      units = representative_values[value_name].units
55      row.append('%s (%s)' % (value_name, units))
56    csv_writer.writerow(row)
57    self.output_stream.flush()
58    return header_value_names
59
60  def _OutputValuesForPage(self, header_value_names, page, page_values,
61                           csv_writer):
62    row = [page.display_name]
63    values_by_value_name = {}
64    for value in page_values:
65      values_by_value_name[value.name] = value
66
67    for value_name in header_value_names:
68      value = values_by_value_name.get(value_name, None)
69      if value and value.GetRepresentativeNumber():
70        row.append('%s' % value.GetRepresentativeNumber())
71      else:
72        row.append('-')
73    csv_writer.writerow(row)
74    self.output_stream.flush()
75