11cb0ef41Sopenharmony_ci#!/usr/bin/python3 21cb0ef41Sopenharmony_ci# Copyright 2019 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_ci# Runs chromium/src/run_benchmark for a given story and extracts the generated 71cb0ef41Sopenharmony_ci# runtime call stats. 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciimport argparse 101cb0ef41Sopenharmony_ciimport csv 111cb0ef41Sopenharmony_ciimport json 121cb0ef41Sopenharmony_ciimport glob 131cb0ef41Sopenharmony_ciimport os 141cb0ef41Sopenharmony_ciimport pathlib 151cb0ef41Sopenharmony_ciimport re 161cb0ef41Sopenharmony_ciimport tabulate 171cb0ef41Sopenharmony_ciimport shutil 181cb0ef41Sopenharmony_ciimport statistics 191cb0ef41Sopenharmony_ciimport subprocess 201cb0ef41Sopenharmony_ciimport sys 211cb0ef41Sopenharmony_ciimport tempfile 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_cifrom callstats_groups import RUNTIME_CALL_STATS_GROUPS 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ciJSON_FILE_EXTENSION=".pb_converted.json" 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_cidef parse_args(): 291cb0ef41Sopenharmony_ci parser = argparse.ArgumentParser( 301cb0ef41Sopenharmony_ci description="Run story and collect runtime call stats.") 311cb0ef41Sopenharmony_ci parser.add_argument("story", metavar="story", nargs=1, help="story to run") 321cb0ef41Sopenharmony_ci parser.add_argument( 331cb0ef41Sopenharmony_ci "--group", 341cb0ef41Sopenharmony_ci dest="group", 351cb0ef41Sopenharmony_ci action="store_true", 361cb0ef41Sopenharmony_ci help="group common stats together into buckets") 371cb0ef41Sopenharmony_ci parser.add_argument( 381cb0ef41Sopenharmony_ci "-r", 391cb0ef41Sopenharmony_ci "--repeats", 401cb0ef41Sopenharmony_ci dest="repeats", 411cb0ef41Sopenharmony_ci metavar="N", 421cb0ef41Sopenharmony_ci action="store", 431cb0ef41Sopenharmony_ci type=int, 441cb0ef41Sopenharmony_ci default=1, 451cb0ef41Sopenharmony_ci help="number of times to run the story") 461cb0ef41Sopenharmony_ci parser.add_argument( 471cb0ef41Sopenharmony_ci "-v", 481cb0ef41Sopenharmony_ci "--verbose", 491cb0ef41Sopenharmony_ci dest="verbose", 501cb0ef41Sopenharmony_ci action="store_true", 511cb0ef41Sopenharmony_ci help="output benchmark runs to stdout") 521cb0ef41Sopenharmony_ci parser.add_argument( 531cb0ef41Sopenharmony_ci "--device", 541cb0ef41Sopenharmony_ci dest="device", 551cb0ef41Sopenharmony_ci action="store", 561cb0ef41Sopenharmony_ci help="device to run the test on. Passed directly to run_benchmark") 571cb0ef41Sopenharmony_ci parser.add_argument( 581cb0ef41Sopenharmony_ci "-d", 591cb0ef41Sopenharmony_ci "--dir", 601cb0ef41Sopenharmony_ci dest="dir", 611cb0ef41Sopenharmony_ci action="store", 621cb0ef41Sopenharmony_ci help=("directory to look for already generated output in. This must " 631cb0ef41Sopenharmony_ci "already exists and it won't re-run the benchmark")) 641cb0ef41Sopenharmony_ci parser.add_argument( 651cb0ef41Sopenharmony_ci "-f", 661cb0ef41Sopenharmony_ci "--format", 671cb0ef41Sopenharmony_ci dest="format", 681cb0ef41Sopenharmony_ci action="store", 691cb0ef41Sopenharmony_ci choices=["csv", "table"], 701cb0ef41Sopenharmony_ci help="output as CSV") 711cb0ef41Sopenharmony_ci parser.add_argument( 721cb0ef41Sopenharmony_ci "-o", 731cb0ef41Sopenharmony_ci "--output", 741cb0ef41Sopenharmony_ci metavar="FILE", 751cb0ef41Sopenharmony_ci dest="out_file", 761cb0ef41Sopenharmony_ci action="store", 771cb0ef41Sopenharmony_ci help="write table to FILE rather stdout") 781cb0ef41Sopenharmony_ci parser.add_argument( 791cb0ef41Sopenharmony_ci "--browser", 801cb0ef41Sopenharmony_ci dest="browser", 811cb0ef41Sopenharmony_ci metavar="BROWSER_TYPE", 821cb0ef41Sopenharmony_ci action="store", 831cb0ef41Sopenharmony_ci default="release", 841cb0ef41Sopenharmony_ci help=("Passed directly to --browser option of run_benchmark. Ignored if " 851cb0ef41Sopenharmony_ci "-executable is used")) 861cb0ef41Sopenharmony_ci parser.add_argument( 871cb0ef41Sopenharmony_ci "-e", 881cb0ef41Sopenharmony_ci "--executable", 891cb0ef41Sopenharmony_ci dest="executable", 901cb0ef41Sopenharmony_ci metavar="EXECUTABLE", 911cb0ef41Sopenharmony_ci action="store", 921cb0ef41Sopenharmony_ci help=("path to executable to run. If not given it will pass '--browser " 931cb0ef41Sopenharmony_ci "release' to run_benchmark")) 941cb0ef41Sopenharmony_ci parser.add_argument( 951cb0ef41Sopenharmony_ci "--chromium-dir", 961cb0ef41Sopenharmony_ci dest="chromium_dir", 971cb0ef41Sopenharmony_ci metavar="DIR", 981cb0ef41Sopenharmony_ci action="store", 991cb0ef41Sopenharmony_ci default=".", 1001cb0ef41Sopenharmony_ci help=("path to chromium directory. If not given, the script must be run " 1011cb0ef41Sopenharmony_ci "inside the chromium/src directory")) 1021cb0ef41Sopenharmony_ci parser.add_argument( 1031cb0ef41Sopenharmony_ci "--js-flags", dest="js_flags", action="store", help="flags to pass to v8") 1041cb0ef41Sopenharmony_ci parser.add_argument( 1051cb0ef41Sopenharmony_ci "--extra-browser-args", 1061cb0ef41Sopenharmony_ci dest="browser_args", 1071cb0ef41Sopenharmony_ci action="store", 1081cb0ef41Sopenharmony_ci help="flags to pass to chrome") 1091cb0ef41Sopenharmony_ci parser.add_argument( 1101cb0ef41Sopenharmony_ci "--benchmark", 1111cb0ef41Sopenharmony_ci dest="benchmark", 1121cb0ef41Sopenharmony_ci action="store", 1131cb0ef41Sopenharmony_ci default="v8.browsing_desktop", 1141cb0ef41Sopenharmony_ci help="benchmark to run") 1151cb0ef41Sopenharmony_ci parser.add_argument( 1161cb0ef41Sopenharmony_ci "--stdev", 1171cb0ef41Sopenharmony_ci dest="stdev", 1181cb0ef41Sopenharmony_ci action="store_true", 1191cb0ef41Sopenharmony_ci help="adds columns for the standard deviation") 1201cb0ef41Sopenharmony_ci parser.add_argument( 1211cb0ef41Sopenharmony_ci "--filter", 1221cb0ef41Sopenharmony_ci dest="filter", 1231cb0ef41Sopenharmony_ci action="append", 1241cb0ef41Sopenharmony_ci help="useable with --group to only show buckets specified by filter") 1251cb0ef41Sopenharmony_ci parser.add_argument( 1261cb0ef41Sopenharmony_ci "--retain", 1271cb0ef41Sopenharmony_ci dest="retain", 1281cb0ef41Sopenharmony_ci action="store", 1291cb0ef41Sopenharmony_ci default="json", 1301cb0ef41Sopenharmony_ci choices=["none", "json", "all"], 1311cb0ef41Sopenharmony_ci help=("controls artifacts to be retained after run. With none, all files " 1321cb0ef41Sopenharmony_ci "are deleted; only the json.gz file is retained for each run; and " 1331cb0ef41Sopenharmony_ci "all keep all files")) 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci return parser.parse_args() 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_cidef process_trace(trace_file): 1391cb0ef41Sopenharmony_ci text_string = pathlib.Path(trace_file).read_text() 1401cb0ef41Sopenharmony_ci result = json.loads(text_string) 1411cb0ef41Sopenharmony_ci 1421cb0ef41Sopenharmony_ci output = {} 1431cb0ef41Sopenharmony_ci result = result["traceEvents"] 1441cb0ef41Sopenharmony_ci for o in result: 1451cb0ef41Sopenharmony_ci o = o["args"] 1461cb0ef41Sopenharmony_ci if "runtime-call-stats" in o: 1471cb0ef41Sopenharmony_ci r = o["runtime-call-stats"] 1481cb0ef41Sopenharmony_ci for name in r: 1491cb0ef41Sopenharmony_ci count = r[name][0] 1501cb0ef41Sopenharmony_ci duration = r[name][1] 1511cb0ef41Sopenharmony_ci if name in output: 1521cb0ef41Sopenharmony_ci output[name]["count"] += count 1531cb0ef41Sopenharmony_ci output[name]["duration"] += duration 1541cb0ef41Sopenharmony_ci else: 1551cb0ef41Sopenharmony_ci output[name] = {"count": count, "duration": duration} 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci return output 1581cb0ef41Sopenharmony_ci 1591cb0ef41Sopenharmony_ci 1601cb0ef41Sopenharmony_cidef run_benchmark(story, 1611cb0ef41Sopenharmony_ci repeats=1, 1621cb0ef41Sopenharmony_ci output_dir=".", 1631cb0ef41Sopenharmony_ci verbose=False, 1641cb0ef41Sopenharmony_ci js_flags=None, 1651cb0ef41Sopenharmony_ci browser_args=None, 1661cb0ef41Sopenharmony_ci chromium_dir=".", 1671cb0ef41Sopenharmony_ci executable=None, 1681cb0ef41Sopenharmony_ci benchmark="v8.browsing_desktop", 1691cb0ef41Sopenharmony_ci device=None, 1701cb0ef41Sopenharmony_ci browser="release"): 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci orig_chromium_dir = chromium_dir 1731cb0ef41Sopenharmony_ci xvfb = os.path.join(chromium_dir, "testing", "xvfb.py") 1741cb0ef41Sopenharmony_ci if not os.path.isfile(xvfb): 1751cb0ef41Sopenharmony_ci chromium_dir = os.path(chromium_dir, "src") 1761cb0ef41Sopenharmony_ci xvfb = os.path.join(chromium_dir, "testing", "xvfb.py") 1771cb0ef41Sopenharmony_ci if not os.path.isfile(xvfb): 1781cb0ef41Sopenharmony_ci print(("chromium_dir does not point to a valid chromium checkout: " + 1791cb0ef41Sopenharmony_ci orig_chromium_dir)) 1801cb0ef41Sopenharmony_ci sys.exit(1) 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci command = [ 1831cb0ef41Sopenharmony_ci xvfb, 1841cb0ef41Sopenharmony_ci os.path.join(chromium_dir, "tools", "perf", "run_benchmark"), 1851cb0ef41Sopenharmony_ci "run", 1861cb0ef41Sopenharmony_ci "--story", 1871cb0ef41Sopenharmony_ci story, 1881cb0ef41Sopenharmony_ci "--pageset-repeat", 1891cb0ef41Sopenharmony_ci str(repeats), 1901cb0ef41Sopenharmony_ci "--output-dir", 1911cb0ef41Sopenharmony_ci output_dir, 1921cb0ef41Sopenharmony_ci "--intermediate-dir", 1931cb0ef41Sopenharmony_ci os.path.join(output_dir, "artifacts"), 1941cb0ef41Sopenharmony_ci benchmark, 1951cb0ef41Sopenharmony_ci ] 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci if executable: 1981cb0ef41Sopenharmony_ci command += ["--browser-executable", executable] 1991cb0ef41Sopenharmony_ci else: 2001cb0ef41Sopenharmony_ci command += ["--browser", browser] 2011cb0ef41Sopenharmony_ci 2021cb0ef41Sopenharmony_ci if device: 2031cb0ef41Sopenharmony_ci command += ["--device", device] 2041cb0ef41Sopenharmony_ci if browser_args: 2051cb0ef41Sopenharmony_ci command += ["--extra-browser-args", browser_args] 2061cb0ef41Sopenharmony_ci if js_flags: 2071cb0ef41Sopenharmony_ci command += ["--js-flags", js_flags] 2081cb0ef41Sopenharmony_ci 2091cb0ef41Sopenharmony_ci if not benchmark.startswith("v8."): 2101cb0ef41Sopenharmony_ci # Most benchmarks by default don't collect runtime call stats so enable them 2111cb0ef41Sopenharmony_ci # manually. 2121cb0ef41Sopenharmony_ci categories = [ 2131cb0ef41Sopenharmony_ci "v8", 2141cb0ef41Sopenharmony_ci "disabled-by-default-v8.runtime_stats", 2151cb0ef41Sopenharmony_ci ] 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci command += ["--extra-chrome-categories", ",".join(categories)] 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci print("Output directory: %s" % output_dir) 2201cb0ef41Sopenharmony_ci stdout = "" 2211cb0ef41Sopenharmony_ci print(f"Running: {' '.join(command)}\n") 2221cb0ef41Sopenharmony_ci proc = subprocess.Popen( 2231cb0ef41Sopenharmony_ci command, 2241cb0ef41Sopenharmony_ci stdout=subprocess.PIPE, 2251cb0ef41Sopenharmony_ci stderr=subprocess.PIPE, 2261cb0ef41Sopenharmony_ci universal_newlines=True) 2271cb0ef41Sopenharmony_ci proc.stderr.close() 2281cb0ef41Sopenharmony_ci status_matcher = re.compile(r"\[ +(\w+) +\]") 2291cb0ef41Sopenharmony_ci for line in iter(proc.stdout.readline, ""): 2301cb0ef41Sopenharmony_ci stdout += line 2311cb0ef41Sopenharmony_ci match = status_matcher.match(line) 2321cb0ef41Sopenharmony_ci if verbose or match: 2331cb0ef41Sopenharmony_ci print(line, end="") 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ci proc.stdout.close() 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci if proc.wait() != 0: 2381cb0ef41Sopenharmony_ci print("\nrun_benchmark failed:") 2391cb0ef41Sopenharmony_ci # If verbose then everything has already been printed. 2401cb0ef41Sopenharmony_ci if not verbose: 2411cb0ef41Sopenharmony_ci print(stdout) 2421cb0ef41Sopenharmony_ci sys.exit(1) 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci print("\nrun_benchmark completed") 2451cb0ef41Sopenharmony_ci 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_cidef write_output(f, table, headers, run_count, format="table"): 2481cb0ef41Sopenharmony_ci if format == "csv": 2491cb0ef41Sopenharmony_ci # strip new lines from CSV output 2501cb0ef41Sopenharmony_ci headers = [h.replace("\n", " ") for h in headers] 2511cb0ef41Sopenharmony_ci writer = csv.writer(f) 2521cb0ef41Sopenharmony_ci writer.writerow(headers) 2531cb0ef41Sopenharmony_ci writer.writerows(table) 2541cb0ef41Sopenharmony_ci else: 2551cb0ef41Sopenharmony_ci # First column is name, and then they alternate between counts and durations 2561cb0ef41Sopenharmony_ci summary_count = len(headers) - 2 * run_count - 1 2571cb0ef41Sopenharmony_ci floatfmt = ("",) + (".0f", ".2f") * run_count + (".2f",) * summary_count 2581cb0ef41Sopenharmony_ci f.write(tabulate.tabulate(table, headers=headers, floatfmt=floatfmt)) 2591cb0ef41Sopenharmony_ci f.write("\n") 2601cb0ef41Sopenharmony_ci 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_ciclass Row: 2631cb0ef41Sopenharmony_ci 2641cb0ef41Sopenharmony_ci def __init__(self, name, run_count): 2651cb0ef41Sopenharmony_ci self.name = name 2661cb0ef41Sopenharmony_ci self.durations = [0] * run_count 2671cb0ef41Sopenharmony_ci self.counts = [0] * run_count 2681cb0ef41Sopenharmony_ci self.mean_duration = None 2691cb0ef41Sopenharmony_ci self.mean_count = None 2701cb0ef41Sopenharmony_ci self.stdev_duration = None 2711cb0ef41Sopenharmony_ci self.stdev_count = None 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci def __repr__(self): 2741cb0ef41Sopenharmony_ci data_str = ", ".join( 2751cb0ef41Sopenharmony_ci str((c, d)) for (c, d) in zip(self.counts, self.durations)) 2761cb0ef41Sopenharmony_ci return (f"{self.name}: {data_str}, mean_count: {self.mean_count}, " + 2771cb0ef41Sopenharmony_ci f"mean_duration: {self.mean_duration}") 2781cb0ef41Sopenharmony_ci 2791cb0ef41Sopenharmony_ci def add_data(self, counts, durations): 2801cb0ef41Sopenharmony_ci self.counts = counts 2811cb0ef41Sopenharmony_ci self.durations = durations 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ci def add_data_point(self, run, count, duration): 2841cb0ef41Sopenharmony_ci self.counts[run] = count 2851cb0ef41Sopenharmony_ci self.durations[run] = duration 2861cb0ef41Sopenharmony_ci 2871cb0ef41Sopenharmony_ci def prepare(self, stdev=False): 2881cb0ef41Sopenharmony_ci if len(self.durations) > 1: 2891cb0ef41Sopenharmony_ci self.mean_duration = statistics.mean(self.durations) 2901cb0ef41Sopenharmony_ci self.mean_count = statistics.mean(self.counts) 2911cb0ef41Sopenharmony_ci if stdev: 2921cb0ef41Sopenharmony_ci self.stdev_duration = statistics.stdev(self.durations) 2931cb0ef41Sopenharmony_ci self.stdev_count = statistics.stdev(self.counts) 2941cb0ef41Sopenharmony_ci 2951cb0ef41Sopenharmony_ci def as_list(self): 2961cb0ef41Sopenharmony_ci l = [self.name] 2971cb0ef41Sopenharmony_ci for (c, d) in zip(self.counts, self.durations): 2981cb0ef41Sopenharmony_ci l += [c, d] 2991cb0ef41Sopenharmony_ci if self.mean_duration is not None: 3001cb0ef41Sopenharmony_ci l += [self.mean_count] 3011cb0ef41Sopenharmony_ci if self.stdev_count is not None: 3021cb0ef41Sopenharmony_ci l += [self.stdev_count] 3031cb0ef41Sopenharmony_ci l += [self.mean_duration] 3041cb0ef41Sopenharmony_ci if self.stdev_duration is not None: 3051cb0ef41Sopenharmony_ci l += [self.stdev_duration] 3061cb0ef41Sopenharmony_ci return l 3071cb0ef41Sopenharmony_ci 3081cb0ef41Sopenharmony_ci def key(self): 3091cb0ef41Sopenharmony_ci if self.mean_duration is not None: 3101cb0ef41Sopenharmony_ci return self.mean_duration 3111cb0ef41Sopenharmony_ci else: 3121cb0ef41Sopenharmony_ci return self.durations[0] 3131cb0ef41Sopenharmony_ci 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ciclass Bucket: 3161cb0ef41Sopenharmony_ci 3171cb0ef41Sopenharmony_ci def __init__(self, name, run_count): 3181cb0ef41Sopenharmony_ci self.name = name 3191cb0ef41Sopenharmony_ci self.run_count = run_count 3201cb0ef41Sopenharmony_ci self.data = {} 3211cb0ef41Sopenharmony_ci self.table = None 3221cb0ef41Sopenharmony_ci self.total_row = None 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_ci def __repr__(self): 3251cb0ef41Sopenharmony_ci s = "Bucket: " + self.name + " {\n" 3261cb0ef41Sopenharmony_ci if self.table: 3271cb0ef41Sopenharmony_ci s += "\n ".join(str(row) for row in self.table) + "\n" 3281cb0ef41Sopenharmony_ci elif self.data: 3291cb0ef41Sopenharmony_ci s += "\n ".join(str(row) for row in self.data.values()) + "\n" 3301cb0ef41Sopenharmony_ci if self.total_row: 3311cb0ef41Sopenharmony_ci s += " " + str(self.total_row) + "\n" 3321cb0ef41Sopenharmony_ci return s + "}" 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_ci def add_data_point(self, name, run, count, duration): 3351cb0ef41Sopenharmony_ci if name not in self.data: 3361cb0ef41Sopenharmony_ci self.data[name] = Row(name, self.run_count) 3371cb0ef41Sopenharmony_ci 3381cb0ef41Sopenharmony_ci self.data[name].add_data_point(run, count, duration) 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci def prepare(self, stdev=False): 3411cb0ef41Sopenharmony_ci if self.data: 3421cb0ef41Sopenharmony_ci for row in self.data.values(): 3431cb0ef41Sopenharmony_ci row.prepare(stdev) 3441cb0ef41Sopenharmony_ci 3451cb0ef41Sopenharmony_ci self.table = sorted(self.data.values(), key=Row.key) 3461cb0ef41Sopenharmony_ci self.total_row = Row("Total", self.run_count) 3471cb0ef41Sopenharmony_ci self.total_row.add_data([ 3481cb0ef41Sopenharmony_ci sum(r.counts[i] 3491cb0ef41Sopenharmony_ci for r in self.data.values()) 3501cb0ef41Sopenharmony_ci for i in range(0, self.run_count) 3511cb0ef41Sopenharmony_ci ], [ 3521cb0ef41Sopenharmony_ci sum(r.durations[i] 3531cb0ef41Sopenharmony_ci for r in self.data.values()) 3541cb0ef41Sopenharmony_ci for i in range(0, self.run_count) 3551cb0ef41Sopenharmony_ci ]) 3561cb0ef41Sopenharmony_ci self.total_row.prepare(stdev) 3571cb0ef41Sopenharmony_ci 3581cb0ef41Sopenharmony_ci def as_list(self, add_bucket_titles=True, filter=None): 3591cb0ef41Sopenharmony_ci t = [] 3601cb0ef41Sopenharmony_ci if filter is None or self.name in filter: 3611cb0ef41Sopenharmony_ci if add_bucket_titles: 3621cb0ef41Sopenharmony_ci t += [["\n"], [self.name]] 3631cb0ef41Sopenharmony_ci t += [r.as_list() for r in self.table] 3641cb0ef41Sopenharmony_ci t += [self.total_row.as_list()] 3651cb0ef41Sopenharmony_ci return t 3661cb0ef41Sopenharmony_ci 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_cidef collect_buckets(story, group=True, repeats=1, output_dir="."): 3691cb0ef41Sopenharmony_ci if group: 3701cb0ef41Sopenharmony_ci groups = RUNTIME_CALL_STATS_GROUPS 3711cb0ef41Sopenharmony_ci else: 3721cb0ef41Sopenharmony_ci groups = [] 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci buckets = {} 3751cb0ef41Sopenharmony_ci 3761cb0ef41Sopenharmony_ci for i in range(0, repeats): 3771cb0ef41Sopenharmony_ci story_dir = f"{story.replace(':', '_')}_{i + 1}" 3781cb0ef41Sopenharmony_ci trace_dir = os.path.join(output_dir, "artifacts", story_dir, "trace", 3791cb0ef41Sopenharmony_ci "traceEvents") 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ci # run_benchmark now dumps two files: a .pb.gz file and a .pb_converted.json 3821cb0ef41Sopenharmony_ci # file. We only need the latter. 3831cb0ef41Sopenharmony_ci trace_file_glob = os.path.join(trace_dir, "*" + JSON_FILE_EXTENSION) 3841cb0ef41Sopenharmony_ci trace_files = glob.glob(trace_file_glob) 3851cb0ef41Sopenharmony_ci if not trace_files: 3861cb0ef41Sopenharmony_ci print("Could not find *%s file in %s" % (JSON_FILE_EXTENSION, trace_dir)) 3871cb0ef41Sopenharmony_ci sys.exit(1) 3881cb0ef41Sopenharmony_ci if len(trace_files) > 1: 3891cb0ef41Sopenharmony_ci print("Expecting one file but got: %s" % trace_files) 3901cb0ef41Sopenharmony_ci sys.exit(1) 3911cb0ef41Sopenharmony_ci 3921cb0ef41Sopenharmony_ci trace_file = trace_files[0] 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci output = process_trace(trace_file) 3951cb0ef41Sopenharmony_ci for name in output: 3961cb0ef41Sopenharmony_ci bucket_name = "Other" 3971cb0ef41Sopenharmony_ci for group in groups: 3981cb0ef41Sopenharmony_ci if group[1].match(name): 3991cb0ef41Sopenharmony_ci bucket_name = group[0] 4001cb0ef41Sopenharmony_ci break 4011cb0ef41Sopenharmony_ci 4021cb0ef41Sopenharmony_ci value = output[name] 4031cb0ef41Sopenharmony_ci if bucket_name not in buckets: 4041cb0ef41Sopenharmony_ci bucket = Bucket(bucket_name, repeats) 4051cb0ef41Sopenharmony_ci buckets[bucket_name] = bucket 4061cb0ef41Sopenharmony_ci else: 4071cb0ef41Sopenharmony_ci bucket = buckets[bucket_name] 4081cb0ef41Sopenharmony_ci 4091cb0ef41Sopenharmony_ci bucket.add_data_point(name, i, value["count"], value["duration"] / 1000.0) 4101cb0ef41Sopenharmony_ci return buckets 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci 4131cb0ef41Sopenharmony_cidef create_table(buckets, record_bucket_names=True, filter=None): 4141cb0ef41Sopenharmony_ci table = [] 4151cb0ef41Sopenharmony_ci for bucket in buckets.values(): 4161cb0ef41Sopenharmony_ci table += bucket.as_list( 4171cb0ef41Sopenharmony_ci add_bucket_titles=record_bucket_names, filter=filter) 4181cb0ef41Sopenharmony_ci return table 4191cb0ef41Sopenharmony_ci 4201cb0ef41Sopenharmony_ci 4211cb0ef41Sopenharmony_cidef main(): 4221cb0ef41Sopenharmony_ci args = parse_args() 4231cb0ef41Sopenharmony_ci story = args.story[0] 4241cb0ef41Sopenharmony_ci 4251cb0ef41Sopenharmony_ci retain = args.retain 4261cb0ef41Sopenharmony_ci if args.dir is not None: 4271cb0ef41Sopenharmony_ci output_dir = args.dir 4281cb0ef41Sopenharmony_ci if not os.path.isdir(output_dir): 4291cb0ef41Sopenharmony_ci print("Specified output directory does not exist: " % output_dir) 4301cb0ef41Sopenharmony_ci sys.exit(1) 4311cb0ef41Sopenharmony_ci else: 4321cb0ef41Sopenharmony_ci output_dir = tempfile.mkdtemp(prefix="runtime_call_stats_") 4331cb0ef41Sopenharmony_ci run_benchmark( 4341cb0ef41Sopenharmony_ci story, 4351cb0ef41Sopenharmony_ci repeats=args.repeats, 4361cb0ef41Sopenharmony_ci output_dir=output_dir, 4371cb0ef41Sopenharmony_ci verbose=args.verbose, 4381cb0ef41Sopenharmony_ci js_flags=args.js_flags, 4391cb0ef41Sopenharmony_ci browser_args=args.browser_args, 4401cb0ef41Sopenharmony_ci chromium_dir=args.chromium_dir, 4411cb0ef41Sopenharmony_ci benchmark=args.benchmark, 4421cb0ef41Sopenharmony_ci executable=args.executable, 4431cb0ef41Sopenharmony_ci browser=args.browser, 4441cb0ef41Sopenharmony_ci device=args.device) 4451cb0ef41Sopenharmony_ci 4461cb0ef41Sopenharmony_ci try: 4471cb0ef41Sopenharmony_ci buckets = collect_buckets( 4481cb0ef41Sopenharmony_ci story, group=args.group, repeats=args.repeats, output_dir=output_dir) 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ci for b in buckets.values(): 4511cb0ef41Sopenharmony_ci b.prepare(args.stdev) 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci table = create_table( 4541cb0ef41Sopenharmony_ci buckets, record_bucket_names=args.group, filter=args.filter) 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci headers = [""] + ["Count", "Duration\n(ms)"] * args.repeats 4571cb0ef41Sopenharmony_ci if args.repeats > 1: 4581cb0ef41Sopenharmony_ci if args.stdev: 4591cb0ef41Sopenharmony_ci headers += [ 4601cb0ef41Sopenharmony_ci "Count\nMean", "Count\nStdev", "Duration\nMean (ms)", 4611cb0ef41Sopenharmony_ci "Duration\nStdev (ms)" 4621cb0ef41Sopenharmony_ci ] 4631cb0ef41Sopenharmony_ci else: 4641cb0ef41Sopenharmony_ci headers += ["Count\nMean", "Duration\nMean (ms)"] 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ci if args.out_file: 4671cb0ef41Sopenharmony_ci with open(args.out_file, "w", newline="") as f: 4681cb0ef41Sopenharmony_ci write_output(f, table, headers, args.repeats, args.format) 4691cb0ef41Sopenharmony_ci else: 4701cb0ef41Sopenharmony_ci write_output(sys.stdout, table, headers, args.repeats, args.format) 4711cb0ef41Sopenharmony_ci finally: 4721cb0ef41Sopenharmony_ci if retain == "none": 4731cb0ef41Sopenharmony_ci shutil.rmtree(output_dir) 4741cb0ef41Sopenharmony_ci elif retain == "json": 4751cb0ef41Sopenharmony_ci # Delete all files bottom up except ones ending in JSON_FILE_EXTENSION and 4761cb0ef41Sopenharmony_ci # attempt to delete subdirectories (ignoring errors). 4771cb0ef41Sopenharmony_ci for dir_name, subdir_list, file_list in os.walk( 4781cb0ef41Sopenharmony_ci output_dir, topdown=False): 4791cb0ef41Sopenharmony_ci for file_name in file_list: 4801cb0ef41Sopenharmony_ci if not file_name.endswith(JSON_FILE_EXTENSION): 4811cb0ef41Sopenharmony_ci os.remove(os.path.join(dir_name, file_name)) 4821cb0ef41Sopenharmony_ci for subdir in subdir_list: 4831cb0ef41Sopenharmony_ci try: 4841cb0ef41Sopenharmony_ci os.rmdir(os.path.join(dir_name, subdir)) 4851cb0ef41Sopenharmony_ci except OSError: 4861cb0ef41Sopenharmony_ci pass 4871cb0ef41Sopenharmony_ci 4881cb0ef41Sopenharmony_ci 4891cb0ef41Sopenharmony_ciif __name__ == "__main__": 4901cb0ef41Sopenharmony_ci sys.exit(main()) 491