From: Michal Sojka Date: Wed, 5 Feb 2014 21:09:37 +0000 (+0100) Subject: Add wvperf2html from NUL X-Git-Tag: fix-allnoconfig~31 X-Git-Url: http://rtime.felk.cvut.cz/gitweb/can-benchmark.git/commitdiff_plain/a71c3ce5c2153fed059f7a493c55f490d75964b2 Add wvperf2html from NUL --- diff --git a/continuous/www/wvperf2html.py b/continuous/www/wvperf2html.py new file mode 100755 index 0000000..b690f63 --- /dev/null +++ b/continuous/www/wvperf2html.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python +# +# WvTest: +# Copyright (C) 2012, 2014 Michal Sojka +# Licensed under the GNU Library General Public License, version 2. +# See the included file named LICENSE for license information. +# +# This script converts a sequence of wvtest protocol outputs with +# results of performance measurements to interactive graphs (HTML + +# JavaScript). An example can be seen at +# http://os.inf.tu-dresden.de/~sojka/nul/performance.html. + +from __future__ import print_function +import sys +import re +import os +import os.path +import string +import time +import numpy as np +import json + + +re_prefix = "\([0-9]+\) (?:# )?" +re_date = re.compile('^Date: (.*)') +re_testing = re.compile('^('+re_prefix+')?\s*Testing "(.*)" in (.*):\s*$') +re_commit = re.compile('.*(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}).*, commit: (.*)') +re_commithash = re.compile('([0-9a-f]{7})(-dirty)? \(') +re_assertion = re.compile('^('+re_prefix+')?!\s*(.*?)\s+(\S+)\s*$') +re_perf = re.compile('^('+re_prefix+')?!\s*(.*?)\s+PERF:\s*(.*?)\s+(\S+)\s*$') +re_perfaxis = re.compile('axis="([^"]+)"') + +def dateConv(date): + d = time.gmtime(time.mktime(date)) + return int(time.mktime(d))*1000 + + +class Axis: + def __init__(self, name=None, units=None): + self.name = name + self.units = units + self.num = None + def getLabel(self): + if self.units and self.name: + return "%s [%s]" % (self.name, self.units) + elif self.units: + return self.units + else: + return self.name + def __repr__(self): return "Axis(name=%s units=%s, id=%s)" % (self.name, self.units, hex(id(self))) + +class Column: + def __init__(self, name, units, axis): + self.name = name + self.units = units + self.axis = axis + def __repr__(self): return "Column(name=%s units=%s axis=%s)" % (self.name, self.units, repr(self.axis)) + +class Row(dict): + def __init__(self, graph, date): + self.graph = graph + self.date = date + def __getitem__(self, column): + try: + return dict.__getitem__(self, column) + except KeyError: + return None + def getDate(self): + return dateConv(self.date) + +class Graph: + def __init__(self, id, title): + self.columns = {} + self.columns_ordered = [] + self.id = id + self.title = title + self.rows = [] + self.date2row = {} + self.axes = {} + self.axes_ordered = [] + self.dataname = title.translate(string.maketrans(" /", "--"), "\"':,+()").lower()+".json" + + def __getitem__(self, date): + try: + rownum = self.date2row[date] + except KeyError: + rownum = len(self.rows) + self.date2row[date] = rownum + try: + return self.rows[rownum] + except IndexError: + self.rows[rownum:rownum] = [Row(self, date)] + return self.rows[rownum] + + def addValue(self, date, col, val, units): + row = self[date] + row[col] = val + if col not in self.columns: + axis=self.getAxis(units) or self.addAxis(units, Axis(units=units)) + column = Column(col, units, axis) + self.columns[col] = column + self.columns_ordered.append(column) + else: + column = self.columns[col] + self.columns_ordered.remove(column) + self.columns_ordered.append(column) + self.columns[col].units=units + self.columns[col].axis.units=units + + def addAxis(self, key, axis): + self.axes[key] = axis + return axis + + def setAxis(self, col, key): + self.columns[col].axis = self.getAxis(key) or self.addAxis(key, Axis(name=key)) + + def getAxis(self, key): + if key not in self.axes: return None + return self.axes[key] + + def findRanges(self): + for axis in list(self.axes.values()): + cols = [col for col in list(self.columns.values()) if col.axis == axis] + values = [] + for col in cols: + allvalues = np.array([row[col.name] for row in self.rows if row[col.name] != None], np.float64) + lastmonth = allvalues[-30:] + values.extend(lastmonth); + if len(values) > 0: + axis.minrange = np.mean(values)/10.0 + + def fixupAxisNumbers(self): + # Sort axes according to the columns and number them + num = 0 + for column in self.columns_ordered: + axis = column.axis + if axis not in self.axes_ordered: + self.axes_ordered.insert(0, axis) + axis.num = num + num += 1 + num = 0 + for axis in self.axes_ordered: + axis.num = num + num += 1 + + def options_json(self): + options = { + 'rangeSelector': { + 'selected': 2 # 6m + }, + 'title': { + 'text': self.title + }, + 'legend': { + 'enabled': True, + 'floating': False, + 'verticalAlign': "top", + 'x': 100, + 'y': 60, + }, + 'tooltip': { + 'formatter': "FUN(tooltip_formatter)END", + 'style': { + 'whiteSpace': 'normal', + 'width': '400px', + }, + }, + 'plotOptions': { + 'series': { + 'events': { + 'click': "FUN(series_onclick)END", + }, + 'dataGrouping' : { + 'enabled' : False, + }, + } + }, + 'yAxis': [{ + 'lineWidth': 1, + 'labels': { 'align': 'right', + 'x': -3 }, + 'title': { 'text': axis.getLabel() }, + 'minRange': axis.minrange, + } for axis in self.axes_ordered], + 'series': [{ 'name': '%s [%s]' % (col.name, col.units), + 'yAxis': col.axis.num } + for col in self.columns_ordered] + } + return json.dumps(options, indent=True).replace('"FUN(', '').replace(')END"', '') + + def getData(self): + data = [[[row.getDate(), row[col.name]] for row in self.rows] for col in self.columns_ordered] + return json.dumps(data).replace('], [', '],\n[') + + +class Graphs(dict): + pass + +graphs = Graphs() +date2commit = {} +commit2msg = {} + +date = time.localtime(time.time()) + +for line in sys.stdin: + line = line.rstrip() + + match = re_date.match(line) + if (match): + date = time.strptime(match.group(1), "%a, %d %b %Y %H:%M:%S +0200") + continue + + match = re_testing.match(line) + if match: + what = match.group(2) + where = match.group(3) + + match = re_commit.match(what) + if match: + date = time.strptime(match.group(1), "%Y-%m-%d %H:%M:%S") + commit = match.group(2) + match = re_commithash.search(commit); + if match: + commithash = match.group(1) + else: + commithash = None + date2commit[dateConv(date)] = commithash + commit2msg[commithash] = commit + + (basename, ext) = os.path.splitext(os.path.basename(where)) + + if what != "all": title = what + else: title = basename + try: + graph = graphs[basename] + except KeyError: + graph = Graph(basename, title) + graphs[basename] = graph + continue + + match = re_perf.match(line) + if match: + perfstr = match.group(3) + perf = perfstr.split() + col = perf[0] + try: + val = float(perf[1]) + except ValueError: + val = None + try: + units = perf[2] + if '=' in units: units = None + except: + units = None + if match.group(4) != "ok": + val=None + + graph.addValue(date, col, val, units) + + match = re_perfaxis.search(perfstr) + if match: + graph.setAxis(col, match.group(1)); + +graphs = [g for g in list(graphs.values()) if len(g.columns)] +graphs = sorted(graphs, key=lambda g: g.title.lower()) + +for g in graphs: + g.findRanges() + g.fixupAxisNumbers() + +print(""" + + + + + NUL Performance Plots + + + + + + + +

NUL Performance Plots

+

The graphs below show performance numbers from various + benchmarks that run nightly on NUL repository.

+

Table of content:

+ ") +for graph in graphs: + print(""" +

%(title)s

+
+ +""" % {'id': graph.id, + 'title': graph.title, + 'dataname': graph.dataname, + 'options': graph.options_json()}) + print(graph.getData(), file=open(graph.dataname, 'w')) +print(""" + + +""") + +# Local Variables: +# compile-command: "make perf" +# End: