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