Add dynamic graphing capability to TKO.
Signed-off-by: Martin J. Bligh <mbligh@google.com>
git-svn-id: http://test.kernel.org/svn/autotest/trunk@680 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/tko/frontend.py b/tko/frontend.py
index 85124c2..55ec215 100755
--- a/tko/frontend.py
+++ b/tko/frontend.py
@@ -42,18 +42,24 @@
def __init__(self, db, test_idx, job_idx, testname, subdir, kernel_idx, status_num, reason, machine):
self.idx = test_idx
- self.job = None
self.job = job(db, job_idx)
# self.machine = self.job.machine
self.test = testname
self.subdir = subdir
- self.kernel = None
- # self.kernel = kernel.select(db, {'kernel_idx' : kernel_idx})
+ self.kernel = kernel.select(db, {'kernel_idx' : kernel_idx})[0]
self.status_num = status_num
self.status_word = db.status_word[status_num]
self.reason = reason
self.url = html_root + self.job.tag + '/' + self.subdir
-
+
+ self.iterations = {}
+ # Create a dictionary - dict{key} = [value1, value2, ....]
+ for i in iteration.select(db, {'test_idx' : test_idx}):
+ if self.iterations.has_key(i.key):
+ self.iterations[i.key].append(i.value)
+ else:
+ self.iterations[i.key] = [i.value]
+
class job:
def __init__(self, db, job_idx):
@@ -64,12 +70,22 @@
(self.tag, self.machine) = rows[0]
+class iteration:
+ @classmethod
+ def select(klass, db, where):
+ fields = ['iteration', 'attribute', 'value']
+ iterations = []
+ rows = db.select(','.join(fields), 'iteration_result', where)
+ for row in rows:
+ iterations.append(klass(*row))
+ return iterations
+
+
+ def __init__(self, iteration, key, value):
+ self.iteration = iteration
+ self.key = key
+ self.value = value
+
# class patch:
# def __init__(self):
# self.spec = None
-#
-#
-# class iteration:
-# def __init__(self):
-# self.a = None
-#
diff --git a/tko/machine_test_attribute_graph.cgi b/tko/machine_test_attribute_graph.cgi
index 75fb9c8..8bbe51e 100755
--- a/tko/machine_test_attribute_graph.cgi
+++ b/tko/machine_test_attribute_graph.cgi
@@ -16,20 +16,27 @@
db = db.db()
def main():
-# form = cgi.FieldStorage()
-# if not form.has_key("machine") and form.has_key("kernel"):
-# raise
-#
-# machine = form["machine"].value
-# kernel_version = form["kernel"].value
-# draw_graph("A test graph", "Kernel", "Elapsed time (seconds)")
- print "Content-type: text/html\n"
- sys.stdout.flush()
- machine = 'cagg4'
- where = { 'subdir' : 'kernbench', 'machine' : machine }
- tests = frontend.test.select(db, where)
- kernels.sort(key = kernel_encode)
+ form = cgi.FieldStorage()
+ machine = form["machine"].value
+ benchmark = form["benchmark"].value
+ key = form["key"].value
+ data = {}
+ where = { 'subdir' : benchmark, 'machine' : machine }
+ for test in frontend.test.select(db, where):
+ if test.iterations.has_key(key):
+ data[test.kernel.printable] = test.iterations[key]
+
+ # for kernel in sort_kernels(data.keys()):
+ # print "%s %s" % (kernel, str(data[kernel]))
+ title = "%s on %s" % (benchmark, machine)
+ graph = plotgraph.gnuplot(title, 'Kernel', key, xsort = sort_kernels)
+ graph.add_dataset('all kernels', data)
+ graph.plot(cgi_header = True)
+
+
+def sort_kernels(kernels):
+ return sorted(kernels, key = kernel_versions.version_encode)
def draw_graph(title, xlabel, ylabel):
diff --git a/tko/plotgraph.py b/tko/plotgraph.py
index 579af8b..a7de429 100755
--- a/tko/plotgraph.py
+++ b/tko/plotgraph.py
@@ -7,33 +7,53 @@
"""
import subprocess, sys, os
+from math import sqrt
Popen = subprocess.Popen
+def avg_dev(values):
+ if len(values) == 0:
+ return (0,0)
+ average = sum(values) / len(values)
+ sum_sq_dev = sum( [(x - average) ** 2 for x in values] )
+ std_dev = sqrt(sum_sq_dev / float(len(values)));
+ return (average, std_dev);
+
+
class gnuplot:
- def __init__(self, title, xlabel, ylabel):
+ def __init__(self, title, xlabel, ylabel, xsort = sorted):
self.title = title
self.xlabel = xlabel
self.ylabel = ylabel
self.data_titles = []
self.datasets = []
+ self.xsort = xsort
+ self.xvalues = set([])
- def set_xlabels(self, labels):
+ def xtics(self):
count = 1
- self.xtics = []
- for label in labels:
- self.xtics.append('"%s" %d' % (label, count))
+ tics = []
+ for label in self.xsort(self.xlabels):
+ tics.append('"%s" %d' % (label, count))
count += 1
+ return tics
- def add_dataset(self, title, values):
+ def add_dataset(self, title, labeled_values):
"""
Add a data line
- For yerrorbars, values should be "<value> <error>" as a string
+ title: title of the dataset
+ labeled_values: dictionary of lists
+ { label : [value1, value2, ... ] , ... }
"""
self.data_titles.append(title)
- self.datasets.append(values)
+ data_points = {}
+ for label in labeled_values:
+ point = "%s %s" % avg_dev(labeled_values[label])
+ data_points[label] = point
+ self.xvalues.add(label)
+ self.datasets.append(data_points)
def plot(self, cgi_header = False, output = None, test = None):
@@ -55,16 +75,19 @@
g.write('set style data yerrorlines\n')
g.write('set grid\n')
- g.write('set xtics rotate (%s)\n' % ','.join(self.xtics))
+ self.xlabels = self.xsort(list(self.xvalues))
+ g.write('set xtics rotate (%s)\n' % ','.join(self.xtics()))
plot_lines = ['"-" title "%s"' % t for t in self.data_titles]
g.write('plot ' + ', '.join(plot_lines) + '\n')
for dataset in self.datasets:
count = 1
- for data in dataset:
+ for label in self.xlabels:
+ data = dataset[label]
g.write("%d %s\n" % (count, str(data)))
count += 1
+ sys.stdout.flush()
g.write('e\n')
g.close()