Do not create multiple DimValue instances of the same value
[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 DimensionTraffic(Dimension):
121     def __init__(self):
122         Dimension.__init__(self, 'traf', 'Traffic')
123     def val2str(self, v):
124         if v == "50":
125             return "50%"
126         elif v == "oneatatime":
127             return "one message at a time"
128         else:
129             return v
130     def htmlTableHeading(self, v):
131         return self.val2str(v)
132 class Test(object):
133     @classmethod
134     def isOnPath(cls, path):
135         f = os.path.join(path, '.results')
136         return os.path.isfile(f)
137     def __init__(self, path, values, tests=None):
138         self.path = path
139         self.name = os.path.basename(path)
140         self.values = values
141         self.tests = tests
142     def printThumbLink(self, file):
143         thumb = self.path+'/thumb'
144         try:
145             imgs = [img for img in dircache.listdir(thumb)]
146         except OSError:
147             imgs = [ self.name + ".png" ]
148         for img in imgs:
149             print >>file, "<a href='%s/results.html'><img src='%s/thumb/%s'></a>" % \
150                   (urllib.quote(self.path), urllib.quote(self.path), img)
151     def generateHtml(self):
152         html = open(os.path.join(self.path, 'results.html'), "w")
153         title = "CAN gateway timing analysis"
154         cdup = "../"*len(self.values)
155         print >> html, """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
156 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
157 <head>
158 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
159 <title>%s</title>
160 <link rel="stylesheet" href="%sstyle.css" type="text/css" /> 
161 </head>
162 <body>
163 <h1>%s</h1>"""  % (title, cdup, title)
164         params = ["%s %s" % (v.dim, v) for v in self.values]
165         print >>html, "Results for:", ", ".join(params)
166         print >>html, "<div class='box'><h4>Other results</h4>"
167         for d in self.tests.space:
168             links = []
169             for v in d:
170                 if v in self.values:
171                     print "XXX", repr(v)
172                     links.append(str(v))
173                 else:
174                     vv = DimValues(self.values)
175                     vv.replace(v)
176                     href = cdup + urllib.quote(self.tests[vv.key()].path+"/results.html")
177                     links.append("<a href='%s'>%s</a>"%(href, str(v)))
178             print >>html, "%s: " % d, " | ".join(links), "<br>"
179
180         print >>html, "</div>"
181         print >>html, "<div><img src='%s' /></div>" % (self.name+".png")
182         print >>html, "<a href='./'>Raw data</a><br />"
183         print >>html, "<a href='%s'>Script source</a><br />" % (cdup+self.name+".sh.html")
184         print >>html, "<a href='%s'>Back to top</a><br />" % cdup
185         
186         html.close()
187
188 class Space(list):
189     """List of Dimensions()s (order matters)"""
190     def __init__(self, *dimensions):
191         self.extend(list(dimensions))
192     def path2dimValues(self, path):
193         coordinates = path.split("/")
194         if len(coordinates) != len(self):
195             raise KeyError("The number coordinates do not match the number of dimensions: " + str(coordinates))
196         
197         dv = DimValues([DimValue(self[i], coordinates[i]) \
198                             for i in xrange(len(coordinates))])
199         return dv
200
201     def iterValues(self):
202         idx = [0 for i in xrange(len(self))]
203         done=False
204         while not done:
205             values=DimValues()
206             for i in xrange(len(self)):
207                 values.append(self[i].values()[idx[i]])
208             yield values
209             done=True
210             for i in xrange(len(self)):
211                 idx[i] += 1
212                 if idx[i] < len(self[i]):
213                     done=False
214                     break
215                 idx[i] = 0
216     def reorder(self, dimValues):
217         reordered = DimValues()
218         for d in self:
219             for v in dimValues:
220                 if v.dim == d:
221                     reordered.append(v)
222         return reordered
223     def iterDimensionPairs(self):
224         for i in xrange(len(self)):
225             for j in xrange(i+1, len(self)):
226                 yield (self[i], self[j])
227                 yield (self[j], self[i])
228     def iterRemainingDimensions(self, dimensionPair):
229         for d in self:
230             if d not in dimensionPair:
231                 yield d
232
233
234 class Tests(dict):
235     """Represents all tests organized along several dimensions"""
236     def __init__(self, rootpath, space):
237         dict.__init__(self)
238         self.space = space
239         if (rootpath):
240             self.populate(rootpath)
241     def getTest(self, key):
242         if len(key) != len(self.space):
243             raise KeyError("The coordinates in key do not match the dimension of the space")
244         realkey = self.space.reorder(key)
245         return self[realkey.key()]
246
247     def addTest(self, test):
248         self[test.values.key()] = test
249         
250     def populate(self, rootpath):
251         for root, dirs, files in os.walk(rootpath):
252             if (root.find(rootpath) == 0):
253                 path = root[len(rootpath):]
254             else:
255                 path = rootpath
256             if Test.isOnPath(root):
257                 dv = self.space.path2dimValues(path)
258                 self.addTest(Test(root, dv, self))
259     def generateHtml(self):
260         for pair in self.space.iterDimensionPairs():
261             remDims = Space(*tuple([d for d in self.space.iterRemainingDimensions(pair)]))
262             for vals in remDims.iterValues():
263                 page = Page(pair, vals, self)
264                 print page.getName()
265                 page.generate()
266         try:
267             os.remove("index.html")
268         except OSError: pass
269         os.symlink(page.getName(), "index.html")
270         css = open("style.css", "w")
271         print >>css, """img { border: 0; }
272 table { border-collapse: collapse; }
273 th, td { border: 1px solid lightgray; padding: 4px;}
274 h4 { margin: 0; }
275 .box { border: 1px solid black; padding: 1ex; margin: 1ex 0}
276 """
277         css.close()
278         for test in self.values():
279             print test.path
280             test.generateHtml()
281
282         os.system("source-highlight -d --output-dir=. ../*.sh > /dev/null")
283
284 class Page(object):
285     def __init__(self, dimPair, valsOther, tests):
286         self.dimy, self.dimx = dimPair
287         self.dimOther = [v.dim for v in valsOther]
288         self.valsOther = tests.space.reorder(valsOther)
289         self.tests = tests
290     def getName(self):
291         return "%s-vs-%s-for-%s.html"%(self.dimy.type, self.dimx.type,
292                                        "-".join([v.value for v in self.valsOther]))
293     def generate(self):
294         html = open(self.getName(), "w")
295         title = "CAN gateway timing analysis" 
296         print >> html, """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
297 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
298 <head>
299 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
300 <title>%s</title>
301 <link rel="stylesheet" href="style.css" type="text/css" /> 
302 </head>
303 <body>
304 <h1>%s</h1>"""  % (title, title)
305         params = ["%s %s" % (v.dim, v) for v in self.valsOther]
306         print >>html, "<h3>Results for ", ", ".join(params), "</h3>"
307         print >>html, "<div class='box'><h4>Other views</h4>"
308         for d in self.dimOther:
309             print >>html, "%s: " % d
310             print >>html, "<a href='%s'>X axis</a>, " % \
311                 Page((self.dimy, d), self.valsOther - d + self.dimx.getValue(0), self.tests).getName()
312             print >>html, "<a href='%s'>Y axis</a>;&nbsp;&nbsp;" % \
313                 Page((d, self.dimx), self.valsOther - d + self.dimy.getValue(0), self.tests).getName()
314             links = []
315             for v in d:
316                 if v in self.valsOther:
317                     links.append(str(v))
318                 else:
319                     vv = DimValues(self.valsOther)
320                     vv.replace(v)
321                     links.append("<a href='%s'>%s</a>"%(urllib.quote(Page((self.dimy, self.dimx), vv, self.tests).getName()), str(v)))
322             print >>html, " | ".join(links)
323             print >>html, "<br>"
324             try:
325                 print >>html, d.htmlPreamble()
326             except Exception:
327                 pass
328         print >>html, "</div>"
329
330         print >>html, "<table><thead><tr><td>%s &rarr; <br />%s &darr;</td>" % (self.dimx.name, self.dimy.name)
331         for x in self.dimx:
332             print >>html, "<th>%s</th>" % x.htmlTableHeading()
333         print >>html, "</tr></thead>"
334         for y in self.dimy:
335             print >>html, "<tr><th>%s</th>" % y.htmlTableHeading()
336
337             for x in self.dimx:
338                 print >>html, "<td>"
339                 idx = [x,y]
340                 idx.extend(self.valsOther)
341                 try:
342                     test = tests.getTest(idx)
343                     test.printThumbLink(html)
344                 except KeyError:
345                     print >>html, "N/A"
346                 print >>html, "</td>"
347             print >>html, "</tr>"
348         print >> html, """
349 </table>
350 <div style="font-size: small; color: gray; margin-top: 1em;">Authors: Michal Sojka, Pavel Píša, Copyright © 2010 Czech Technical University in Prague</div>
351 </body>
352 """
353
354
355 if __name__ == "__main__":
356     os.chdir(sys.argv[1])
357     os.system("rm *.html")
358     tests = Tests("./", Space(DimensionHostKern(), DimensionKern(), DimensionTraffic(), DimensionTest()))
359     tests.generateHtml()
360     sys.exit(0)