Skip to content

Commit a7a2dbe

Browse files
committed
Add maintainance script to automate test rebaselining. NFC
This is just the first iteration. See emscripten-core#23146 for more plans.
1 parent 3ffc9a0 commit a7a2dbe

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

tools/maint/rebaseline_tests.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2024 The Emscripten Authors. All rights reserved.
3+
# Emscripten is available under two separate licenses, the MIT license and the
4+
# University of Illinois/NCSA Open Source License. Both these licenses can be
5+
# found in the LICENSE file.
6+
7+
"""Automatically rebaseline tests that have codesize expectations and create
8+
a git commit containing the resulting changes along with readable details of
9+
the generated changes.
10+
"""
11+
12+
import argparse
13+
import json
14+
import os
15+
import subprocess
16+
import statistics
17+
import sys
18+
19+
script_dir = os.path.dirname(os.path.abspath(__file__))
20+
root_dir = os.path.dirname(os.path.dirname(script_dir))
21+
22+
sys.path.insert(0, root_dir)
23+
from tools import utils
24+
25+
TESTS = [
26+
'browser.test_small_js_flags',
27+
'other.test_INCOMING_MODULE_JS_API',
28+
'other.*code_size*',
29+
'other.*codesize*'
30+
]
31+
32+
33+
def run(cmd, **args):
34+
return subprocess.check_output(cmd, text=True, cwd=root_dir, **args)
35+
36+
37+
all_deltas = []
38+
39+
40+
def process_changed_file(filename):
41+
content = open(filename).read()
42+
old_content = run(['git', 'show', f'HEAD:{filename}'])
43+
print(f'processing {filename}')
44+
if len(content.splitlines()) == 1:
45+
size = int(content.strip())
46+
old_size = int(old_content.strip())
47+
else:
48+
try:
49+
current_json = json.loads(content)
50+
old_json = json.loads(old_content)
51+
except Exception:
52+
print(f'{filename}: Unable to parse json content. Unsupported file format?')
53+
sys.exit(1)
54+
size = current_json['total']
55+
old_size = old_json['total']
56+
57+
filename = utils.removeprefix(filename, 'test/')
58+
delta = size - old_size
59+
percent_delta = delta * 100 / old_size
60+
all_deltas.append(percent_delta)
61+
return f'{filename}: {old_size} => {size} [{delta:+} bytes / {percent_delta:+.2f}%]\n'
62+
63+
64+
def main(argv):
65+
parser = argparse.ArgumentParser()
66+
parser.add_argument('-s', '--skip-tests', action='store_true', help="don't actually run the tests, just analyze the existing results")
67+
args = parser.parse_args()
68+
69+
if not args.skip_tests:
70+
if run(['git', 'status', '-uno', '--porcelain']).strip():
71+
print('tree is not clean')
72+
return 1
73+
74+
subprocess.check_call(['test/runner', '--rebaseline', '--browser=0'] + TESTS, cwd=root_dir)
75+
76+
if not run(['git', 'status', '-uno', '--porcelain']):
77+
print('no updates found')
78+
return 1
79+
80+
output = run(['git', 'status', '-uno', '--porcelain'])
81+
filenames = []
82+
for line in output.splitlines():
83+
status, filename = line.strip().split(' ', 1)
84+
filenames.append(filename)
85+
86+
87+
commit_message = f'''
88+
Automatic rebaseline of codesize expectations. NFC
89+
90+
This is an automatic change generated by tools/maint/rebaseline_tests.py.
91+
92+
The following ({len(filenames)}) test expectation files were updated by
93+
running the tests with `--rebaseline`:
94+
95+
'''
96+
97+
for file in filenames:
98+
commit_message += process_changed_file(file)
99+
100+
commit_message += f'\nAverage change: {statistics.mean(all_deltas):+.2f}% ({min(all_deltas):+.2f}% - {max(all_deltas):+.2f}%)\n'
101+
102+
run(['git', 'checkout', '-b', 'rebaseline_tests'])
103+
run(['git', 'add', '-u', '.'])
104+
run(['git', 'commit', '-F', '-'], input=commit_message)
105+
106+
print(commit_message)
107+
return 0
108+
109+
110+
if __name__ == '__main__':
111+
sys.exit(main(sys.argv))

0 commit comments

Comments
 (0)