1ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh#  tko/nightly.py  code shared by various tko/*.cgi graphing scripts
24bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
34bfe361ad3ac94fcd9f95637b540e6627ac2f155mblighimport cgi, cgitb
45b380beed60f3d00df3449c6d92f599bde304d33mblighimport os, sys
55b380beed60f3d00df3449c6d92f599bde304d33mblighimport common
64bfe361ad3ac94fcd9f95637b540e6627ac2f155mblighfrom autotest_lib.tko import db, plotgraph, perf
75b380beed60f3d00df3449c6d92f599bde304d33mblighfrom autotest_lib.client.common_lib import kernel_versions
84bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
94bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
10ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef add_kernel_jobs(label_pattern):
11eab66ce582bfe05076ff096c3a044d8f0497bbcashoward    cmd = "select job_idx from tko_jobs where label like '%s'" % label_pattern
12ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    nrows = perf.db_cur.execute(cmd)
13ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return [row[0] for row in perf.db_cur.fetchall()]
14ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
15ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
16ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef is_filtered_platform(platform, platforms_filter):
17ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    if not platforms_filter:
18ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        return True
19ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for p in platforms_filter:
20ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if platform.startswith(p):
21ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            return True
22ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return False
23ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
24ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
25ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef get_test_attributes(testrunx):
26eab66ce582bfe05076ff096c3a044d8f0497bbcashoward    cmd = ( "select attribute, value from tko_test_attributes"
27ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            " where test_idx = %d" % testrunx )
28ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    nrows = perf.db_cur.execute(cmd)
29ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return dict(perf.db_cur.fetchall())
30ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
31ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
32ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef get_antag(testrunx):
33ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    attrs = get_test_attributes(testrunx)
34ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return attrs.get('antag', None)
35ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
36ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
37ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef matching_test_attributes(attrs, required_test_attributes):
38ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    if not required_test_attributes:
39ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        return True
40ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    matches = [attrs[key] == required_test_attributes[key]
41ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh               for key in attrs if key in required_test_attributes]
42ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return min(matches+[True])  # True if all jointly-existing keys matched
43ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
44ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
45ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef collect_testruns(jobs, test, test_attributes,
46ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                         platforms_filter, by_hosts, no_antag):
47ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # get test_runs run #s for 1 test on 1 kernel and some platforms
48ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # TODO: Is jobs list short enough to use directly in 1 sql cmd?
49ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # TODO: add filtering on test series?
50ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    runs = {}   # platform --> list of test runs
51ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for jobx in jobs:
52eab66ce582bfe05076ff096c3a044d8f0497bbcashoward        cmd = ( "select test_idx, machine_idx from tko_tests"
53ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                " where job_idx = %s and test = %s" )
54ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        args = [jobx, test]
55ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        nrows = perf.db_cur.execute(cmd, args)
56ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for testrunx, machx in perf.db_cur.fetchall():
57ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            platform, host = perf.machine_idx_to_platform_host(machx)
58ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if by_hosts:
59ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                platform += '.'+host
60ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if ( is_filtered_platform(platform, platforms_filter)  and
61ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                 matching_test_attributes(get_test_attributes(testrunx),
62ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                          test_attributes) and
63ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                 (not no_antag or get_antag(testrunx) == '') ):
64ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                runs.setdefault(platform, []).append(testrunx)
65ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return runs
66ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
67ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
68ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef all_tested_platforms(test_runs):
69ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # extract list of all tested platforms from test_runs table
70ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    platforms = set()
71ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for kernel in test_runs:
72ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        platforms.update(set(test_runs[kernel].keys()))
73ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return sorted(platforms)
74ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
75ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
76ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef divide_twoway_testruns(test_runs, platform):
77ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # partition all twoway runs based on name of antagonist progs
78ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    twoway_runs = {}
79ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    antagonists = set()
80ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for kernel in test_runs:
81ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        runs = {}
82ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for testrunx in test_runs[kernel].get(platform, []):
83ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            antag = get_antag(testrunx)
84ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if antag is not None:
85ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                runs.setdefault(antag, []).append(testrunx)
86ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                antagonists.add(antag)
87ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        twoway_runs[kernel] = runs
88ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return twoway_runs, sorted(antagonists)
89ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
90ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
91ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef collect_raw_scores(runs, metric):
92ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # get unscaled scores of test runs for 1 test on certain jobs
93ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #   arrange them by platform type
94ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    platform_scores = {}  # platform --> list of perf scores
95ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for platform in runs:
96ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        vals = perf.get_metric_at_point(runs[platform], metric)
97ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if vals:
98ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            platform_scores[platform] = vals
99ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return platform_scores
100ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
101ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
102ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef collect_scaled_scores(metric, test_runs, regressed_platforms, relative):
103ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # get scores of test runs for 1 test on some kernels and platforms
104ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # optionally make relative to oldest (?) kernel on that platform
105ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # arrange by plotline (ie platform) for gnuplot
106ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    plot_data = {}  # platform --> (kernel --> list of perf scores)
107ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    baseline = {}
108ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for kernel in sorted(test_runs.keys()):
109ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for platform in test_runs[kernel]:
110ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if not (regressed_platforms is None or
111ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    platform in regressed_platforms):
112ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                continue  # delete results for uninteresting platforms
113ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            vals = perf.get_metric_at_point(test_runs[kernel][platform],
114ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                            metric)
115ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if vals:
116ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                if relative:
117ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    if platform not in baseline:
118ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                        baseline[platform], std = plotgraph.avg_dev(vals)
119ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    vals = [v/baseline[platform] for v in vals]
120ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                pdp = plot_data.setdefault(platform, {})
121ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                pdp.setdefault(kernel, []).extend(vals)
122ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return plot_data
123ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
124ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
125ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef collect_twoway_scores(metric, antagonists, twoway_runs, relative):
126ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    alone = ''
127ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    plot_data = {}
128ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for kernel in twoway_runs:
129ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for test2 in antagonists:
130ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            runs = twoway_runs[kernel].get(test2, [])
131ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            vals = perf.get_metric_at_point(runs, metric)
132ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            plot_data.setdefault(test2, {})
133ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if vals:
134ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                plot_data[test2][kernel] = vals
135ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if relative:
136ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            vals = plot_data[alone].get(kernel, [])
137ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if vals:
138ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                baseline = perf.average(vals)
139ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                for test2 in antagonists:
140ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    vals = plot_data[test2].get(kernel, [])
141ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    vals = [val/baseline for val in vals]
142ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    if vals:
143ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                        plot_data[test2][kernel] = vals
144ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            else:
145ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                for test2 in antagonists:
146ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    if kernel in plot_data[test2]:
147ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                        del plot_data[test2][kernel]
148ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return plot_data
149ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
150ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
151ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef find_regressions(kernels, test_runs, metric):
152ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # A test is regressed on some platform if its latest results are
153ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #  definitely lower than on the reference kernel.
154ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # Runs for the latest kernel may be underway and incomplete.
155ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # In that case, selectively use next-latest kernel.
156ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # TODO: the next-latest method hurts if latest run is not sorted last,
157ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #       or if there are several dev threads
158ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    ref    = kernels[0]
159ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    latest = kernels[-1]
160ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    prev   = kernels[-2:][0]
161ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    scores = {}  #  kernel --> (platform --> list of perf scores)
162ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for k in [ref, prev, latest]:
163ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if k in test_runs:
164ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            scores[k] = collect_raw_scores(test_runs[k], metric)
165ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    regressed_platforms = []
166ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for platform in scores[ref]:
167ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if latest in scores and platform in scores[latest]:
168ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            k = latest
169ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        elif prev in scores and platform in scores[prev]:
170ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            k = prev
171ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:  # perhaps due to decay of test machines
172ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            k = ref  # no regression info avail
173ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        ref_avg, ref_std = plotgraph.avg_dev(scores[ref][platform])
174ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        avg,     std     = plotgraph.avg_dev(scores[ k ][platform])
175ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if avg+std < ref_avg-ref_std:
176ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            regressed_platforms.append(platform)
177ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return sorted(regressed_platforms)
178ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
179ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
180ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef get_testrun_context(testrun):
181eab66ce582bfe05076ff096c3a044d8f0497bbcashoward    cmd = ( 'select tko_jobs.label, tko_jobs.tag, tko_tests.subdir,'
182eab66ce582bfe05076ff096c3a044d8f0497bbcashoward            ' tko_tests.started_time'
183eab66ce582bfe05076ff096c3a044d8f0497bbcashoward            ' from tko_jobs, tko_tests'
184eab66ce582bfe05076ff096c3a044d8f0497bbcashoward            ' where tko_jobs.job_idx = tko_tests.job_idx'
185eab66ce582bfe05076ff096c3a044d8f0497bbcashoward            ' and tko_tests.test_idx = %d' % testrun )
186ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    nrows = perf.db_cur.execute(cmd)
187ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    assert nrows == 1
188ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    row = perf.db_cur.fetchone()
189ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    row = [row[0], row[1], row[2], row[3].strftime('%m/%d/%y %H:%M')]
190ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return row
191ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
192ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
193ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef html_top():
194ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "Content-Type: text/html\n\n<html><body>"
195ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
196ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
197ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef abs_rel_link(myurl, passthru):
198ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # link redraws current page with opposite absolute/relative choice
199ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    mod_passthru = passthru[:]
200ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    if 'absolute' in passthru:
201ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        mod_passthru.remove('absolute')
202ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        opposite = 'relative'
203ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    else:
204ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        mod_passthru.append('absolute')
205ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        opposite = 'absolute'
206ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    url = '%s?%s' % (myurl, '&'.join(mod_passthru))
207ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    return "<a href='%s'> %s </a>" % (url, opposite)
208ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
209ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
210ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef table_1_metric_all_kernels(plot_data, columns, column_argname,
211ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                               kernels, kernel_dates,
212ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                               myurl, filtered_passthru):
213ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # generate html table of graph's numbers
214ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #   for 1 benchmark metric over all kernels (rows),
215ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #   over various platforms or various antagonists etc (cols).
216ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    ref_thresholds = {}
217ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<table border=1 cellpadding=3 cellspacing=0>"
218ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<tr> <td><b> Kernel </b></td>",
219ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for label in columns:
220ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if not label and column_argname == 'antag':
221ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            label = 'no antag'
222ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<td><b>", label.replace('_', '<br>_'), "</b></td>"
223ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "</tr>"
224ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for kernel in kernels:
225ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<tr> <td><b>", kernel, "</b>",
226ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if kernel in kernel_dates:
227ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "<br><small>", kernel_dates[kernel], "</small>"
228ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "</td>"
229ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for col in columns:
230ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "<td",
231ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            vals = plot_data[col].get(kernel, [])
232ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if not vals:
233ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "> ?",
234ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            else:
235ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                (avg, std_dev) = plotgraph.avg_dev(vals)
236ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                if col not in ref_thresholds:
237ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    ref_thresholds[col] = avg - std_dev
238ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                if avg+std_dev < ref_thresholds[col]:
239ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    print "bgcolor=pink",
240ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "> ",
241ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                args = filtered_passthru[:]
242ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                perf.append_cgi_args(args,
243ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                   {column_argname:col, 'kernel':kernel})
244ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "<a href='%s?%s&runs&attrs'>" % (myurl,
245ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                                       '&'.join(args))
246ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "<b>%.4g</b>" % avg, "</a><br>",
247ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "&nbsp; <small> %dr   </small>" % len(vals),
248ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "&nbsp; <small> %.3g </small>" % std_dev,
249ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "</td>"
250ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "</tr>\n"
251ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "</table>"
252ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<p> <b>Bold value:</b> Average of this metric, then <br>"
253ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "number of good test runs, then standard deviation of those runs"
254ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<br> Pink if regressed from reference kernel"
255ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
256ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
257ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef table_all_metrics_1_platform(test_runs, platform, relative):
258ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # TODO: show std dev in cells
259ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #       can't mark regressions, since some metrics improve downwards
260ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    kernels = perf.sort_kernels(test_runs.keys())
261ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    scores = {}
262ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    attrs = set()
263ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for kernel in kernels:
264ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        testruns = test_runs[kernel].get(platform, [])
265ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if testruns:
266ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            d = perf.collect_all_metrics_scores(testruns)
267ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            scores[kernel] = d
268ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            attrs.update(set(d.keys()))
269ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
270ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "No runs completed on", kernel, "<br>"
271ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    attrs = sorted(list(attrs))[:100]
272ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
273ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<table border=1 cellpadding=4 cellspacing=0>"
274ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<tr><td> Metric </td>"
275ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for kernel in kernels:
276ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        kernel = kernel.replace("_", "_<br>")
277ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<td>", kernel, "</td>"
278ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "</tr>"
279ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for attr in attrs:
280ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<tr>"
281ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<td>", attr, "</td>"
282ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        baseline = None
283ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for kernel in kernels:
284ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "<td>",
285ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if kernel in scores and attr in scores[kernel]:
286ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                (avg, dev) = plotgraph.avg_dev(scores[kernel][attr])
287ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                if baseline and relative:
288ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    percent = (avg/baseline - 1)*100
289ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    print "%+.1f%%" % percent,
290ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                else:
291ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    baseline = avg
292ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    print "%.4g" % avg,
293ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            else:
294ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "?"
295ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "</td>"
296ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "</tr>"
297ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "</table>"
298ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
299ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
300ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef table_variants_all_tests(plot_data, columns, colkeys, benchmarks,
301ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                             myurl, filtered_passthru):
302ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # generate html table of graph's numbers
303ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #   for primary metric over all benchmarks (rows),
304ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #   on one platform and one kernel,
305ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #   over various combos of test run attribute constraints (cols).
306ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    ref_thresholds = {}
307ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<table border=1 cellpadding=3 cellspacing=0>"
308ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<tr> <td><b> Benchmark </b></td>",
309ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for col in columns:
310ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<td><b>", colkeys[col].replace(',', ',<br>'), "</b></td>"
311ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "</tr>"
312ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for benchmark in benchmarks:
313ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<tr> <td><b>", benchmark, "</b></td>"
314ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for col in columns:
315ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "<td>",
316ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            vals = plot_data[col].get(benchmark, [])
317ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if not vals:
318ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "?",
319ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            else:
320ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                (avg, std_dev) = plotgraph.avg_dev(vals)
321ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                args = filtered_passthru[:]
322ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                perf.append_cgi_args(args, {'test':benchmark})
323ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                for keyval in colkeys[col].split(','):
324ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    key, val = keyval.split('=', 1)
325ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    perf.append_cgi_args(args, {key:val})
326ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "<a href='%s?%s&runs&attrs'>" % (myurl,
327ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                                       '&'.join(args))
328ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "<b>%.4g</b>" % avg, "</a><br>",
329ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "&nbsp; <small> %dr   </small>" % len(vals),
330ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "&nbsp; <small> %.3g </small>" % std_dev,
331ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "</td>"
332ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "</tr>\n"
333ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "</table>"
334ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<p> <b>Bold value:</b> Average of this metric, then <br>"
335ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "number of good test runs, then standard deviation of those runs"
336ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
337ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
338ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef table_testrun_details(runs, metric, tko_server, show_attrs):
339ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<table border=1 cellpadding=4 cellspacing=0>"
340ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<tr><td> %s metric </td>" % metric
341ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<td> Job label </td> <td> Job tag </td> <td> Run results </td>"
342ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<td> Started_time </td>"
343ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    if show_attrs:
344ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<td> Test attributes </td>"
345ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "</tr>\n"
346ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
347ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for testrunx in runs:
348ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<tr> <td>",
349ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        vals = perf.get_metric_at_point([testrunx], metric)
350ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for v in vals:
351ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "%.4g&nbsp;" % v,
352ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "</td>"
353ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        row = get_testrun_context(testrunx)
354ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        row[2] = ( "<a href='//%s/results/%s/%s/results/keyval'> %s </a>"
355ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                   % (tko_server, row[1], row[2], row[2]) )
356ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for v in row:
357ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "<td> %s </td>" % v
358ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if show_attrs:
359ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            attrs = get_test_attributes(testrunx)
360ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "<td>",
361ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            for attr in sorted(attrs.keys()):
362ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                if attr == "sysinfo-cmdline": continue
363ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                if attr[:4] == "svs-": continue
364ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                val = attrs[attr]
365ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                if len(val) > 40:
366ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    val = val[:40-3] + "..."
367ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                print "%s=%s &nbsp; &nbsp; " % (attr, val)
368ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "</td>"
369ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "</tr>\n"
370ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "</table>"
371ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
372ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
373ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef overview_thumb(test, metric, myurl, passthru):
374ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    pass_ = passthru + ['test=%s' % test]
375ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    if metric:
376ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        pass_ += ['metric=%s' % metric]
377ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    pass_ = '&'.join(pass_)
378ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "<a    href='%s?%s&table'>"             % (myurl, pass_)
379ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    print "  <img src='%s?%s&size=450,500'> </a>" % (myurl, pass_)
380ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # embedded graphs fit 3 across on 1400x1050 laptop
381ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
382ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
383ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef graph_1_test(title, metric, plot_data, line_argname, lines,
384ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                 kernel_legend, relative, size, dark=False):
385ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # generate graph image for one benchmark, showing avg and
386ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #  std dev of one metric, over various kernels (X columns),
387ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    #  over various platforms or antagonists etc (graphed lines)
388ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    xlegend = kernel_legend
389ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    ylegend = metric.capitalize()
390ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    if relative:
391ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        ylegend += ', Relative'
392ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        ymin = 0.8
393ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    else:
394ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        ymin = None
395ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    if len(lines) > 1:
396ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        keytitle = line_argname.capitalize() + ':'
397ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    else:
398ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        keytitle = ''
399ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    graph = plotgraph.gnuplot(title, xlegend, ylegend, size=size,
400ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                              xsort=perf.sort_kernels, keytitle=keytitle)
401ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for line in lines:
402ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        label = line
403ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if not label and line_argname == 'antag':
404ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            label = 'no antag'
405ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        graph.add_dataset(label, plot_data[line])
406ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    graph.plot(cgi_header=True, ymin=ymin, dark=dark)
407ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
408ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
409ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighdef graph_variants_all_tests(title, plot_data, linekeys, size, dark):
410ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # generate graph image showing all benchmarks
411ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #   on one platform and one kernel,
412ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #   over various combos of test run attribute constraints (lines).
413ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    xlegend = "Benchmark"
414ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    ylegend = "Relative Perf"
415ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    graph = plotgraph.gnuplot(title, xlegend, ylegend, size=size)
416ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    for i in linekeys:
417ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        graph.add_dataset(linekeys[i], plot_data[i])
418ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    graph.plot(cgi_header=True, dark=dark, ymin=0.8)
419ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
420ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
421ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmblighclass generate_views(object):
422ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
423ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
424ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def __init__(self, kernel_legend, benchmarks, test_group,
425ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                     site_benchmark_metrics, tko_server,
426ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                     jobs_selector, no_antag):
427ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.kernel_legend = kernel_legend
428ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.benchmarks = benchmarks
429ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.test_group = test_group
430ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.tko_server = tko_server
431ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.jobs_selector = jobs_selector
432ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.no_antag = no_antag
433ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
434ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        cgitb.enable()
435ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        test, antagonists = self.parse_most_cgi_args()
436ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
437ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        perf.init(tko_server=tko_server)
438ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for b in site_benchmark_metrics:
439ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            perf.add_benchmark_main_metric(b, site_benchmark_metrics[b])
440ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
441ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.test_runs = {}     # kernel --> (platform --> list of test runs)
442ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.job_table = {}     # kernel id --> list of job idxs
443ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.kernel_dates = {}  # kernel id --> date of nightly test
444ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
445ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        vary = self.cgiform.getlist('vary')
446ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if vary:
447ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            platform = self.platforms_filter[0]
448ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.analyze_variants_all_tests_1_platform(platform, vary)
449ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        elif test:
450ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.analyze_1_test(test, antagonists)
451ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
452ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.overview_page_all_tests(self.benchmarks, antagonists)
453ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
454ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
455ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def collect_all_testruns(self, trimmed_kernels, test):
456ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    # get test_runs run #s for 1 test on some kernels and platforms
4574bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        for kernel in trimmed_kernels:
458ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            runs = collect_testruns(self.job_table[kernel], test,
459ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                    self.test_attributes, self.platforms_filter,
460ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                    'by_hosts' in self.toggles, self.no_antag)
4614bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh            if runs:
462ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                self.test_runs[kernel] = runs
4634bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
4644bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
465ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def table_for_graph_1_test(self, title, metric, plot_data,
466ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                 column_argname, columns, filtered_passthru):
467ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # generate detailed html page with 1 graph and corresp numbers
468ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #   for 1 benchmark metric over all kernels (rows),
469ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #   over various platforms or various antagonists etc (cols).
470ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        html_top()
471ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print '<h3> %s </h3>' % title
472ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print ('%s, machine group %s on //%s server <br>' %
473ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh               (self.kernel_legend, self.test_group, self.tko_server))
474ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if self.test_tag:
475ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print '%s test script series <br>' % self.test_tag[1:]
476ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
477ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<img src='%s?%s'>" % (self.myurl, '&'.join(self.passthru))
478ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
479ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        link = abs_rel_link(self.myurl, self.passthru+['table'])
480ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<p><p> <h4> Redraw this with %s performance? </h4>" % link
4814bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
482ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        heading = "%s, %s metric" % (title, metric)
483ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if self.relative:
484ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            heading += ", relative"
4854bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        print "<p><p> <h3> %s: </h3>" % heading
486ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        table_1_metric_all_kernels(plot_data, columns, column_argname,
487ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                   self.kernels, self.kernel_dates,
488ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                   self.myurl, filtered_passthru)
489ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "</body></html>"
4904bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
491ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
492ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def graph_1_test_all_platforms(self, test, metric, platforms, plot_data):
493ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # generate graph image for one benchmark
494ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        title = test.capitalize()
495ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if 'regress' in self.toggles:
496ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            title += ' Regressions'
497ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if 'table' in self.cgiform:
498ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.table_for_graph_1_test(title, metric, plot_data,
499ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                        'platforms', platforms,
500ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                        filtered_passthru=self.passthru)
501ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
502ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            graph_1_test(title, metric, plot_data, 'platforms', platforms,
503ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                         self.kernel_legend, self.relative,
504ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                         self.size, 'dark' in self.toggles)
505ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
506ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
507ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def testrun_details(self, title, runs, metric):
508ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        html_top()
509ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print '<h3> %s </h3>' % title
510ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print ('%s, machine group %s on //%s server' %
511ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh               (self.kernel_legend, self.test_group, self.tko_server))
512ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if self.test_tag:
513ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print '<br> %s test script series' % self.test_tag[1:]
514ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print '<p>'
515ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        table_testrun_details(runs, metric,
516ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                              self.tko_server, 'attrs' in self.cgiform)
5174bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        print "</body></html>"
5184bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
5194bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
520ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def testrun_details_for_1_test_kernel_platform(self, test,
521ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                                   metric, platform):
522ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        default_kernel = min(self.test_runs.keys())
523ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        kernel = self.cgiform.getvalue('kernel', default_kernel)
524ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        title = '%s on %s using %s' % (test.capitalize(), platform, kernel)
525ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        runs = self.test_runs[kernel].get(platform, [])
526ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.testrun_details(title, runs, metric)
5274bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
528ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
529ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def analyze_1_metric_all_platforms(self, test, metric):
530ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if 'regress' in self.toggles:
531ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            regressed_platforms = find_regressions(self.kernels, self.test_runs,
532ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                                   metric)
533ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
534ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            regressed_platforms = None
535ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        plot_data = collect_scaled_scores(metric, self.test_runs,
536ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                          regressed_platforms, self.relative)
537ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        platforms = sorted(plot_data.keys())
538ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if not plot_data:
539ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            html_top()
540ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print 'No runs'
541ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        elif 'runs' in self.cgiform:
542ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.testrun_details_for_1_test_kernel_platform(test, metric,
543ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                                            platforms[0])
544ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
545ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.graph_1_test_all_platforms(test, metric, platforms, plot_data)
546ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
547ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
548ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def analyze_all_metrics_1_platform(self, test, platform):
549ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # TODO: show #runs in header
550ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        html_top()
551ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        heading = "%s %s:&nbsp %s" % (self.test_group, self.kernel_legend,
552ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                      test.capitalize())
553ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<h2> %s </h2>" % heading
554ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "platform=%s <br>" % platform
555ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for attr in self.test_attributes:
556ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print "%s=%s &nbsp; " % (attr, self.test_attributes[attr])
557ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<p>"
558ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        table_all_metrics_1_platform(self.test_runs, platform, self.relative)
5594bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        print "</body></html>"
5604bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
5614bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
562ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def table_for_variants_all_tests(self, title, plot_data, colkeys, columns,
563ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                       filtered_passthru, test_tag):
564ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # generate detailed html page with 1 graph and corresp numbers
565ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #   for primary metric over all benchmarks (rows),
566ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #   on one platform and one kernel,
567ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #   over various combos of test run attribute constraints (cols).
568ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        html_top()
569ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print '<h3> %s </h3>' % title
570ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print ('%s, machine group %s on //%s server <br>' %
571ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh               (self.kernel_legend, self.test_group, self.tko_server))
572ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if test_tag:
573ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print '%s test script series <br>' % test_tag[1:]
574ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
575ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        varies = ['vary='+colkeys[col] for col in columns]
576ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<img src='%s?%s'>" % (self.myurl, '&'.join(self.passthru+varies))
577ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
578ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<p><p> <h3> %s: </h3>" % title
579ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        table_variants_all_tests(plot_data, columns, colkeys, self.benchmarks,
580ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                 self.myurl, filtered_passthru)
581ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "</body></html>"
582ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
583ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
584ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def analyze_variants_all_tests_1_platform(self, platform, vary):
585ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # generate one graph image for results of all benchmarks
586ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # on one platform and one kernel, comparing effects of
587ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # two or more combos of kernel options (test run attributes)
588ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #   (numa_fake,stale_page,kswapd_merge,sched_idle, etc)
589ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        kernel = self.cgiform.getvalue('kernel', 'some_kernel')
590ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.passthru.append('kernel=%s' % kernel)
591ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
592ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # two or more vary_groups, one for each plotted line,
593ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # each group begins with vary= and ends with next  &
594ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # each group has comma-separated list of test attribute key=val pairs
595ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #    eg   vary=keyval1,keyval2&vary=keyval3,keyval4
596ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        vary_groups = [dict(pair.split('=',1) for pair
597ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                            in vary_group.split(','))
598ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                       for vary_group in vary]
599ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
600ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        test = self.benchmarks[0]  # pick any test in all jobs
601ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        kernels, test_tag = self.jobs_selector(test, self.job_table,
602ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                               self.kernel_dates)
603ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
604ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        linekeys = {}
605ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        plot_data = {}
606ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        baselines = {}
607ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for i, vary_group in enumerate(vary_groups):
608ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            group_attributes = self.test_attributes.copy()
609ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            group_attributes.update(vary_group)
610ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            linekey = ','.join('%s=%s' % (attr, vary_group[attr])
611ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                               for attr in vary_group)
612ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            linekeys[i] = linekey
613ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            data = {}
614ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            for benchmark in self.benchmarks:
615ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                metric = perf.benchmark_main_metric(benchmark)
616ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                runs = collect_testruns(self.job_table[kernel],
617ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                        benchmark+test_tag,
618ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                        group_attributes,
619ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                        self.platforms_filter,
620ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                        'by_hosts' in self.toggles,
621ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                        self.no_antag)
622ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                vals = []
623ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                for testrunx in runs[platform]:
624ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    vals += perf.get_metric_at_point([testrunx], metric)
625ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                if vals:
626ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    if benchmark not in baselines:
627ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                        baselines[benchmark], stddev = plotgraph.avg_dev(vals)
628ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    vals = [val/baselines[benchmark] for val in vals]
629ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    data[benchmark] = vals
630ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            plot_data[i] = data
631ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
632ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        title  = "%s on %s" % (kernel, platform)
633ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        for attr in self.test_attributes:
634ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            title += ', %s=%s' % (attr, self.test_attributes[attr])
635ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if 'table' in self.cgiform:
636ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.table_for_variants_all_tests(title, plot_data, linekeys,
637ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                               range(len(linekeys)),
638ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                               filtered_passthru=self.passthru,
639ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                               test_tag=test_tag)
640ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
641ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            graph_variants_all_tests(title, plot_data, linekeys,
642ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                     self.size, 'dark' in self.toggles)
643ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
644ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
645ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def graph_twoway_antagonists_1_test_1_platform(
646ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                  self, test, metric, platform, antagonists, twoway_runs):
647ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # generate graph of one benchmark's performance paired with
648ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #    various antagonists, with one plotted line per antagonist,
649ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        #    over most kernels (X axis), all on one machine type
650ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        # performance is relative to the no-antag baseline case
651ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        plot_data = collect_twoway_scores(metric, antagonists,
652ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                          twoway_runs, self.relative)
653ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        title  = "%s vs. an Antagonist on %s:" % (test.capitalize(), platform)
654ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if 'table' in self.cgiform:
655ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            filtered_passthru = [arg for arg in self.passthru
656ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                     if not arg.startswith('antag=')]
657ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.table_for_graph_1_test(title, metric, plot_data,
658ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                   'antag', antagonists,
659ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                   filtered_passthru=filtered_passthru)
660ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
661ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            graph_1_test(title, metric, plot_data, 'antag', antagonists,
662ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                         self.kernel_legend, self.relative,
663ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                         self.size, 'dark' in self.toggles)
664ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
665ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
666ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def testrun_details_for_twoway_test(self, test, metric, platform,
667ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                        antagonist, twoway_runs):
668ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        default_kernel = min(twoway_runs.keys())
669ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        kernel = self.cgiform.getvalue('kernel', default_kernel)
670ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        title = '%s vs. Antagonist %s on %s using %s' % (
671ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                test.capitalize(), antagonist.capitalize(), platform, kernel)
672ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        runs = twoway_runs[kernel].get(antagonist, [])
673ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.testrun_details(title, runs, metric)
674ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
675ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
676ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def analyze_twoway_antagonists_1_test_1_platform(
677ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                  self, test, metric, platform, antagonists):
678ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        twoway_runs, all_antagonists = divide_twoway_testruns(self.test_runs,
679ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                                              platform)
680ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if antagonists == ['*']:
681ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            antagonists = all_antagonists
682ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if not twoway_runs:
683ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            html_top()
684ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            print 'No runs'
685ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        elif 'runs' in self.cgiform:
686ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.testrun_details_for_twoway_test(
687ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    test, metric, platform, antagonists[0], twoway_runs)
688ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
689ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.graph_twoway_antagonists_1_test_1_platform(
690ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    test, metric, platform, antagonists, twoway_runs)
691ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
6924bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
693ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def get_twoway_default_platform(self):
694ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if self.platforms_filter:
695ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            return self.platforms_filter[0]
696ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        test = 'unixbench'
697ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        kernels, test_tag = self.jobs_selector(test, self.job_table,
698ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                               self.kernel_dates)
699ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.collect_all_testruns(kernels, test+test_tag)
700ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        return all_tested_platforms(self.test_runs)[0]
7014bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
702ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
703ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def overview_page_all_tests(self, benchmarks, antagonists):
7044bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        # generate overview html page with small graphs for each benchmark
7054bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        #   linking to detailed html page for that benchmark
7064bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        #   recursively link to this same cgi to generate each image
707ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        html_top()
708ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if antagonists is not None:
709ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            heading = ('Twoway Container Isolation using %s on %s' %
710ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                       (self.kernel_legend, self.get_twoway_default_platform()))
711ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
712ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            heading = '%s, %s Benchmarks' % (self.kernel_legend,
713ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                             self.test_group)
714ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if 'regress' in self.toggles:
7154bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh            heading += ", Regressions Only"
716ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<h3> %s </h3>" % heading
7174bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        for test in benchmarks:
718ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            overview_thumb(test, '', self.myurl, self.passthru)
7199b2cd046f49d801d7889707e3a7250ac545ac3ebmbligh            if test == 'unixbench':
720ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                overview_thumb('unixbench', 'Process_creation',
721ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                               self.myurl, self.passthru)
722ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
723ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        link = abs_rel_link(self.myurl, self.passthru)
724ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        print "<p><p> <h4> Redraw this with %s performance? </h4>" % link
7254bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        print "</body></html>"
7264bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
7274bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh
728ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def analyze_1_test(self, test, antagonists):
729ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.passthru.append('test=%s' % test)
730ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        metric = self.cgiform.getvalue('metric', '')
7314bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        if metric:
732ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.passthru.append('metric=%s' % metric)
7334bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        else:
7344bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh            metric = perf.benchmark_main_metric(test)
7354bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh            assert metric, "no default metric for test %s" % test
736ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.kernels, self.test_tag = self.jobs_selector(test, self.job_table,
737ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                                         self.kernel_dates)
738ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.collect_all_testruns(self.kernels, test+self.test_tag)
739ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if not self.platforms_filter and (metric == '*' or
740ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                          antagonists is not None):
741ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            # choose default platform
742ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.platforms_filter = all_tested_platforms(self.test_runs)[0:1]
743ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.passthru.append('platforms=%s' %
744ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                                 ','.join(self.platforms_filter))
745ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if antagonists is not None:
746ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            antagonists = antagonists.split(',')
747ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            if len(antagonists) == 1 and antagonists != ['*']:
748ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                self.relative = False
749ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.analyze_twoway_antagonists_1_test_1_platform(
750ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh                    test, metric, self.platforms_filter[0], antagonists)
751ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        elif metric == '*':
752ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            platform = self.platforms_filter[0]
753ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.analyze_all_metrics_1_platform(test, platform)
7544bfe361ad3ac94fcd9f95637b540e6627ac2f155mbligh        else:
755ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.analyze_1_metric_all_platforms(test, metric)
756ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
757ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh
758ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh    def parse_most_cgi_args(self):
759ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.myurl = os.path.basename(sys.argv[0])
760ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.cgiform = cgi.FieldStorage(keep_blank_values=True)
761ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.size = self.cgiform.getvalue('size', '1200,850')
762ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        all_toggles = set(('absolute', 'regress', 'dark', 'by_hosts'))
763ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.toggles = set(tog for tog in all_toggles if tog in self.cgiform)
764ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        platforms = self.cgiform.getvalue('platforms', '')
765ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if '.' in platforms:
766ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.toggles.add('by_hosts')
767ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.passthru = list(self.toggles)
768ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.relative = 'absolute' not in self.toggles
769ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if platforms:
770ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.passthru.append('platforms=%s' % platforms)
771ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.platforms_filter = platforms.split(',')
772ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
773ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.platforms_filter = []
774ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        self.test_attributes = perf.parse_test_attr_args(self.cgiform)
775ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        perf.append_cgi_args(self.passthru, self.test_attributes)
776ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        test = self.cgiform.getvalue('test', '')
777ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        if 'antag' in self.cgiform:
778ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            antagonists = ','.join(self.cgiform.getlist('antag'))
779ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            #      antag=*
780ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            #   or antag=test1,test2,test3,...
781ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            #   or antag=test1&antag=test2&...
782ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            #   testN is empty for solo case of no antagonist
783ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            self.passthru.append('antag=%s' % antagonists)
784ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        else:
785ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh            antagonists = None  # not same as ''
786ef8fd9cf99d6a161fbbcf1a7de6475e74e3ddf3dmbligh        return test, antagonists
787