]> rtime.felk.cvut.cz Git - wvtest.git/blob - tools/wvperf2html.py
Put the definition of prefix to a variable
[wvtest.git] / tools / wvperf2html.py
1 #!/usr/bin/env python
2
3 import sys
4 import re
5 import os
6 import os.path
7 import string
8 import time
9 import numpy as np
10
11 re_prefix = "\([0-9]+\) (?:#   )?"
12 re_date = re.compile('^Date: (.*)')
13 re_testing = re.compile('^('+re_prefix+')?\s*Testing "(.*)" in (.*):\s*$')
14 re_commit = re.compile('.*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*, commit: (.*)')
15 re_commithash = re.compile('([0-9a-f]{7})(-dirty)? \(')
16 re_assertion = re.compile('^('+re_prefix+')?!\s*(.*?)\s+(\S+)\s*$')
17 re_perf =  re.compile('^('+re_prefix+')?!\s*(.*?)\s+PERF:\s*(.*?)\s+(\S+)\s*$')
18 re_perfaxis = re.compile('axis="([^"]+)"')
19
20 class Axis:
21     def __init__(self, name=None, units=None):
22         self.name = name
23         self.units = units
24         self.num = None
25     def getLabel(self):
26         if self.units and self.name:
27             return "%s [%s]" % (self.name, self.units)
28         elif self.units:
29             return self.units
30         else:
31             return self.name
32     def __repr__(self): return "Axis(name=%s units=%s, id=%s)" % (self.name, self.units, hex(id(self)))
33
34 class Column:
35     def __init__(self, name, units, axis):
36         self.name = name
37         self.units = units
38         self.axis = axis
39     def __repr__(self): return "Column(name=%s units=%s axis=%s)" % (self.name, self.units, repr(self.axis))
40
41 class Row(dict):
42     def __init__(self, graph, date):
43         self.graph = graph
44         self.date = date
45     def __getitem__(self, column):
46         try:
47             return dict.__getitem__(self, column)
48         except KeyError:
49             return None
50     def getDate(self):
51         d = time.gmtime(time.mktime(self.date))
52         return "Date.UTC(%s, %s, %s, %s, %s, %s)" % \
53             (d.tm_year, d.tm_mon-1, d.tm_mday, d.tm_hour, d.tm_min, d.tm_sec)
54
55 class Graph:
56     def __init__(self, id, title):
57         self.columns = {}
58         self.columns_ordered = []
59         self.id = id
60         self.title = title
61         self.rows = []
62         self.date2row = {}
63         self.axes = {}
64         self.axes_ordered = []
65
66     def __getitem__(self, date):
67         try:
68             rownum = self.date2row[date]
69         except KeyError:
70             rownum = len(self.rows)
71             self.date2row[date] = rownum
72         try:
73             return self.rows[rownum]
74         except IndexError:
75             self.rows[rownum:rownum] = [Row(self, date)]
76             return self.rows[rownum]
77
78     def addValue(self, date, col, val, units):
79         row = self[date]
80         row[col] = val
81         if not self.columns.has_key(col):
82             axis=self.getAxis(units) or self.addAxis(units, Axis(units=units))
83             column = Column(col, units, axis)
84             self.columns[col] = column
85             self.columns_ordered.append(column)
86         else:
87             column = self.columns[col]
88             self.columns_ordered.remove(column)
89             self.columns_ordered.append(column)
90         self.columns[col].units=units
91         self.columns[col].axis.units=units
92
93     def addAxis(self, key, axis):
94         self.axes[key] = axis
95         return axis
96
97     def setAxis(self, col, key):
98         self.columns[col].axis = self.getAxis(key) or self.addAxis(key, Axis(name=key))
99
100     def getAxis(self, key):
101         if not self.axes.has_key(key): return None
102         return self.axes[key]
103
104     def findRanges(self):
105         for axis in self.axes.values():
106             cols = [col for col in self.columns.values() if col.axis == axis]
107             low = None
108             high = None
109             all_in_range = True
110             for col in cols:
111                 values = np.array([row[col.name] for row in self.rows if row[col.name] != None], np.float64)
112                 if low == None and high == None:
113                     lastmonth = values[-30:]
114                     median = np.median(lastmonth)
115                     low  = median * 0.95
116                     high = median * 1.05
117
118                 if (values > high).any() or (values < low).any():
119                     all_in_range = False
120             if all_in_range:
121                 axis.yrange_max = high
122                 axis.yrange_min = low
123             else:
124                 axis.yrange_max = None
125                 axis.yrange_min = None
126
127     def fixupAxisNumbers(self):
128         # Sort axes according to the columns and number them
129         num = 0
130         for column in self.columns_ordered:
131             axis = column.axis
132             if axis not in self.axes_ordered:
133                 self.axes_ordered.insert(0, axis)
134                 axis.num = num
135                 num += 1
136         num = 0
137         for axis in self.axes_ordered:
138             axis.num = num
139             num += 1
140
141     def jschart(self):
142         print """
143                         window.chart = new Highcharts.StockChart({
144                             chart: {
145                                 renderTo: '"""+self.id+"""'
146                             },
147
148                             rangeSelector: {
149                                 selected: 1
150                             },
151
152                             title: {
153                                 text: '"""+self.title+"""'
154                             },
155                             legend: {
156                                 enabled: true,
157                                 floating: false,
158                                 verticalAlign: "top",
159                                 x: 100,
160                                 y: 60,
161                             },
162                             tooltip: {
163                                 formatter: function() {
164                                     var s = '<b>'+ Highcharts.dateFormat('%a, %d %b %Y %H:%M:%S', this.x) +'</b><br/>';
165                                     s += commitMap[this.x].msg;
166                                     $.each(this.points, function(i, point) {
167                                         s += '<br/><span style="color:'+ point.series.color+';">'+ point.series.name +'</span>: '+point.y;
168                                     });
169                                     return s;
170                                 },
171                                 style: {
172                                     whiteSpace: 'normal',
173                                     width: '400px',
174                                 },
175                             },
176                             plotOptions: {
177                                 series: {
178                                     events: {
179                                         click: function(event) {
180                                             var lastpoint = null;
181                                             for (var i in this.data) {
182                                               if (event.point == this.data[i]) {
183                                                 if (i > 0) lastpoint = this.data[i-1];
184                                                 break;
185                                               }
186                                             }
187                                             if (lastpoint)
188                                               window.location = "http://os.inf.tu-dresden.de/~jsteckli/cgi-bin/cgit.cgi/nul/log/?qt=range&q="+commitMap[lastpoint.x].hash+'..'+commitMap[event.point.x].hash;
189                                             else
190                                               window.location = "http://os.inf.tu-dresden.de/~jsteckli/cgi-bin/cgit.cgi/nul/log/?id="+commitMap[event.point.x].hash;
191                                         }
192                                     }
193                                 }
194                             },
195                             yAxis: ["""
196         for axis in self.axes_ordered:
197             print "\t\t\t\t{"
198             print "\t\t\t\t\tlineWidth: 1,"
199             print "\t\t\t\t\tlabels: { align: 'right', x: -3 },"
200             print "\t\t\t\t\ttitle: { text: '%s' }," % axis.getLabel()
201             #print "\t\t\t\t\tplotBands: { from: %s, to: %s, color: '#eee' }," % (col.low, col.high)
202             if axis.yrange_min: print "\t\t\t\t\tmin: %s," % axis.yrange_min
203             if axis.yrange_max: print "\t\t\t\t\tmax: %s," % axis.yrange_max
204             print "\t\t\t\t},"
205         print """\t\t\t    ],
206
207                             series: ["""
208         num = 0
209         for col in self.columns_ordered:
210             print "\t\t\t\t{ name: '%s [%s]', yAxis: %d, data: [" % (col.name, col.units, col.axis.num)
211             num += 1
212             for row in self.rows:
213                 val = row[col.name]
214                 if val == None: val = "null"
215                 print "\t\t\t\t\t[%s, %s], " % (row.getDate(), val)
216             print "\t\t\t\t]},"
217         print """\t\t\t    ],
218                         });"""
219
220 class Graphs(dict):
221     pass
222
223 graphs = Graphs()
224 commits = {}
225
226 date = time.localtime(time.time())
227
228 for line in sys.stdin.readlines():
229     line = line.rstrip()
230
231     match = re_date.match(line)
232     if (match):
233         date = time.strptime(match.group(1), "%a, %d %b %Y %H:%M:%S +0200")
234         continue
235
236     match = re_testing.match(line)
237     if match:
238         what = match.group(2)
239         where = match.group(3)
240
241         match = re_commit.match(what)
242         if match:
243             date = time.strptime(match.group(1), "%Y-%m-%d %H:%M:%S")
244             commit = match.group(2)
245             match = re_commithash.search(commit);
246             if match:
247                 commithash = match.group(1)
248             else:
249                 commithash = None
250             commits[date] = (commit, commithash)
251
252         (basename, ext) = os.path.splitext(os.path.basename(where))
253
254         if what != "all": title = what
255         else: title = basename
256         try:
257             graph = graphs[basename]
258         except KeyError:
259             graph = Graph(basename, title)
260             graphs[basename] = graph
261         continue
262
263     match = re_perf.match(line)
264     if match:
265         perfstr = match.group(3)
266         perf = perfstr.split()
267         col = perf[0]
268         try:
269             val = float(perf[1])
270         except ValueError:
271             val = None
272         try:
273             units = perf[2]
274             if '=' in units: units = None
275         except:
276             units = None
277         if match.group(4) != "ok":
278             val=None
279
280         graph.addValue(date, col, val, units)
281
282         match = re_perfaxis.search(perfstr)
283         if match:
284             graph.setAxis(col, match.group(1));
285
286 graphs = [g for g in graphs.values() if len(g.columns)]
287 graphs = sorted(graphs, key=lambda g: g.title.lower())
288
289 for g in graphs:
290     g.findRanges()
291     g.fixupAxisNumbers()
292
293 print """
294 <!DOCTYPE HTML>
295 <html>
296     <head>
297         <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
298         <title>NUL Performance Plots</title>
299
300         <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
301         <script type="text/javascript">
302                 var commitMap = {"""
303 for d in sorted(commits.iterkeys()):
304     v = commits[d];
305     print '\t\t\t%d: { msg: "%s", hash: "%s" },' % (1000*time.mktime(d), v[0].replace('"', '\\"'), str(v[1]).replace('"', '\\"'))
306 print """\t\t};
307                 $(function() {"""
308 for graph in graphs:
309     graph.jschart()
310 print """
311                 });
312         </script>
313     </head>
314
315     <body>
316         <h1>NUL Performance Plots</h1>
317         <script type="text/javascript" src="js/highstock.js"></script>
318         <ul>
319 """
320 for graph in graphs:
321     print "     <li><a href='#%s'>%s</a></li>" % (graph.title, graph.title)
322 print "    </ul>"
323 for graph in graphs:
324     print "     <h2><a name='%s'>%s</a></h2>" % (graph.title, graph.title)
325     print '     <div id="%s" style="height: 400px"></div>' % graph.id
326 print """
327     </body>
328 </html>
329 """
330
331 # Local Variables:
332 # compile-command: "cat nul-nightly/nul_*.log|./wvperfpreprocess.py|./wvperf2html.py > graphs.html"
333 # End: