results_report.py revision 0dcbc4b1714260820fd4b8d6536fbb05e139cc0f
1#!/usr/bin/python
2
3# Copyright 2011 Google Inc. All Rights Reserved.
4
5from column_chart import ColumnChart
6from results_columns import IterationColumn
7from results_columns import IterationsCompleteColumn
8from results_columns import MaxColumn
9from results_columns import MeanColumn
10from results_columns import MinColumn
11from results_columns import RatioColumn
12from results_columns import StandardDeviationColumn
13from results_sorter import ResultSorter
14from table import Table
15
16
17class ResultsReport(object):
18  DELTA_COLUMN_NAME = "Change"
19
20  def __init__(self, experiment):
21    self.experiment = experiment
22    self.benchmark_runs = experiment.benchmark_runs
23    self.labels = experiment.labels
24    self.benchmarks = experiment.benchmarks
25    self.baseline = self.labels[0]
26
27  def _SortByLabel(self, runs):
28    labels = {}
29    for benchmark_run in runs:
30      if benchmark_run.label_name not in labels:
31        labels[benchmark_run.label_name] = []
32      labels[benchmark_run.label_name].append(benchmark_run)
33    return labels
34
35  def GetFullTable(self):
36    full_columns = []
37    max_iterations = 0
38    for benchmark in self.benchmarks:
39      if benchmark.iterations > max_iterations:
40        max_iterations = benchmark.iterations
41
42    for i in range(1, max_iterations + 1):
43      full_columns.append(IterationColumn(str(i), i))
44
45    full_columns.append(IterationsCompleteColumn("Completed"))
46    full_columns.append(MinColumn("Min"))
47    full_columns.append(MaxColumn("Max"))
48    full_columns.append(MeanColumn("Avg"))
49    full_columns.append(StandardDeviationColumn("Std Dev"))
50    full_columns.append(RatioColumn(self.DELTA_COLUMN_NAME))
51    return self._GetTable(self.labels, self.benchmarks, self.benchmark_runs,
52                          full_columns)
53
54  def GetSummaryTable(self):
55    summary_columns = [MeanColumn("Average"),
56                       RatioColumn(self.DELTA_COLUMN_NAME)]
57    return self._GetTable(self.labels, self.benchmarks, self.benchmark_runs,
58                          summary_columns)
59
60  def _GetTable(self, labels, benchmarks, benchmark_runs, columns):
61    table = Table("box-table-a")
62    label_headings = [Table.Cell("", hidden=True, colspan=2, header=True)]
63    for label in labels:
64      colspan = len(columns)
65      if label.name == self.baseline.name:
66        colspan -= 1
67      label_headings.append(Table.Cell(label.name, colspan=colspan,
68                                       header=True))
69
70    table.AddRow(label_headings)
71
72    column_headings = [Table.Cell("Autotest Key", header=True),
73                       Table.Cell("Iterations", header=True)]
74    for label in labels:
75      for column in columns:
76        if (label.name == self.baseline.name and
77            column.name == self.DELTA_COLUMN_NAME):
78          continue
79        column_headings.append(Table.Cell(column.name, header=True))
80
81    table.AddRow(column_headings)
82
83    sorter = ResultSorter(benchmark_runs)
84
85    for benchmark in benchmarks:
86      table.AddRow([Table.Cell(benchmark.name)])
87      autotest_keys = sorter.GetAutotestKeys(benchmark.name)
88      for autotest_key in autotest_keys:
89        row = [Table.Cell(autotest_key),
90               Table.Cell(benchmark.iterations)]
91        for label in labels:
92          for column in columns:
93            if (label.name == self.baseline.name and
94                column.name == self.DELTA_COLUMN_NAME):
95              continue
96            results = sorter.GetResults(benchmark.name,
97                                        autotest_key, label.name)
98            baseline_results = sorter.GetResults(benchmark.name,
99                                                 autotest_key,
100                                                 self.baseline.name)
101            value = column.Compute(results, baseline_results)
102            if isinstance(value, float):
103              value_string = "%.2f" % value
104            else:
105              value_string = value
106
107            row.append(Table.Cell(value_string))
108
109        table.AddRow(row)
110
111    return table
112
113
114class TextResultsReport(ResultsReport):
115  TEXT = """
116===========================================
117Results report for: '%s'
118===========================================
119
120-------------------------------------------
121Benchmark Run Status
122-------------------------------------------
123%s
124
125Number re-images: %s
126
127-------------------------------------------
128Summary
129-------------------------------------------
130%s
131
132-------------------------------------------
133Full Table
134-------------------------------------------
135%s
136
137-------------------------------------------
138Experiment File
139-------------------------------------------
140%s
141===========================================
142"""
143
144  def __init__(self, experiment):
145    super(TextResultsReport, self).__init__(experiment)
146
147  def GetStatusTable(self):
148    status_table = Table("status")
149    for benchmark_run in self.benchmark_runs:
150      status_table.AddRow([Table.Cell(benchmark_run.name),
151                           Table.Cell(benchmark_run.status),
152                           Table.Cell(benchmark_run.failure_reason)])
153    return status_table
154
155  def GetReport(self):
156    return self.TEXT % (self.experiment.name,
157                        self.GetStatusTable().ToText(),
158                        self.experiment.machine_manager.num_reimages,
159                        self.GetSummaryTable().ToText(30),
160                        self.GetFullTable().ToText(30),
161                        self.experiment.experiment_file)
162
163
164class HTMLResultsReport(ResultsReport):
165  HTML = """
166<html>
167  <head>
168    <style type="text/css">
169
170body {
171  font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
172  font-size: 12px;
173}
174
175pre {
176  margin: 10px;
177  color: #039;
178  font-size: 14px;
179}
180
181.chart {
182  display: inline;
183}
184
185.hidden {
186  visibility: hidden;
187}
188
189.results-section {
190  border: 1px solid #b9c9fe;
191  margin: 10px;
192}
193
194.results-section-title {
195  background-color: #b9c9fe;
196  color: #039;
197  padding: 7px;
198  font-size: 14px;
199  width: 200px;
200}
201
202.results-section-content {
203  margin: 10px;
204  padding: 10px;
205  overflow:auto;
206}
207
208#box-table-a {
209  font-size: 12px;
210  width: 480px;
211  text-align: left;
212  border-collapse: collapse;
213}
214
215#box-table-a th {
216  padding: 6px;
217  background: #b9c9fe;
218  border-right: 1px solid #fff;
219  border-bottom: 1px solid #fff;
220  color: #039;
221  text-align: center;
222}
223
224#box-table-a td {
225  padding: 4px;
226  background: #e8edff;
227  border-bottom: 1px solid #fff;
228  border-right: 1px solid #fff;
229  color: #669;
230  border-top: 1px solid transparent;
231}
232
233#box-table-a tr:hover td {
234  background: #d0dafd;
235  color: #339;
236}
237
238    </style>
239    <script type='text/javascript' src='https://www.google.com/jsapi'></script>
240    <script type='text/javascript'>
241      google.load('visualization', '1', {packages:['corechart']});
242      google.setOnLoadCallback(init);
243      function init() {
244        switchTab('summary', 'html');
245        switchTab('full', 'html');
246        drawTable();
247      }
248      function drawTable() {
249        %s
250      }
251      function switchTab(table, tab) {
252        document.getElementById(table + '-html').style.display = 'none';
253        document.getElementById(table + '-text').style.display = 'none';
254        document.getElementById(table + '-tsv').style.display = 'none';
255        document.getElementById(table + '-' + tab).style.display = 'block';
256      }
257    </script>
258  </head>
259
260  <body>
261    <div class='results-section'>
262      <div class='results-section-title'>Summary Table</div>
263      <div class='results-section-content'>
264        <div id='summary-html'>%s</div>
265        <div id='summary-text'><pre>%s</pre></div>
266        <div id='summary-tsv'><pre>%s</pre></div>
267      </div>
268      %s
269    </div>
270    <div class='results-section'>
271      <div class='results-section-title'>Charts</div>
272      <div class='results-section-content'>%s</div>
273    </div>
274    <div class='results-section'>
275      <div class='results-section-title'>Full Table</div>
276      <div class='results-section-content'>
277        <div id='full-html'>%s</div>
278        <div id='full-text'><pre>%s</pre></div>
279        <div id='full-tsv'><pre>%s</pre></div>
280      </div>
281      %s
282    </div>
283    <div class='results-section'>
284      <div class='results-section-title'>Experiment File</div>
285      <div class='results-section-content'>
286        <pre>%s</pre>
287    </div>
288    </div>
289  </body>
290</html>
291"""
292
293  def __init__(self, experiment):
294    super(HTMLResultsReport, self).__init__(experiment)
295
296  def _GetTabMenuHTML(self, table):
297    return """
298<div class='tab-menu'>
299  <a href="javascript:switchTab('%s', 'html')">HTML</a>
300  <a href="javascript:switchTab('%s', 'text')">Text</a>
301  <a href="javascript:switchTab('%s', 'tsv')">TSV</a>
302</div>""" % (table, table, table)
303
304  def GetReport(self):
305    chart_javascript = ""
306    charts = self._GetCharts(self.labels, self.benchmarks, self.benchmark_runs)
307    for chart in charts:
308      chart_javascript += chart.GetJavascript()
309    chart_divs = ""
310    for chart in charts:
311      chart_divs += chart.GetDiv()
312
313    summary_table = self.GetSummaryTable()
314    full_table = self.GetFullTable()
315    return self.HTML % (chart_javascript,
316                        summary_table.ToHTML(),
317                        summary_table.ToText(),
318                        summary_table.ToTSV(),
319                        self._GetTabMenuHTML("summary"),
320                        chart_divs,
321                        full_table.ToHTML(),
322                        full_table.ToText(),
323                        full_table.ToTSV(),
324                        self._GetTabMenuHTML("full"),
325                        self.experiment.experiment_file)
326
327  def _GetCharts(self, labels, benchmarks, benchmark_runs):
328    charts = []
329    sorter = ResultSorter(benchmark_runs)
330
331    for benchmark in benchmarks:
332      autotest_keys = sorter.GetAutotestKeys(benchmark.name)
333
334      for autotest_key in autotest_keys:
335        title = "%s: %s" % (benchmark.name, autotest_key.replace("/", " "))
336        chart = ColumnChart(title, 300, 200)
337        chart.AddColumn("Label", "string")
338        chart.AddColumn("Average", "number")
339        chart.AddColumn("Min", "number")
340        chart.AddColumn("Max", "number")
341        chart.AddSeries("Min", "line", "black")
342        chart.AddSeries("Max", "line", "black")
343
344        for label in labels:
345          res = sorter.GetResults(benchmark.name, autotest_key, label.name)
346          avg_val = MeanColumn("").Compute(res, None)
347          min_val = MinColumn("").Compute(res, None)
348          max_val = MaxColumn("").Compute(res, None)
349          chart.AddRow([label.name, avg_val, min_val, max_val])
350          if isinstance(avg_val, str):
351            chart = None
352            break
353
354        if chart:
355          charts.append(chart)
356    return charts
357
358