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