better reports
[framework/uifw/expedite.git] / src / bin / expedite-cmp
1 #!/usr/bin/env python
2
3 import sys
4 import os
5 import os.path
6 import csv
7 from optparse import OptionParser
8
9 fmttext = '%(value)7.2f (%(percentual)+6.1f%%)'
10 fmthtml = '%(value)7.2f <span style="color: #666; width: 55pt; display: inline-block; text-align: right; text-shadow: #999 1px 1px 3px;">(%(percentual)+0.1f%%)</span>'
11
12
13 parser = OptionParser(usage="%prog [options] <reference> <file2> .. <fileN>",
14                       description="""\
15 Generate reports comparing two or more outputs of expedite.
16
17 Just run expedite and save output to a file and then feed them to this
18 program. The first file is used as base for comparison and other files
19 will print relative improvements.
20 """)
21 parser.add_option("-e", "--accepted-error",
22                   help=("maximum error to accept as percentage 0.0-1.0. "
23                         "[default=%default]"),
24                   action="store", type="float", default=0.05)
25 parser.add_option("-r", "--report",
26                   help=("kind of report to use. One of text or html. "
27                         "[default=%default]"),
28                   action="store", type="choice", default="text",
29                   choices=["text", "html"])
30 parser.add_option("-F", "--format",
31                   help=("format to use as python format string, "
32                         "valid keys are: value and percentual. "
33                         "[defaults: html=\"%s\", text=\"%s\"]" %
34                         (fmthtml, fmttext)),
35                   action="store", type="str", default=None)
36 parser.add_option("-C", "--no-color", dest="color",
37                   help="do not use color in reports.",
38                   action="store_false", default=True)
39
40 options, files = parser.parse_args()
41 if len(files) < 2:
42     raise SystemExit("need at least 2 files to compare")
43
44 if options.format is None:
45     if options.report == "html":
46         options.format = fmthtml
47     else:
48         options.format = fmttext
49
50 ref_f = files[0]
51 others_f = files[1:]
52
53 max_test_name = 0
54 data = {}
55 tests = []
56 for f in files:
57     d = data[f] = {}
58     for row in csv.reader(open(f)):
59         t = row[1].strip()
60         if f == ref_f:
61             tests.append(t)
62         d[t] = float(row[0])
63         max_test_name = max(len(t), max_test_name)
64
65 def report_text():
66     test_name_fmt = "%%%ds:" % max_test_name
67
68     fmtsize = len(options.format % {"value": 12345.67, "percentual": 1234.56})
69     hdrfmt = "%%%d.%ds" % (fmtsize, fmtsize)
70
71     print test_name_fmt % "\\",
72     print "%7.7s" % (files[0][-7:],),
73     for f in files[1:]:
74         n, e = os.path.splitext(f)
75         print hdrfmt % n[-fmtsize:],
76     print
77
78     if options.color and os.environ.get("TERM", "") == "xterm":
79         color_good = "\033[1;32m"
80         color_bad = "\033[1;31m"
81         color_equal = "\033[1;30m"
82         color_reset = "\033[0m"
83     else:
84         color_good = ""
85         color_bad = ""
86         color_equal = ""
87         color_reset = ""
88
89
90     def print_row(test):
91         print test_name_fmt % test,
92         ref_val = data[ref_f][test]
93         print "%7.2f" % ref_val,
94         for f in others_f:
95             try:
96                 val = data[f][test]
97             except KeyError:
98                 print "-?????-",
99                 continue
100
101             percent = (val - ref_val) / ref_val
102             if percent < -options.accepted_error:
103                 c = color_bad
104             elif percent > options.accepted_error:
105                 c = color_good
106             else:
107                 c = color_equal
108
109             fmt = options.format % {"value": val, "percentual": percent * 100}
110             if len(fmt) < fmtsize:
111                 fmt = hdrfmt % fmt
112             print "%s%s%s" % (c, fmt, color_reset),
113
114         print
115
116     for t in tests:
117         print_row(t)
118
119
120 def report_html():
121     import time
122
123     fnames = [os.path.basename(f) for f in files]
124     print """\
125 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
126   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
127
128 <html xmlns="http://www.w3.org/1999/xhtml">
129   <head>
130     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
131     <title>expedite comparison sheet: %(files)s</title>
132   </head>
133   <style type="text/css">
134     table
135     {
136        border: 1px solid black;
137        border-collapse: collapse;
138     }
139     thead
140     {
141        border-bottom: 1px solid black;
142     }
143     tr.overall-results
144     {
145        border-top: 1px solid black;
146        font-weight: bold;
147     }
148     td.value, td.value-reference, td.value-missing, td.value-good, td.value-bad, td.value-equal
149     {
150        font-family: courier, monospaced;
151        font-size: 10pt;
152        text-align: right;
153        border-left: 1px solid black;
154        border-bottom: 1px dashed #ccc;
155     }
156     td.test-name, thead tr td { text-align: right; }\
157 """
158     if options.color:
159         print """\
160     td.value-good { background-color: #aaffaa; }
161     td.value-bad { background-color: #ffaaaa; }
162     td.value-missing { background-color: #ffffaa; }
163     td.test-name, thead tr td
164     {
165        font-weight: bold;
166        background-color: #d9d9d9;
167        border-bottom: 1px dashed #ccc;
168     }
169 """
170
171     print """
172   </style>
173   <body>
174      <p>Comparison sheet for %(files)s, created at %(date)s.</p>
175      <table>
176        <thead>
177          <tr>
178            <td>\\</td>\
179 """ % {"files": ", ".join(fnames),
180        "date": time.asctime(),
181        }
182
183     for f in fnames:
184         print """\
185            <td>%s</td>\
186 """ % f
187     print """\
188          </tr>
189        </thead>
190        <tbody>\
191 """
192
193     def print_row(test):
194         ref_val = data[ref_f][test]
195         if "EVAS SPEED" in test.upper():
196             extra_cls = ' class="overall-results"'
197         else:
198             extra_cls = ""
199
200         print """\
201          <tr%s>
202            <td class="test-name">%s</td>
203            <td class="value-reference">%7.2f</td>\
204 """ % (extra_cls, test, ref_val)
205
206         for f in others_f:
207             try:
208                 val = data[f][test]
209             except KeyError:
210                 print """\
211            <td class="value-missing">-?????-</td>\
212 """
213                 continue
214
215             percent = (val - ref_val) / ref_val
216             if percent < -options.accepted_error:
217                 c = 'bad'
218             elif percent > options.accepted_error:
219                 c = 'good'
220             else:
221                 c = 'equal'
222
223             v = options.format % {"value": val, "percentual": percent * 100}
224
225             print """\
226            <td class="value-%s">%s</td>\
227 """ % (c, v)
228
229         print """\
230          </tr>\
231 """
232
233     for t in tests:
234         print_row(t)
235
236     print """\
237        </tbody>
238      </table>
239   </body>
240 </html>
241 """
242
243 if options.report == "text":
244     report_text()
245 elif options.report == "html":
246     report_html()