27 params = {
'sha': os.environ[
'GIT_COMMIT'],
28 'host': os.environ[
'BENCH_HOST'],
31 benchmark_detail_url =
'{}/benchmarks/{{}}/'.format(os.environ[
'CONBENCH_URL'])
34 ZSCORE_CHECK = 2.5758293035489
36 ZSCORE_WARNING = 3.2905267314919255
41 conn = psycopg2.connect(os.environ[
'CONBENCH_DSN'])
45 cur.execute(
"""select co.author_avatar, co.author_name, co.branch, co.message, co.repository -- 1 row
47 join "commit" co on co.id=r.commit_id
48 join hardware h on h.id=r.hardware_id
49 where h.name=%(host)s and co.sha=%(sha)s
50 order by r."timestamp" desc
56 return s.replace(
'&',
'&').replace(
'<',
'<').replace(
'>',
'>')
60 return {
'author_avatar': row[0],
64 'commit_url':
'{}/commit/{}'.format(row[4], params[
'sha']),
65 'short_sha': params[
'sha'][0:8],
66 'host': params[
'host'] }
73 cur.execute(
"""with main_run as ( -- 1 row
74 select r.id, r."timestamp"
76 join "commit" co on co.id=r.commit_id
77 join hardware h on h.id=r.hardware_id
78 where h.name=%(host)s and co.sha=%(sha)s
79 order by r."timestamp" desc
81 ), main_stats as ( -- |b| rows. |b| = number of benchmarks (TPC-DS has 99)
82 select br.id as benchmark_result_id, ca.name, ca.tags->>'benchmark_name' as benchmark_name,
83 nullif(br.mean, 1234567.89) as mean
85 join benchmark_result br on br.run_id=mr.id
86 join "case" ca on ca.id=br.case_id
87 ), prior_runs as ( -- n most recent master runs. n is in the limit clause
90 join run r on r."timestamp" < mr."timestamp"
91 join "commit" co on co.id=r.commit_id
92 join hardware h on h.id=r.hardware_id
93 where h.name=%(host)s and co.branch='heavyai:master'
94 order by r."timestamp" desc
96 ), prior_benchmarks as ( -- n*|b| rows
97 select ca.name, ca.tags->>'benchmark_name' as benchmark_name, nullif(br.mean, 1234567.89) as mean
99 join benchmark_result br on br.run_id=pr.id
100 join "case" ca on ca.id=br.case_id
101 ), prior_stats as ( -- |b| rows
102 select pb.name, pb.benchmark_name, avg(pb.mean) as avg, stddev_samp(pb.mean) as stddev
103 from prior_benchmarks pb
104 group by pb.name, pb.benchmark_name
106 select ms.benchmark_result_id as benchmark_id, ms.name, ms.benchmark_name, ms.mean as duration_ms, -- |b| rows
107 ps.avg, ps.stddev, (ms.mean - ps.avg) / ps.stddev as z_score
109 join prior_stats ps on ps.name=ms.name and ps.benchmark_name=ms.benchmark_name
110 order by ms.name, ms.benchmark_name
113 header = [desc[0]
for desc
in cur.description]
114 rows = cur.fetchall()
116 stats = {
'worst_z_score': 0.0,
'nfixes': 0,
'nchecks': 0,
'nwarnings': 0,
'nerrors': 0 }
128 def cell(self, tag, idx, value):
129 if type(value)
is str:
130 return '<{0}>{1}</{0}>'.format(tag, value)
135 return '<{0}>{1}</{0}>'.format(tag, value)
137 stats[
'nerrors'] += 1
138 return '<{0} class="error">{1}</{0}>'.format(tag, value)
139 if stats[
'worst_z_score'] < value:
140 stats[
'worst_z_score'] = value
141 if value <= -ZSCORE_ERROR:
143 return '<{0} class="fixed">{1:0.3f}</{0}>'.format(tag, value)
144 elif value < ZSCORE_CHECK:
145 return '<{0}>{1:0.3f}</{0}>'.format(tag, value)
146 elif value < ZSCORE_WARNING:
147 stats[
'nchecks'] += 1
148 return '<{0} class="check">{1:0.3f}</{0}>'.format(tag, value)
149 elif value < ZSCORE_ERROR:
150 stats[
'nwarnings'] += 1
151 return '<{0} class="warning">{1:0.3f}</{0}>'.format(tag, value)
153 stats[
'nerrors'] += 1
154 return '<{0} class="error">{1:0.3f}</{0}>'.format(tag, value)
157 return '<{0}>{1}</{0}>'.format(tag, value)
161 return '<{0} class="fixed">{1:0.3f}</{0}>'.format(tag, value)
163 return '<{0}>{1:0.3f}</{0}>'.format(tag, value)
168 fixup.remove(
'benchmark_id')
169 fixup.remove(
'benchmark_name')
174 row = list(row_tuple)
175 benchmark_id = header.index(
'benchmark_id')
176 name = header.index(
'name')
177 benchmark_name = header.index(
'benchmark_name')
179 if row[name] ==
'StringDictionaryBenchmark':
180 p = re.compile(
'\w+/(\w+)')
181 md = p.search(row[benchmark_name])
182 row[name] =
'StringDictionary {}'.format(md.group(1))
184 row[name] =
'{} {}'.format(row[name], row[benchmark_name])
186 row[name] =
'<a href="{}">{}</a>'.format(benchmark_detail_url.format(row[benchmark_id]), row[name])
187 assert(benchmark_id < benchmark_name)
188 del row[benchmark_name]
189 del row[benchmark_id]
194 zscore_idx = len(self.
row) - 1
195 return '<tr>{}</tr>'.format(
''.
join([self.
cell(tag,idx,value)
for idx, value
in enumerate(self.
row)]))
199 '<tr><td>Fixed Tests</td><td class="fixed">{nfixes}</td></tr>',
200 '<tr><td>Check Tests</td><td class="check">{nchecks}</td></tr>',
201 '<tr><td>Warnings</td><td class="warning">{nwarnings}</td></tr>',
202 '<tr><td>Errors</td><td class="error">{nerrors}</td></tr>',
203 '<tr><td>Worst z_score</td><td>{worst_z_score:0.3f}</td></tr>'
207 html_params[
'header_row'] =
Row(header,
None).tr(
'th')
208 html_params[
'body_rows'] =
"\n".
join([
Row(header, row).tr(
'td')
for row
in rows])
212 print(
"""<!DOCTYPE html>
215 <title>Benchmarks for {branch} / {short_sha} on {host}</title>
216 <link rel="stylesheet" href="report.css">
219 <h1>Benchmarks for {branch} / <a href="{commit_url}">{short_sha}</a> on {host}</h1>
220 <p><a href="{commit_url}">{commit_message}</a></p>
221 <!-- img disabled due to strict Content Security Policy for HTML Publisher Jenkins plugin -->
222 <p><!--img alt="avatar" src="{author_avatar}" height=25-->{author_name}</p>
232 """.format(**html_params))
237 elif stats[
'nwarnings']: