mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-26 23:21:11 +00:00
126 lines
4.7 KiB
Python
Executable File
126 lines
4.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import argparse
|
|
import csv
|
|
import re
|
|
import sys
|
|
import os
|
|
from statistics import geometric_mean
|
|
|
|
TIMING_LOG_RE = re.compile(r"(.*)/(.*).tmp(.*)")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="BOLT NFC stat parser",
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
)
|
|
parser.add_argument(
|
|
"input", nargs="+", help="timing.log files produced by llvm-bolt-wrapper"
|
|
)
|
|
parser.add_argument(
|
|
"--check_longer_than",
|
|
default=2,
|
|
type=float,
|
|
help="Only warn on tests longer than X seconds for at least one side",
|
|
)
|
|
parser.add_argument(
|
|
"--threshold_single",
|
|
default=10,
|
|
type=float,
|
|
help="Threshold for a single test result swing, abs percent",
|
|
),
|
|
parser.add_argument(
|
|
"--threshold_agg",
|
|
default=5,
|
|
type=float,
|
|
help="Threshold for geomean test results swing, abs percent",
|
|
),
|
|
parser.add_argument("--verbose", "-v", action="store_true")
|
|
args = parser.parse_args()
|
|
|
|
def fmt_delta(value, exc_threshold, above_bound=True):
|
|
formatted_value = format(value, "+.2%")
|
|
if not above_bound:
|
|
formatted_value += "?"
|
|
elif exc_threshold and sys.stdout.isatty(): # terminal supports colors
|
|
return f"\033[1m{formatted_value}\033[0m"
|
|
return formatted_value
|
|
|
|
# Ratios for geomean computation
|
|
time_ratios = []
|
|
mem_ratios = []
|
|
# Whether any test exceeds the single test threshold (mem or time)
|
|
threshold_single = False
|
|
# Whether geomean exceeds aggregate test threshold (mem or time)
|
|
threshold_agg = False
|
|
|
|
if args.verbose:
|
|
print(f"# Individual test threshold: +-{args.threshold_single}%")
|
|
print(f"# Aggregate (geomean) test threshold: +-{args.threshold_agg}%")
|
|
print(
|
|
f"# Checking time swings for tests with runtime >"
|
|
f"{args.check_longer_than}s - otherwise marked as ?"
|
|
)
|
|
print("Test/binary BOLT_wall_time BOLT_max_rss")
|
|
|
|
for input_file in args.input:
|
|
input_dir = os.path.dirname(input_file)
|
|
with open(input_file) as timing_file:
|
|
timing_reader = csv.reader(timing_file, delimiter=";")
|
|
for row in timing_reader:
|
|
test_name = row[0]
|
|
m = TIMING_LOG_RE.match(row[0])
|
|
if m:
|
|
test_name = f"{input_dir}/{m.groups()[1]}/{m.groups()[2]}"
|
|
else:
|
|
# Prepend input dir to unparsed test name
|
|
test_name = input_dir + "#" + test_name
|
|
time_a, time_b = float(row[1]), float(row[3])
|
|
mem_a, mem_b = int(row[2]), int(row[4])
|
|
# Check if time is above bound for at least one side
|
|
time_above_bound = any(
|
|
[x > args.check_longer_than for x in [time_a, time_b]]
|
|
)
|
|
# Compute B/A ratios (for % delta and geomean)
|
|
time_ratio = time_b / time_a if time_a else float('nan')
|
|
mem_ratio = mem_b / mem_a if mem_a else float('nan')
|
|
# Keep ratios for geomean
|
|
if time_above_bound and time_ratio > 0: # must be >0 for gmean
|
|
time_ratios += [time_ratio]
|
|
mem_ratios += [mem_ratio]
|
|
# Deltas: (B/A)-1 = (B-A)/A
|
|
time_delta = time_ratio - 1
|
|
mem_delta = mem_ratio - 1
|
|
# Check individual test results vs single test threshold
|
|
time_exc = (
|
|
100.0 * abs(time_delta) > args.threshold_single and time_above_bound
|
|
)
|
|
mem_exc = 100.0 * abs(mem_delta) > args.threshold_single
|
|
if time_exc or mem_exc:
|
|
threshold_single = True
|
|
# Print deltas with formatting in verbose mode
|
|
if args.verbose or time_exc or mem_exc:
|
|
print(
|
|
test_name,
|
|
fmt_delta(time_delta, time_exc, time_above_bound),
|
|
fmt_delta(mem_delta, mem_exc),
|
|
)
|
|
|
|
time_gmean_delta = geometric_mean(time_ratios) - 1
|
|
mem_gmean_delta = geometric_mean(mem_ratios) - 1
|
|
time_agg_threshold = 100.0 * abs(time_gmean_delta) > args.threshold_agg
|
|
mem_agg_threshold = 100.0 * abs(mem_gmean_delta) > args.threshold_agg
|
|
if time_agg_threshold or mem_agg_threshold:
|
|
threshold_agg = True
|
|
if time_agg_threshold or mem_agg_threshold or args.verbose:
|
|
print(
|
|
"Geomean",
|
|
fmt_delta(time_gmean_delta, time_agg_threshold),
|
|
fmt_delta(mem_gmean_delta, mem_agg_threshold),
|
|
)
|
|
exit(threshold_single or threshold_agg)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|