11cb0ef41Sopenharmony_ci#!/usr/bin/env python 21cb0ef41Sopenharmony_ci# Copyright 2017 the V8 project authors. All rights reserved. 31cb0ef41Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be 41cb0ef41Sopenharmony_ci# found in the LICENSE file. 51cb0ef41Sopenharmony_ci''' 61cb0ef41Sopenharmony_cipython %prog 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciCompare perf trybot JSON files and output the results into a pleasing HTML page. 91cb0ef41Sopenharmony_ciExamples: 101cb0ef41Sopenharmony_ci %prog -t "ia32 results" Result,../result.json Master,/path-to/master.json -o results.html 111cb0ef41Sopenharmony_ci %prog -t "x64 results" ../result.json master.json -o results.html 121cb0ef41Sopenharmony_ci''' 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ci# for py2/py3 compatibility 151cb0ef41Sopenharmony_cifrom __future__ import print_function 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_cifrom collections import OrderedDict 181cb0ef41Sopenharmony_ciimport json 191cb0ef41Sopenharmony_ciimport math 201cb0ef41Sopenharmony_cifrom argparse import ArgumentParser 211cb0ef41Sopenharmony_ciimport os 221cb0ef41Sopenharmony_ciimport shutil 231cb0ef41Sopenharmony_ciimport sys 241cb0ef41Sopenharmony_ciimport tempfile 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ciPERCENT_CONSIDERED_SIGNIFICANT = 0.5 271cb0ef41Sopenharmony_ciPROBABILITY_CONSIDERED_SIGNIFICANT = 0.02 281cb0ef41Sopenharmony_ciPROBABILITY_CONSIDERED_MEANINGLESS = 0.05 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ciclass Statistics: 311cb0ef41Sopenharmony_ci @staticmethod 321cb0ef41Sopenharmony_ci def Mean(values): 331cb0ef41Sopenharmony_ci return float(sum(values)) / len(values) 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci @staticmethod 361cb0ef41Sopenharmony_ci def Variance(values, average): 371cb0ef41Sopenharmony_ci return map(lambda x: (x - average) ** 2, values) 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci @staticmethod 401cb0ef41Sopenharmony_ci def StandardDeviation(values, average): 411cb0ef41Sopenharmony_ci return math.sqrt(Statistics.Mean(Statistics.Variance(values, average))) 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci @staticmethod 441cb0ef41Sopenharmony_ci def ComputeZ(baseline_avg, baseline_sigma, mean, n): 451cb0ef41Sopenharmony_ci if baseline_sigma == 0: 461cb0ef41Sopenharmony_ci return 1000.0; 471cb0ef41Sopenharmony_ci return abs((mean - baseline_avg) / (baseline_sigma / math.sqrt(n))) 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci # Values from http://www.fourmilab.ch/rpkp/experiments/analysis/zCalc.html 501cb0ef41Sopenharmony_ci @staticmethod 511cb0ef41Sopenharmony_ci def ComputeProbability(z): 521cb0ef41Sopenharmony_ci if z > 2.575829: # p 0.005: two sided < 0.01 531cb0ef41Sopenharmony_ci return 0 541cb0ef41Sopenharmony_ci if z > 2.326348: # p 0.010 551cb0ef41Sopenharmony_ci return 0.01 561cb0ef41Sopenharmony_ci if z > 2.170091: # p 0.015 571cb0ef41Sopenharmony_ci return 0.02 581cb0ef41Sopenharmony_ci if z > 2.053749: # p 0.020 591cb0ef41Sopenharmony_ci return 0.03 601cb0ef41Sopenharmony_ci if z > 1.959964: # p 0.025: two sided < 0.05 611cb0ef41Sopenharmony_ci return 0.04 621cb0ef41Sopenharmony_ci if z > 1.880793: # p 0.030 631cb0ef41Sopenharmony_ci return 0.05 641cb0ef41Sopenharmony_ci if z > 1.811910: # p 0.035 651cb0ef41Sopenharmony_ci return 0.06 661cb0ef41Sopenharmony_ci if z > 1.750686: # p 0.040 671cb0ef41Sopenharmony_ci return 0.07 681cb0ef41Sopenharmony_ci if z > 1.695397: # p 0.045 691cb0ef41Sopenharmony_ci return 0.08 701cb0ef41Sopenharmony_ci if z > 1.644853: # p 0.050: two sided < 0.10 711cb0ef41Sopenharmony_ci return 0.09 721cb0ef41Sopenharmony_ci if z > 1.281551: # p 0.100: two sided < 0.20 731cb0ef41Sopenharmony_ci return 0.10 741cb0ef41Sopenharmony_ci return 0.20 # two sided p >= 0.20 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ciclass ResultsDiff: 781cb0ef41Sopenharmony_ci def __init__(self, significant, notable, percentage_string): 791cb0ef41Sopenharmony_ci self.significant_ = significant 801cb0ef41Sopenharmony_ci self.notable_ = notable 811cb0ef41Sopenharmony_ci self.percentage_string_ = percentage_string 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_ci def percentage_string(self): 841cb0ef41Sopenharmony_ci return self.percentage_string_; 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci def isSignificant(self): 871cb0ef41Sopenharmony_ci return self.significant_ 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_ci def isNotablyPositive(self): 901cb0ef41Sopenharmony_ci return self.notable_ > 0 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci def isNotablyNegative(self): 931cb0ef41Sopenharmony_ci return self.notable_ < 0 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci 961cb0ef41Sopenharmony_ciclass BenchmarkResult: 971cb0ef41Sopenharmony_ci def __init__(self, units, count, result, sigma): 981cb0ef41Sopenharmony_ci self.units_ = units 991cb0ef41Sopenharmony_ci self.count_ = float(count) 1001cb0ef41Sopenharmony_ci self.result_ = float(result) 1011cb0ef41Sopenharmony_ci self.sigma_ = float(sigma) 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci def Compare(self, other): 1041cb0ef41Sopenharmony_ci if self.units_ != other.units_: 1051cb0ef41Sopenharmony_ci print ("Incompatible units: %s and %s" % (self.units_, other.units_)) 1061cb0ef41Sopenharmony_ci sys.exit(1) 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci significant = False 1091cb0ef41Sopenharmony_ci notable = 0 1101cb0ef41Sopenharmony_ci percentage_string = "" 1111cb0ef41Sopenharmony_ci # compute notability and significance. 1121cb0ef41Sopenharmony_ci if self.units_ == "score": 1131cb0ef41Sopenharmony_ci compare_num = 100*self.result_/other.result_ - 100 1141cb0ef41Sopenharmony_ci else: 1151cb0ef41Sopenharmony_ci compare_num = 100*other.result_/self.result_ - 100 1161cb0ef41Sopenharmony_ci if abs(compare_num) > 0.1: 1171cb0ef41Sopenharmony_ci percentage_string = "%3.1f" % (compare_num) 1181cb0ef41Sopenharmony_ci z = Statistics.ComputeZ(other.result_, other.sigma_, 1191cb0ef41Sopenharmony_ci self.result_, self.count_) 1201cb0ef41Sopenharmony_ci p = Statistics.ComputeProbability(z) 1211cb0ef41Sopenharmony_ci if p < PROBABILITY_CONSIDERED_SIGNIFICANT: 1221cb0ef41Sopenharmony_ci significant = True 1231cb0ef41Sopenharmony_ci if compare_num >= PERCENT_CONSIDERED_SIGNIFICANT: 1241cb0ef41Sopenharmony_ci notable = 1 1251cb0ef41Sopenharmony_ci elif compare_num <= -PERCENT_CONSIDERED_SIGNIFICANT: 1261cb0ef41Sopenharmony_ci notable = -1 1271cb0ef41Sopenharmony_ci return ResultsDiff(significant, notable, percentage_string) 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci def result(self): 1301cb0ef41Sopenharmony_ci return self.result_ 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci def sigma(self): 1331cb0ef41Sopenharmony_ci return self.sigma_ 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ciclass Benchmark: 1371cb0ef41Sopenharmony_ci def __init__(self, name): 1381cb0ef41Sopenharmony_ci self.name_ = name 1391cb0ef41Sopenharmony_ci self.runs_ = {} 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci def name(self): 1421cb0ef41Sopenharmony_ci return self.name_ 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci def getResult(self, run_name): 1451cb0ef41Sopenharmony_ci return self.runs_.get(run_name) 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci def appendResult(self, run_name, trace): 1481cb0ef41Sopenharmony_ci values = map(float, trace['results']) 1491cb0ef41Sopenharmony_ci count = len(values) 1501cb0ef41Sopenharmony_ci mean = Statistics.Mean(values) 1511cb0ef41Sopenharmony_ci stddev = float(trace.get('stddev') or 1521cb0ef41Sopenharmony_ci Statistics.StandardDeviation(values, mean)) 1531cb0ef41Sopenharmony_ci units = trace["units"] 1541cb0ef41Sopenharmony_ci # print run_name, units, count, mean, stddev 1551cb0ef41Sopenharmony_ci self.runs_[run_name] = BenchmarkResult(units, count, mean, stddev) 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ciclass BenchmarkSuite: 1591cb0ef41Sopenharmony_ci def __init__(self, name): 1601cb0ef41Sopenharmony_ci self.name_ = name 1611cb0ef41Sopenharmony_ci self.benchmarks_ = {} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci def SortedTestKeys(self): 1641cb0ef41Sopenharmony_ci keys = self.benchmarks_.keys() 1651cb0ef41Sopenharmony_ci keys.sort() 1661cb0ef41Sopenharmony_ci t = "Total" 1671cb0ef41Sopenharmony_ci if t in keys: 1681cb0ef41Sopenharmony_ci keys.remove(t) 1691cb0ef41Sopenharmony_ci keys.append(t) 1701cb0ef41Sopenharmony_ci return keys 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci def name(self): 1731cb0ef41Sopenharmony_ci return self.name_ 1741cb0ef41Sopenharmony_ci 1751cb0ef41Sopenharmony_ci def getBenchmark(self, benchmark_name): 1761cb0ef41Sopenharmony_ci benchmark_object = self.benchmarks_.get(benchmark_name) 1771cb0ef41Sopenharmony_ci if benchmark_object == None: 1781cb0ef41Sopenharmony_ci benchmark_object = Benchmark(benchmark_name) 1791cb0ef41Sopenharmony_ci self.benchmarks_[benchmark_name] = benchmark_object 1801cb0ef41Sopenharmony_ci return benchmark_object 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ciclass ResultTableRenderer: 1841cb0ef41Sopenharmony_ci def __init__(self, output_file): 1851cb0ef41Sopenharmony_ci self.benchmarks_ = [] 1861cb0ef41Sopenharmony_ci self.print_output_ = [] 1871cb0ef41Sopenharmony_ci self.output_file_ = output_file 1881cb0ef41Sopenharmony_ci 1891cb0ef41Sopenharmony_ci def Print(self, str_data): 1901cb0ef41Sopenharmony_ci self.print_output_.append(str_data) 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci def FlushOutput(self): 1931cb0ef41Sopenharmony_ci string_data = "\n".join(self.print_output_) 1941cb0ef41Sopenharmony_ci print_output = [] 1951cb0ef41Sopenharmony_ci if self.output_file_: 1961cb0ef41Sopenharmony_ci # create a file 1971cb0ef41Sopenharmony_ci with open(self.output_file_, "w") as text_file: 1981cb0ef41Sopenharmony_ci text_file.write(string_data) 1991cb0ef41Sopenharmony_ci else: 2001cb0ef41Sopenharmony_ci print(string_data) 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ci def bold(self, data): 2031cb0ef41Sopenharmony_ci return "<b>%s</b>" % data 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci def red(self, data): 2061cb0ef41Sopenharmony_ci return "<font color=\"red\">%s</font>" % data 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci def green(self, data): 2101cb0ef41Sopenharmony_ci return "<font color=\"green\">%s</font>" % data 2111cb0ef41Sopenharmony_ci 2121cb0ef41Sopenharmony_ci def PrintHeader(self): 2131cb0ef41Sopenharmony_ci data = """<html> 2141cb0ef41Sopenharmony_ci<head> 2151cb0ef41Sopenharmony_ci<title>Output</title> 2161cb0ef41Sopenharmony_ci<style type="text/css"> 2171cb0ef41Sopenharmony_ci/* 2181cb0ef41Sopenharmony_ciStyle inspired by Andy Ferra's gist at https://gist.github.com/andyferra/2554919 2191cb0ef41Sopenharmony_ci*/ 2201cb0ef41Sopenharmony_cibody { 2211cb0ef41Sopenharmony_ci font-family: Helvetica, arial, sans-serif; 2221cb0ef41Sopenharmony_ci font-size: 14px; 2231cb0ef41Sopenharmony_ci line-height: 1.6; 2241cb0ef41Sopenharmony_ci padding-top: 10px; 2251cb0ef41Sopenharmony_ci padding-bottom: 10px; 2261cb0ef41Sopenharmony_ci background-color: white; 2271cb0ef41Sopenharmony_ci padding: 30px; 2281cb0ef41Sopenharmony_ci} 2291cb0ef41Sopenharmony_cih1, h2, h3, h4, h5, h6 { 2301cb0ef41Sopenharmony_ci margin: 20px 0 10px; 2311cb0ef41Sopenharmony_ci padding: 0; 2321cb0ef41Sopenharmony_ci font-weight: bold; 2331cb0ef41Sopenharmony_ci -webkit-font-smoothing: antialiased; 2341cb0ef41Sopenharmony_ci cursor: text; 2351cb0ef41Sopenharmony_ci position: relative; 2361cb0ef41Sopenharmony_ci} 2371cb0ef41Sopenharmony_cih1 { 2381cb0ef41Sopenharmony_ci font-size: 28px; 2391cb0ef41Sopenharmony_ci color: black; 2401cb0ef41Sopenharmony_ci} 2411cb0ef41Sopenharmony_ci 2421cb0ef41Sopenharmony_cih2 { 2431cb0ef41Sopenharmony_ci font-size: 24px; 2441cb0ef41Sopenharmony_ci border-bottom: 1px solid #cccccc; 2451cb0ef41Sopenharmony_ci color: black; 2461cb0ef41Sopenharmony_ci} 2471cb0ef41Sopenharmony_ci 2481cb0ef41Sopenharmony_cih3 { 2491cb0ef41Sopenharmony_ci font-size: 18px; 2501cb0ef41Sopenharmony_ci} 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_cih4 { 2531cb0ef41Sopenharmony_ci font-size: 16px; 2541cb0ef41Sopenharmony_ci} 2551cb0ef41Sopenharmony_ci 2561cb0ef41Sopenharmony_cih5 { 2571cb0ef41Sopenharmony_ci font-size: 14px; 2581cb0ef41Sopenharmony_ci} 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_cih6 { 2611cb0ef41Sopenharmony_ci color: #777777; 2621cb0ef41Sopenharmony_ci font-size: 14px; 2631cb0ef41Sopenharmony_ci} 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_cip, blockquote, ul, ol, dl, li, table, pre { 2661cb0ef41Sopenharmony_ci margin: 15px 0; 2671cb0ef41Sopenharmony_ci} 2681cb0ef41Sopenharmony_ci 2691cb0ef41Sopenharmony_cili p.first { 2701cb0ef41Sopenharmony_ci display: inline-block; 2711cb0ef41Sopenharmony_ci} 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ciul, ol { 2741cb0ef41Sopenharmony_ci padding-left: 30px; 2751cb0ef41Sopenharmony_ci} 2761cb0ef41Sopenharmony_ci 2771cb0ef41Sopenharmony_ciul :first-child, ol :first-child { 2781cb0ef41Sopenharmony_ci margin-top: 0; 2791cb0ef41Sopenharmony_ci} 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ciul :last-child, ol :last-child { 2821cb0ef41Sopenharmony_ci margin-bottom: 0; 2831cb0ef41Sopenharmony_ci} 2841cb0ef41Sopenharmony_ci 2851cb0ef41Sopenharmony_citable { 2861cb0ef41Sopenharmony_ci padding: 0; 2871cb0ef41Sopenharmony_ci} 2881cb0ef41Sopenharmony_ci 2891cb0ef41Sopenharmony_citable tr { 2901cb0ef41Sopenharmony_ci border-top: 1px solid #cccccc; 2911cb0ef41Sopenharmony_ci background-color: white; 2921cb0ef41Sopenharmony_ci margin: 0; 2931cb0ef41Sopenharmony_ci padding: 0; 2941cb0ef41Sopenharmony_ci} 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_citable tr:nth-child(2n) { 2971cb0ef41Sopenharmony_ci background-color: #f8f8f8; 2981cb0ef41Sopenharmony_ci} 2991cb0ef41Sopenharmony_ci 3001cb0ef41Sopenharmony_citable tr th { 3011cb0ef41Sopenharmony_ci font-weight: bold; 3021cb0ef41Sopenharmony_ci border: 1px solid #cccccc; 3031cb0ef41Sopenharmony_ci text-align: left; 3041cb0ef41Sopenharmony_ci margin: 0; 3051cb0ef41Sopenharmony_ci padding: 6px 13px; 3061cb0ef41Sopenharmony_ci} 3071cb0ef41Sopenharmony_citable tr td { 3081cb0ef41Sopenharmony_ci border: 1px solid #cccccc; 3091cb0ef41Sopenharmony_ci text-align: right; 3101cb0ef41Sopenharmony_ci margin: 0; 3111cb0ef41Sopenharmony_ci padding: 6px 13px; 3121cb0ef41Sopenharmony_ci} 3131cb0ef41Sopenharmony_citable tr td.name-column { 3141cb0ef41Sopenharmony_ci text-align: left; 3151cb0ef41Sopenharmony_ci} 3161cb0ef41Sopenharmony_citable tr th :first-child, table tr td :first-child { 3171cb0ef41Sopenharmony_ci margin-top: 0; 3181cb0ef41Sopenharmony_ci} 3191cb0ef41Sopenharmony_citable tr th :last-child, table tr td :last-child { 3201cb0ef41Sopenharmony_ci margin-bottom: 0; 3211cb0ef41Sopenharmony_ci} 3221cb0ef41Sopenharmony_ci</style> 3231cb0ef41Sopenharmony_ci</head> 3241cb0ef41Sopenharmony_ci<body> 3251cb0ef41Sopenharmony_ci""" 3261cb0ef41Sopenharmony_ci self.Print(data) 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci def StartSuite(self, suite_name, run_names): 3291cb0ef41Sopenharmony_ci self.Print("<h2>") 3301cb0ef41Sopenharmony_ci self.Print("<a name=\"%s\">%s</a> <a href=\"#top\">(top)</a>" % 3311cb0ef41Sopenharmony_ci (suite_name, suite_name)) 3321cb0ef41Sopenharmony_ci self.Print("</h2>"); 3331cb0ef41Sopenharmony_ci self.Print("<table class=\"benchmark\">") 3341cb0ef41Sopenharmony_ci self.Print("<thead>") 3351cb0ef41Sopenharmony_ci self.Print(" <th>Test</th>") 3361cb0ef41Sopenharmony_ci main_run = None 3371cb0ef41Sopenharmony_ci for run_name in run_names: 3381cb0ef41Sopenharmony_ci self.Print(" <th>%s</th>" % run_name) 3391cb0ef41Sopenharmony_ci if main_run == None: 3401cb0ef41Sopenharmony_ci main_run = run_name 3411cb0ef41Sopenharmony_ci else: 3421cb0ef41Sopenharmony_ci self.Print(" <th>%</th>") 3431cb0ef41Sopenharmony_ci self.Print("</thead>") 3441cb0ef41Sopenharmony_ci self.Print("<tbody>") 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_ci def FinishSuite(self): 3481cb0ef41Sopenharmony_ci self.Print("</tbody>") 3491cb0ef41Sopenharmony_ci self.Print("</table>") 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ci 3521cb0ef41Sopenharmony_ci def StartBenchmark(self, benchmark_name): 3531cb0ef41Sopenharmony_ci self.Print(" <tr>") 3541cb0ef41Sopenharmony_ci self.Print(" <td class=\"name-column\">%s</td>" % benchmark_name) 3551cb0ef41Sopenharmony_ci 3561cb0ef41Sopenharmony_ci def FinishBenchmark(self): 3571cb0ef41Sopenharmony_ci self.Print(" </tr>") 3581cb0ef41Sopenharmony_ci 3591cb0ef41Sopenharmony_ci 3601cb0ef41Sopenharmony_ci def PrintResult(self, run): 3611cb0ef41Sopenharmony_ci if run == None: 3621cb0ef41Sopenharmony_ci self.PrintEmptyCell() 3631cb0ef41Sopenharmony_ci return 3641cb0ef41Sopenharmony_ci self.Print(" <td>%3.1f</td>" % run.result()) 3651cb0ef41Sopenharmony_ci 3661cb0ef41Sopenharmony_ci 3671cb0ef41Sopenharmony_ci def PrintComparison(self, run, main_run): 3681cb0ef41Sopenharmony_ci if run == None or main_run == None: 3691cb0ef41Sopenharmony_ci self.PrintEmptyCell() 3701cb0ef41Sopenharmony_ci return 3711cb0ef41Sopenharmony_ci diff = run.Compare(main_run) 3721cb0ef41Sopenharmony_ci res = diff.percentage_string() 3731cb0ef41Sopenharmony_ci if diff.isSignificant(): 3741cb0ef41Sopenharmony_ci res = self.bold(res) 3751cb0ef41Sopenharmony_ci if diff.isNotablyPositive(): 3761cb0ef41Sopenharmony_ci res = self.green(res) 3771cb0ef41Sopenharmony_ci elif diff.isNotablyNegative(): 3781cb0ef41Sopenharmony_ci res = self.red(res) 3791cb0ef41Sopenharmony_ci self.Print(" <td>%s</td>" % res) 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ci 3821cb0ef41Sopenharmony_ci def PrintEmptyCell(self): 3831cb0ef41Sopenharmony_ci self.Print(" <td></td>") 3841cb0ef41Sopenharmony_ci 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci def StartTOC(self, title): 3871cb0ef41Sopenharmony_ci self.Print("<h1>%s</h1>" % title) 3881cb0ef41Sopenharmony_ci self.Print("<ul>") 3891cb0ef41Sopenharmony_ci 3901cb0ef41Sopenharmony_ci def FinishTOC(self): 3911cb0ef41Sopenharmony_ci self.Print("</ul>") 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci def PrintBenchmarkLink(self, benchmark): 3941cb0ef41Sopenharmony_ci self.Print("<li><a href=\"#" + benchmark + "\">" + benchmark + "</a></li>") 3951cb0ef41Sopenharmony_ci 3961cb0ef41Sopenharmony_ci def PrintFooter(self): 3971cb0ef41Sopenharmony_ci data = """</body> 3981cb0ef41Sopenharmony_ci</html> 3991cb0ef41Sopenharmony_ci""" 4001cb0ef41Sopenharmony_ci self.Print(data) 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_cidef Render(args): 4041cb0ef41Sopenharmony_ci benchmark_suites = {} 4051cb0ef41Sopenharmony_ci run_names = OrderedDict() 4061cb0ef41Sopenharmony_ci 4071cb0ef41Sopenharmony_ci for json_file_list in args.json_file_list: 4081cb0ef41Sopenharmony_ci run_name = json_file_list[0] 4091cb0ef41Sopenharmony_ci if run_name.endswith(".json"): 4101cb0ef41Sopenharmony_ci # The first item in the list is also a file name 4111cb0ef41Sopenharmony_ci run_name = os.path.splitext(run_name)[0] 4121cb0ef41Sopenharmony_ci filenames = json_file_list 4131cb0ef41Sopenharmony_ci else: 4141cb0ef41Sopenharmony_ci filenames = json_file_list[1:] 4151cb0ef41Sopenharmony_ci 4161cb0ef41Sopenharmony_ci for filename in filenames: 4171cb0ef41Sopenharmony_ci print ("Processing result set \"%s\", file: %s" % (run_name, filename)) 4181cb0ef41Sopenharmony_ci with open(filename) as json_data: 4191cb0ef41Sopenharmony_ci data = json.load(json_data) 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_ci run_names[run_name] = 0 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ci for error in data["errors"]: 4241cb0ef41Sopenharmony_ci print("Error:", error) 4251cb0ef41Sopenharmony_ci 4261cb0ef41Sopenharmony_ci for trace in data["traces"]: 4271cb0ef41Sopenharmony_ci suite_name = trace["graphs"][0] 4281cb0ef41Sopenharmony_ci benchmark_name = "/".join(trace["graphs"][1:]) 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci benchmark_suite_object = benchmark_suites.get(suite_name) 4311cb0ef41Sopenharmony_ci if benchmark_suite_object == None: 4321cb0ef41Sopenharmony_ci benchmark_suite_object = BenchmarkSuite(suite_name) 4331cb0ef41Sopenharmony_ci benchmark_suites[suite_name] = benchmark_suite_object 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci benchmark_object = benchmark_suite_object.getBenchmark(benchmark_name) 4361cb0ef41Sopenharmony_ci benchmark_object.appendResult(run_name, trace); 4371cb0ef41Sopenharmony_ci 4381cb0ef41Sopenharmony_ci 4391cb0ef41Sopenharmony_ci renderer = ResultTableRenderer(args.output) 4401cb0ef41Sopenharmony_ci renderer.PrintHeader() 4411cb0ef41Sopenharmony_ci 4421cb0ef41Sopenharmony_ci title = args.title or "Benchmark results" 4431cb0ef41Sopenharmony_ci renderer.StartTOC(title) 4441cb0ef41Sopenharmony_ci for suite_name, benchmark_suite_object in sorted(benchmark_suites.iteritems()): 4451cb0ef41Sopenharmony_ci renderer.PrintBenchmarkLink(suite_name) 4461cb0ef41Sopenharmony_ci renderer.FinishTOC() 4471cb0ef41Sopenharmony_ci 4481cb0ef41Sopenharmony_ci for suite_name, benchmark_suite_object in sorted(benchmark_suites.iteritems()): 4491cb0ef41Sopenharmony_ci renderer.StartSuite(suite_name, run_names) 4501cb0ef41Sopenharmony_ci for benchmark_name in benchmark_suite_object.SortedTestKeys(): 4511cb0ef41Sopenharmony_ci benchmark_object = benchmark_suite_object.getBenchmark(benchmark_name) 4521cb0ef41Sopenharmony_ci # print suite_name, benchmark_object.name() 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ci renderer.StartBenchmark(benchmark_name) 4551cb0ef41Sopenharmony_ci main_run = None 4561cb0ef41Sopenharmony_ci main_result = None 4571cb0ef41Sopenharmony_ci for run_name in run_names: 4581cb0ef41Sopenharmony_ci result = benchmark_object.getResult(run_name) 4591cb0ef41Sopenharmony_ci renderer.PrintResult(result) 4601cb0ef41Sopenharmony_ci if main_run == None: 4611cb0ef41Sopenharmony_ci main_run = run_name 4621cb0ef41Sopenharmony_ci main_result = result 4631cb0ef41Sopenharmony_ci else: 4641cb0ef41Sopenharmony_ci renderer.PrintComparison(result, main_result) 4651cb0ef41Sopenharmony_ci renderer.FinishBenchmark() 4661cb0ef41Sopenharmony_ci renderer.FinishSuite() 4671cb0ef41Sopenharmony_ci 4681cb0ef41Sopenharmony_ci renderer.PrintFooter() 4691cb0ef41Sopenharmony_ci renderer.FlushOutput() 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_cidef CommaSeparatedList(arg): 4721cb0ef41Sopenharmony_ci return [x for x in arg.split(',')] 4731cb0ef41Sopenharmony_ci 4741cb0ef41Sopenharmony_ciif __name__ == '__main__': 4751cb0ef41Sopenharmony_ci parser = ArgumentParser(description="Compare perf trybot JSON files and " + 4761cb0ef41Sopenharmony_ci "output the results into a pleasing HTML page.") 4771cb0ef41Sopenharmony_ci parser.add_argument("-t", "--title", dest="title", 4781cb0ef41Sopenharmony_ci help="Optional title of the web page") 4791cb0ef41Sopenharmony_ci parser.add_argument("-o", "--output", dest="output", 4801cb0ef41Sopenharmony_ci help="Write html output to this file rather than stdout") 4811cb0ef41Sopenharmony_ci parser.add_argument("json_file_list", nargs="+", type=CommaSeparatedList, 4821cb0ef41Sopenharmony_ci help="[column name,]./path-to/result.json - a comma-separated" + 4831cb0ef41Sopenharmony_ci " list of optional column name and paths to json files") 4841cb0ef41Sopenharmony_ci 4851cb0ef41Sopenharmony_ci args = parser.parse_args() 4861cb0ef41Sopenharmony_ci Render(args) 487