results_report.py revision 4467f004e7f0854963bec90daff1879fbd9d2fec
1#!/usr/bin/python
2
3# Copyright 2011 Google Inc. All Rights Reserved.
4
5from utils.tabulator import *
6
7from column_chart import ColumnChart
8from results_organizer import ResultOrganizer
9from perf_table import PerfTable
10
11
12class ResultsReport(object):
13  MAX_COLOR_CODE = 255
14
15  def __init__(self, experiment):
16    self.experiment = experiment
17    self.benchmark_runs = experiment.benchmark_runs
18    self.labels = experiment.labels
19    self.benchmarks = experiment.benchmarks
20    self.baseline = self.labels[0]
21
22  def _SortByLabel(self, runs):
23    labels = {}
24    for benchmark_run in runs:
25      if benchmark_run.label_name not in labels:
26        labels[benchmark_run.label_name] = []
27      labels[benchmark_run.label_name].append(benchmark_run)
28    return labels
29
30  def GetFullTables(self, perf=False):
31    columns = [Column(NonEmptyCountResult(),
32                      Format(),
33                      "Completed"),
34               Column(RawResult(),
35                      Format()),
36               Column(MinResult(),
37                      Format()),
38               Column(MaxResult(),
39                      Format()),
40               Column(AmeanResult(),
41                      Format()),
42               Column(StdResult(),
43                      Format())
44              ]
45    if not perf:
46      return self._GetTables(self.labels, self.benchmark_runs, columns)
47    return self. _GetPerfTables(self.labels, columns)
48
49  def GetSummaryTables(self, perf=False):
50    columns = [Column(NonEmptyCountResult(),
51                      Format(),
52                      "Completed"),
53               Column(AmeanResult(),
54                      Format()),
55               Column(StdResult(),
56                      Format(), "StdDev"),
57               Column(CoeffVarResult(),
58                      CoeffVarFormat(), "StdDev/Mean"),
59               Column(GmeanRatioResult(),
60                      RatioFormat(), "GmeanSpeedup"),
61               Column(GmeanRatioResult(),
62                      ColorBoxFormat(), " "),
63               Column(PValueResult(),
64                      PValueFormat(), "p-value")
65              ]
66    if not perf:
67      return self._GetTables(self.labels, self.benchmark_runs, columns)
68    return self. _GetPerfTables(self.labels, columns)
69
70  def _ParseColumn(self, columns, iteration):
71    new_column = []
72    for column in columns:
73      if column.result.__class__.__name__ != "RawResult":
74      #TODO(asharif): tabulator should support full table natively.
75        new_column.append(column)
76      else:
77        for i in range(iteration):
78          cc = Column(LiteralResult(i), Format(), str(i+1))
79          new_column.append(cc)
80    return new_column
81
82  def _AreAllRunsEmpty(self, runs):
83    for label in runs:
84      for dictionary in label:
85        if dictionary:
86          return False
87    return True
88
89  def _GetTableHeader(self, benchmark):
90    benchmark_info = ("Benchmark:  {0};  Iterations: {1}"
91                      .format(benchmark.name, benchmark.iterations))
92    cell = Cell()
93    cell.string_value = benchmark_info
94    cell.header = True
95    return  [[cell]]
96
97  def _GetTables(self, labels, benchmark_runs, columns):
98    tables = []
99    ro = ResultOrganizer(benchmark_runs, labels, self.benchmarks)
100    result = ro.result
101    label_name = ro.labels
102    for item in result:
103      runs = result[item]
104      for benchmark in self.benchmarks:
105        if benchmark.name == item:
106          break
107      ben_table = self._GetTableHeader(benchmark)
108
109      if  self._AreAllRunsEmpty(runs):
110        cell = Cell()
111        cell.string_value = ("This benchmark contains no result."
112                             " Is the benchmark name valid?")
113        cell_table = [[cell]]
114      else:
115        tg = TableGenerator(runs, label_name)
116        table = tg.GetTable()
117        parsed_columns = self._ParseColumn(columns, benchmark.iterations)
118        tf = TableFormatter(table, parsed_columns)
119        cell_table = tf.GetCellTable()
120      tables.append(ben_table)
121      tables.append(cell_table)
122    return tables
123
124  def _GetPerfTables(self, labels, columns):
125    tables = []
126    label_names = [label.name for label in labels]
127    p_table = PerfTable(self.experiment, label_names)
128
129    if not p_table.perf_data:
130      return tables
131
132    for benchmark in p_table.perf_data:
133      ben = None
134      for ben in self.benchmarks:
135        if ben.name == benchmark:
136          break
137
138      ben_table = self._GetTableHeader(ben)
139      tables.append(ben_table)
140      benchmark_data = p_table.perf_data[benchmark]
141      table = []
142      for event in benchmark_data:
143        tg = TableGenerator(benchmark_data[event], label_names)
144        table = tg.GetTable()
145        parsed_columns = self._ParseColumn(columns, ben.iterations)
146        tf = TableFormatter(table, parsed_columns)
147        tf.GenerateCellTable()
148        tf.AddColumnName()
149        tf.AddLabelName()
150        tf.AddHeader(str(event))
151        table = tf.GetCellTable(headers=False)
152        tables.append(table)
153    return tables
154
155  def PrintTables(self, tables, out_to):
156    output = ""
157    if not tables:
158      return output
159    for table in tables:
160      if out_to == "HTML":
161        tp = TablePrinter(table, TablePrinter.HTML)
162      elif out_to == "PLAIN":
163        tp = TablePrinter(table, TablePrinter.PLAIN)
164      elif out_to == "CONSOLE":
165        tp = TablePrinter(table, TablePrinter.CONSOLE)
166      elif out_to == "TSV":
167        tp = TablePrinter(table, TablePrinter.TSV)
168      elif out_to == "EMAIL":
169        tp = TablePrinter(table, TablePrinter.EMAIL)
170      else:
171        pass
172      output += tp.Print()
173    return output
174
175
176class TextResultsReport(ResultsReport):
177  TEXT = """
178===========================================
179Results report for: '%s'
180===========================================
181
182-------------------------------------------
183Summary
184-------------------------------------------
185%s
186
187
188Number re-images: %s
189
190-------------------------------------------
191Benchmark Run Status
192-------------------------------------------
193%s
194
195
196-------------------------------------------
197Perf Data
198-------------------------------------------
199%s
200
201
202
203Experiment File
204-------------------------------------------
205%s
206
207
208CPUInfo
209-------------------------------------------
210%s
211===========================================
212"""
213
214  def __init__(self, experiment, email=False):
215    super(TextResultsReport, self).__init__(experiment)
216    self.email = email
217
218  def GetStatusTable(self):
219    """Generate the status table by the tabulator."""
220    table = [["", ""]]
221    columns = [Column(LiteralResult(iteration=0), Format(), "Status"),
222               Column(LiteralResult(iteration=1), Format(), "Failing Reason")]
223
224    for benchmark_run in self.benchmark_runs:
225      status = [benchmark_run.name, [benchmark_run.timeline.GetLastEvent(),
226                                     benchmark_run.failure_reason]]
227      table.append(status)
228    tf = TableFormatter(table, columns)
229    cell_table = tf.GetCellTable()
230    return [cell_table]
231
232  def GetReport(self):
233    """Generate the report for email and console."""
234    status_table = self.GetStatusTable()
235    summary_table = self.GetSummaryTables()
236    full_table = self.GetFullTables()
237    perf_table = self.GetSummaryTables(perf=True)
238    if not perf_table:
239      perf_table = None
240    if not self.email:
241      return self.TEXT % (self.experiment.name,
242                          self.PrintTables(summary_table, "CONSOLE"),
243                          self.experiment.machine_manager.num_reimages,
244                          self.PrintTables(status_table, "CONSOLE"),
245                          self.PrintTables(perf_table, "CONSOLE"),
246                          self.experiment.experiment_file,
247                          self.experiment.machine_manager.GetAllCPUInfo(
248                              self.experiment.labels))
249
250    return self.TEXT % (self.experiment.name,
251                        self.PrintTables(summary_table, "EMAIL"),
252                        self.experiment.machine_manager.num_reimages,
253                        self.PrintTables(status_table, "EMAIL"),
254                        self.PrintTables(perf_table, "EMAIL"),
255                        self.experiment.experiment_file,
256                        self.experiment.machine_manager.GetAllCPUInfo(
257                            self.experiment.labels))
258
259
260class HTMLResultsReport(ResultsReport):
261
262  HTML = """
263<html>
264  <head>
265    <style type="text/css">
266
267body {
268  font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
269  font-size: 12px;
270}
271
272pre {
273  margin: 10px;
274  color: #039;
275  font-size: 14px;
276}
277
278.chart {
279  display: inline;
280}
281
282.hidden {
283  visibility: hidden;
284}
285
286.results-section {
287  border: 1px solid #b9c9fe;
288  margin: 10px;
289}
290
291.results-section-title {
292  background-color: #b9c9fe;
293  color: #039;
294  padding: 7px;
295  font-size: 14px;
296  width: 200px;
297}
298
299.results-section-content {
300  margin: 10px;
301  padding: 10px;
302  overflow:auto;
303}
304
305#box-table-a {
306  font-size: 12px;
307  width: 480px;
308  text-align: left;
309  border-collapse: collapse;
310}
311
312#box-table-a th {
313  padding: 6px;
314  background: #b9c9fe;
315  border-right: 1px solid #fff;
316  border-bottom: 1px solid #fff;
317  color: #039;
318  text-align: center;
319}
320
321#box-table-a td {
322  padding: 4px;
323  background: #e8edff;
324  border-bottom: 1px solid #fff;
325  border-right: 1px solid #fff;
326  color: #669;
327  border-top: 1px solid transparent;
328}
329
330#box-table-a tr:hover td {
331  background: #d0dafd;
332  color: #339;
333}
334
335    </style>
336    <script type='text/javascript' src='https://www.google.com/jsapi'></script>
337    <script type='text/javascript'>
338      google.load('visualization', '1', {packages:['corechart']});
339      google.setOnLoadCallback(init);
340      function init() {
341        switchTab('summary', 'html');
342        %s
343        switchTab('full', 'html');
344        drawTable();
345      }
346      function drawTable() {
347        %s
348      }
349      function switchTab(table, tab) {
350        document.getElementById(table + '-html').style.display = 'none';
351        document.getElementById(table + '-text').style.display = 'none';
352        document.getElementById(table + '-tsv').style.display = 'none';
353        document.getElementById(table + '-' + tab).style.display = 'block';
354      }
355    </script>
356  </head>
357
358  <body>
359    <div class='results-section'>
360      <div class='results-section-title'>Summary Table</div>
361      <div class='results-section-content'>
362        <div id='summary-html'>%s</div>
363        <div id='summary-text'><pre>%s</pre></div>
364        <div id='summary-tsv'><pre>%s</pre></div>
365      </div>
366      %s
367    </div>
368    %s
369    <div class='results-section'>
370      <div class='results-section-title'>Charts</div>
371      <div class='results-section-content'>%s</div>
372    </div>
373    <div class='results-section'>
374      <div class='results-section-title'>Full Table</div>
375      <div class='results-section-content'>
376        <div id='full-html'>%s</div>
377        <div id='full-text'><pre>%s</pre></div>
378        <div id='full-tsv'><pre>%s</pre></div>
379      </div>
380      %s
381    </div>
382    <div class='results-section'>
383      <div class='results-section-title'>Experiment File</div>
384      <div class='results-section-content'>
385        <pre>%s</pre>
386    </div>
387    </div>
388  </body>
389</html>
390"""
391
392  PERF_HTML = """
393    <div class='results-section'>
394      <div class='results-section-title'>Perf Table</div>
395      <div class='results-section-content'>
396        <div id='perf-html'>%s</div>
397        <div id='perf-text'><pre>%s</pre></div>
398        <div id='perf-tsv'><pre>%s</pre></div>
399      </div>
400      %s
401    </div>
402"""
403
404  def __init__(self, experiment):
405    super(HTMLResultsReport, self).__init__(experiment)
406
407  def _GetTabMenuHTML(self, table):
408    return """
409<div class='tab-menu'>
410  <a href="javascript:switchTab('%s', 'html')">HTML</a>
411  <a href="javascript:switchTab('%s', 'text')">Text</a>
412  <a href="javascript:switchTab('%s', 'tsv')">TSV</a>
413</div>""" % (table, table, table)
414
415  def GetReport(self):
416    chart_javascript = ""
417    charts = self._GetCharts(self.labels, self.benchmark_runs)
418    for chart in charts:
419      chart_javascript += chart.GetJavascript()
420    chart_divs = ""
421    for chart in charts:
422      chart_divs += chart.GetDiv()
423
424    summary_table = self.GetSummaryTables()
425    full_table = self.GetFullTables()
426    perf_table = self.GetSummaryTables(perf=True)
427    if perf_table:
428      perf_html = self.PERF_HTML % (
429          self.PrintTables(perf_table, "HTML"),
430          self.PrintTables(perf_table, "PLAIN"),
431          self.PrintTables(perf_table, "TSV"),
432          self._GetTabMenuHTML("perf")
433          )
434      perf_init = "switchTab('perf', 'html');"
435    else:
436      perf_html = ""
437      perf_init = ""
438
439    return self.HTML % (perf_init,
440                        chart_javascript,
441                        self.PrintTables(summary_table, "HTML"),
442                        self.PrintTables(summary_table, "PLAIN"),
443                        self.PrintTables(summary_table, "TSV"),
444                        self._GetTabMenuHTML("summary"),
445                        perf_html,
446                        chart_divs,
447                        self.PrintTables(full_table, "HTML"),
448                        self.PrintTables(full_table, "PLAIN"),
449                        self.PrintTables(full_table, "TSV"),
450                        self._GetTabMenuHTML("full"),
451                        self.experiment.experiment_file)
452
453  def _GetCharts(self, labels, benchmark_runs):
454    charts = []
455    ro = ResultOrganizer(benchmark_runs, labels)
456    result = ro.result
457    for item in result:
458      runs = result[item]
459      tg = TableGenerator(runs, ro.labels)
460      table = tg.GetTable()
461      columns = [Column(AmeanResult(),
462                        Format()),
463                 Column(MinResult(),
464                        Format()),
465                 Column(MaxResult(),
466                        Format())
467                ]
468      tf = TableFormatter(table, columns)
469      data_table = tf.GetCellTable()
470
471      for i in range(2, len(data_table)):
472        cur_row_data = data_table[i]
473        autotest_key = cur_row_data[0].string_value
474        title = "{0}: {1}".format(item, autotest_key.replace("/", ""))
475        chart = ColumnChart(title, 300, 200)
476        chart.AddColumn("Label", "string")
477        chart.AddColumn("Average", "number")
478        chart.AddColumn("Min", "number")
479        chart.AddColumn("Max", "number")
480        chart.AddSeries("Min", "line", "black")
481        chart.AddSeries("Max", "line", "black")
482        cur_index = 1
483        for label in ro.labels:
484          chart.AddRow([label, cur_row_data[cur_index].value,
485                        cur_row_data[cur_index + 1].value,
486                        cur_row_data[cur_index + 2].value])
487          if isinstance(cur_row_data[cur_index].value, str):
488            chart = None
489            break
490          cur_index += 3
491        if chart:
492          charts.append(chart)
493    return charts
494