gethtml: Add load dimenstion
[can-benchmark.git] / gw-tests / genhtml / genhtml.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 import os;
4 import dircache;
5 import sys;
6 import urllib
7 import traceback
8
9 class DimValue(object):
10     def __new__(cls, dim, value):
11         if value in dim:
12             print "OLD", value
13             return dim[value]
14         else:
15             print "NEW", value
16             return super(DimValue, cls).__new__(cls, dim, value)
17     def __init__(self, dim, value):
18         self.dim = dim
19         self.value = value
20         self.dim.addValue(self)
21     def __str__(self):
22         return self.dim.val2str(self.value)
23     def __repr__(self):
24         return "DimValue(%s, %s)" % (repr(self.dim), repr(self.value))
25     def htmlTableHeading(self):
26         return self.dim.htmlTableHeading(self.value)
27
28 class DimValues(list):
29     def replace(self, val):
30         for i in xrange(len(self)):
31             if self[i].dim == val.dim:
32                 self[i] = val
33     def __add__(self, val):
34         ret = DimValues(self)
35         ret.append(val)
36         return ret
37     def __sub__(self, dim):
38         result = DimValues(self)
39         for v in self:
40             if v.dim == dim:
41                 result.remove(v)
42         return result
43     def key(self):
44         return tuple([v.value for v in self])
45
46 class Dimension(dict):
47     def __init__(self, atype, name=None):
48         self.type = atype
49         if (name):
50             self.name = name
51         else:
52             self.name = atype
53         self.sortedKeys = []
54
55     def __iter__(self):
56         for i in xrange(len(self)):
57             yield self.getValue(i)
58     def getValue(self, index):
59         return self[self.sortedKeys[index]]
60
61     def addValue(self, value):
62         if value not in self:
63             if isinstance(value, DimValue):
64                 self[value.value] = value
65             else:
66                 raise Exception("Unsupported usage of addValue")
67                 #self[value] = DimValue(self, value)
68             self.sortedKeys = self.keys()
69             self.sortedKeys.sort()
70     def val2str(self, v):
71         return str(v)
72     def htmlTableHeading(self, v):
73         return self.val2str(v)
74     def __str__(self):
75         return self.name
76     def __repr__(self):
77         return "Dimension(%s)"%self.type
78
79 class DimensionKern(Dimension):
80     def __init__(self):
81         Dimension.__init__(self, 'gwkern', 'GW kernel')
82     def htmlTableHeading(self, v):
83         i=v.find(":")
84         if i>0: kver=v[:i]
85         else: kver=v
86         return v+"<br><a href='config-%s'>config</a>"%(urllib.quote(kver))
87     def versions(self):
88         for v in self.values:
89             i=v.find(":")
90             if i>0: kver=v[:i]
91             else: kver=v
92             yield kver
93
94 class DimensionHostKern(Dimension):
95     def __init__(self):
96         Dimension.__init__(self, 'hostkern', 'Host kernel')
97     def val2str(self, v):
98         if v.find("host-") == 0:
99             v = v[5:]
100         return v
101     def htmlTableHeading(self, v):
102         v = self.val2str(v)
103         i = v.find(":")
104         if i>0: kver = v[:i]
105         else: kver = v
106         return v+"<br><a href='config-%s'>config</a>"%(urllib.quote(kver))
107     def versions(self):
108         for v in self.values:
109             i=v.find(":")
110             if i>0: kver=v[:i]
111             else: kver=v
112             yield kver
113
114 class DimensionTest(Dimension):
115     def __init__(self):
116         Dimension.__init__(self, 'test', 'Test')
117     def htmlTableHeading(self, v):
118         return v+"<br><a href='%s.sh.html'>source</a>"%(urllib.quote(v))
119
120 class DimensionLoad(Dimension):
121     def __init__(self):
122         Dimension.__init__(self, 'load', 'Load')
123
124 class DimensionTraffic(Dimension):
125     def __init__(self):
126         Dimension.__init__(self, 'traf', 'Traffic')
127     def val2str(self, v):
128         if v == "50":
129             return "50%"
130         elif v == "oneatatime":
131             return "one message at a time"
132         else:
133             return v
134     def htmlTableHeading(self, v):
135         return self.val2str(v)
136 class Test(object):
137     @classmethod
138     def isOnPath(cls, path):
139         f = os.path.join(path, '.results')
140         return os.path.isfile(f)
141     def __init__(self, path, values, tests=None):
142         self.path = path
143         self.name = os.path.basename(path)
144         self.values = values
145         self.tests = tests
146     def printThumbLink(self, file):
147         thumb = self.path+'/thumb'
148         try:
149             imgs = [img for img in dircache.listdir(thumb)]
150         except OSError:
151             imgs = [ self.name + ".png" ]
152         for img in imgs:
153             print >>file, "<a href='%s/results.html'><img src='%s/thumb/%s'></a>" % \
154                   (urllib.quote(self.path), urllib.quote(self.path), img)
155     def generateHtml(self):
156         html = open(os.path.join(self.path, 'results.html'), "w")
157         title = "CAN gateway timing analysis"
158         cdup = "../"*len(self.values)
159         print >> html, """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
160 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
161 <head>
162 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
163 <title>%s</title>
164 <link rel="stylesheet" href="%sstyle.css" type="text/css" /> 
165 </head>
166 <body>
167 <h1>%s</h1>"""  % (title, cdup, title)
168         params = ["%s %s" % (v.dim, v) for v in self.values]
169         print >>html, "Results for:", ", ".join(params)
170         print >>html, "<div class='box'><h4>Other results</h4>"
171         for d in self.tests.space:
172             links = []
173             for v in d:
174                 if v in self.values:
175                     links.append(str(v))
176                 else:
177                     vv = DimValues(self.values)
178                     vv.replace(v)
179                     href = cdup + urllib.quote(self.tests[vv.key()].path+"/results.html")
180                     links.append("<a href='%s'>%s</a>"%(href, str(v)))
181             print >>html, "%s: " % d, " | ".join(links), "<br>"
182
183         print >>html, "</div>"
184         print >>html, "<div><img src='%s' /></div>" % (self.name+".png")
185         print >>html, "<a href='./'>Raw data</a><br />"
186         print >>html, "<a href='%s'>Script source</a><br />" % (cdup+self.name+".sh.html")
187         print >>html, "<a href='%s'>Back to top</a><br />" % cdup
188         
189         html.close()
190
191 class Space(list):
192     """List of Dimensions()s (order matters)"""
193     def __init__(self, *dimensions):
194         self.extend(list(dimensions))
195     def path2dimValues(self, path):
196         coordinates = path.split("/")
197         if len(coordinates) != len(self):
198             raise KeyError("The number coordinates do not match the number of dimensions: " + str(coordinates))
199         
200         dv = DimValues([DimValue(self[i], coordinates[i]) \
201                             for i in xrange(len(coordinates))])
202         return dv
203
204     def iterValues(self):
205         idx = [0 for i in xrange(len(self))]
206         done=False
207         while not done:
208             values=DimValues()
209             for i in xrange(len(self)):
210                 values.append(self[i].values()[idx[i]])
211             yield values
212             done=True
213             for i in xrange(len(self)):
214                 idx[i] += 1
215                 if idx[i] < len(self[i]):
216                     done=False
217                     break
218                 idx[i] = 0
219     def reorder(self, dimValues):
220         reordered = DimValues()
221         for d in self:
222             for v in dimValues:
223                 if v.dim == d:
224                     reordered.append(v)
225         return reordered
226     def iterDimensionPairs(self):
227         for i in xrange(len(self)):
228             for j in xrange(i+1, len(self)):
229                 yield (self[i], self[j])
230                 yield (self[j], self[i])
231     def iterRemainingDimensions(self, dimensionPair):
232         for d in self:
233             if d not in dimensionPair:
234                 yield d
235
236
237 class Tests(dict):
238     """Represents all tests organized along several dimensions"""
239     def __init__(self, rootpath, space):
240         dict.__init__(self)
241         self.space = space
242         if (rootpath):
243             self.populate(rootpath)
244     def getTest(self, key):
245         if len(key) != len(self.space):
246             raise KeyError("The coordinates in key do not match the dimension of the space")
247         realkey = self.space.reorder(key)
248         return self[realkey.key()]
249
250     def addTest(self, test):
251         self[test.values.key()] = test
252         
253     def populate(self, rootpath):
254         for root, dirs, files in os.walk(rootpath):
255             if (root.find(rootpath) == 0):
256                 path = root[len(rootpath):]
257             else:
258                 path = rootpath
259             if Test.isOnPath(root):
260                 dv = self.space.path2dimValues(path)
261                 self.addTest(Test(root, dv, self))
262     def generateHtml(self):
263         for pair in self.space.iterDimensionPairs():
264             remDims = Space(*tuple([d for d in self.space.iterRemainingDimensions(pair)]))
265             for vals in remDims.iterValues():
266                 page = Page(pair, vals, self)
267                 print page.getName()
268                 page.generate()
269         try:
270             os.remove("index.html")
271         except OSError: pass
272         os.symlink(page.getName(), "index.html")
273         css = open("style.css", "w")
274         print >>css, """img { border: 0; }
275 table { border-collapse: collapse; }
276 th, td { border: 1px solid lightgray; padding: 4px;}
277 h4 { margin: 0; }
278 .box { border: 1px solid black; padding: 1ex; margin: 1ex 0}
279 """
280         css.close()
281         for test in self.values():
282             print test.path
283             test.generateHtml()
284
285         os.system("source-highlight -d --output-dir=. ../*.sh > /dev/null")
286
287 class Page(object):
288     def __init__(self, dimPair, valsOther, tests):
289         self.dimy, self.dimx = dimPair
290         self.dimOther = [v.dim for v in valsOther]
291         self.valsOther = tests.space.reorder(valsOther)
292         self.tests = tests
293     def getName(self):
294         return "%s-vs-%s-for-%s.html"%(self.dimy.type, self.dimx.type,
295                                        "-".join([v.value for v in self.valsOther]))
296     def generate(self):
297         html = open(self.getName(), "w")
298         title = "CAN gateway timing analysis" 
299         print >> html, """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
300 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
301 <head>
302 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
303 <title>%s</title>
304 <link rel="stylesheet" href="style.css" type="text/css" /> 
305 </head>
306 <body>
307 <h1>%s</h1>"""  % (title, title)
308         params = ["%s %s" % (v.dim, v) for v in self.valsOther]
309         print >>html, "<h3>Results for ", ", ".join(params), "</h3>"
310         print >>html, "<div class='box'><h4>Other views</h4>"
311         for d in self.dimOther:
312             print >>html, "%s: " % d
313             print >>html, "<a href='%s'>X axis</a>, " % \
314                 Page((self.dimy, d), self.valsOther - d + self.dimx.getValue(0), self.tests).getName()
315             print >>html, "<a href='%s'>Y axis</a>;&nbsp;&nbsp;" % \
316                 Page((d, self.dimx), self.valsOther - d + self.dimy.getValue(0), self.tests).getName()
317             links = []
318             for v in d:
319                 if v in self.valsOther:
320                     links.append(str(v))
321                 else:
322                     vv = DimValues(self.valsOther)
323                     vv.replace(v)
324                     links.append("<a href='%s'>%s</a>"%(urllib.quote(Page((self.dimy, self.dimx), vv, self.tests).getName()), str(v)))
325             print >>html, " | ".join(links)
326             print >>html, "<br>"
327             try:
328                 print >>html, d.htmlPreamble()
329             except Exception:
330                 pass
331         print >>html, "</div>"
332
333         print >>html, "<table><thead><tr><td>%s &rarr; <br />%s &darr;</td>" % (self.dimx.name, self.dimy.name)
334         for x in self.dimx:
335             print >>html, "<th>%s</th>" % x.htmlTableHeading()
336         print >>html, "</tr></thead>"
337         for y in self.dimy:
338             print >>html, "<tr><th>%s</th>" % y.htmlTableHeading()
339
340             for x in self.dimx:
341                 print >>html, "<td>"
342                 idx = [x,y]
343                 idx.extend(self.valsOther)
344                 try:
345                     test = tests.getTest(idx)
346                     test.printThumbLink(html)
347                 except KeyError:
348                     print >>html, "N/A"
349                 print >>html, "</td>"
350             print >>html, "</tr>"
351         print >> html, """
352 </table>
353 <div style="font-size: small; color: gray; margin-top: 1em;">Authors: Michal Sojka, Pavel Píša, Copyright © 2010 Czech Technical University in Prague</div>
354 </body>
355 """
356
357
358 if __name__ == "__main__":
359     os.chdir(sys.argv[1])
360     os.system("rm *.html")
361     tests = Tests("./", Space(DimensionHostKern(), DimensionKern(), DimensionTraffic(), DimensionLoad(), DimensionTest()))
362     tests.generateHtml()
363     sys.exit(0)