Skip to content

Commit 72f49ad

Browse files
authored
Paramaterize minimal runtime codesize test. NFC. (#12792)
This has several advantages: 1. Its easy to re-run just one of them when debugging. 2. Running all of them is way faster because the run in parallel 3. When they fail the name of the failing test gives more information
1 parent 528a6ab commit 72f49ad

File tree

1 file changed

+108
-105
lines changed

1 file changed

+108
-105
lines changed

tests/test_other.py

Lines changed: 108 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -8186,7 +8186,17 @@ def test(args, closure, opt):
81868186
# The no_windows/no_mac decorators also solve that problem.
81878187
@no_windows("Code size is slightly different on Windows")
81888188
@no_mac("Code size is slightly different on Mac")
8189-
def test_minimal_runtime_code_size(self):
8189+
@parameterized({
8190+
'hello_world_wasm': ('hello_world', False),
8191+
'hello_world_wasm2js': ('hello_world', True),
8192+
'random_printf_wasm': ('random_printf', False),
8193+
'random_printf_wasm2js': ('random_printf', True),
8194+
'hello_webgl_wasm': ('hello_webgl', False),
8195+
'hello_webgl_wasm2js': ('hello_webgl', True),
8196+
'hello_webgl2_wasm': ('hello_webgl2', False),
8197+
'hello_webgl2_wasm2js': ('hello_webgl2', True),
8198+
})
8199+
def test_minimal_runtime_code_size(self, test_name, js):
81908200
smallest_code_size_args = ['-s', 'MINIMAL_RUNTIME=2',
81918201
'-s', 'ENVIRONMENT=web',
81928202
'-s', 'TEXTDECODER=2',
@@ -8227,125 +8237,118 @@ def test_minimal_runtime_code_size(self):
82278237
'-s', 'MODULARIZE=1']
82288238
hello_webgl2_sources = hello_webgl_sources + ['-s', 'MAX_WEBGL_VERSION=2']
82298239

8240+
sources = {
8241+
'hello_world': hello_world_sources,
8242+
'random_printf': random_printf_sources,
8243+
'hello_webgl': hello_webgl_sources,
8244+
'hello_webgl2': hello_webgl2_sources}[test_name]
8245+
82308246
def print_percent(actual, expected):
82318247
if actual == expected:
82328248
return ''
82338249
return ' ({:+.2f}%)'.format((actual - expected) * 100.0 / expected)
82348250

8235-
for js in [False, True]:
8236-
for sources, name in [
8237-
[hello_world_sources, 'hello_world'],
8238-
[random_printf_sources, 'random_printf'],
8239-
[hello_webgl_sources, 'hello_webgl'],
8240-
[hello_webgl2_sources, 'hello_webgl2']
8241-
]:
8251+
outputs = ['a.html', 'a.js']
82428252

8243-
outputs = ['a.html', 'a.js']
8253+
args = smallest_code_size_args[:]
82448254

8245-
test_name = name
8255+
if js:
8256+
outputs += ['a.mem']
8257+
args += wasm2js
8258+
test_name += '_wasm2js'
8259+
else:
8260+
outputs += ['a.wasm']
8261+
test_name += '_wasm'
82468262

8247-
args = smallest_code_size_args[:]
8263+
if 'SINGLE_FILE=1' in sources:
8264+
outputs = ['a.html']
82488265

8266+
results_file = path_from_root('tests', 'code_size', test_name + '.json')
8267+
8268+
expected_results = {}
8269+
try:
8270+
expected_results = json.loads(open(results_file, 'r').read())
8271+
except Exception:
8272+
if not os.environ.get('EMTEST_REBASELINE'):
8273+
raise
8274+
8275+
args = [EMCC, '-o', 'a.html'] + args + sources
8276+
print(shared.shlex_join(args))
8277+
self.run_process(args)
8278+
8279+
def get_file_gzipped_size(f):
8280+
f_gz = f + '.gz'
8281+
with gzip.open(f_gz, 'wb') as gzf:
8282+
gzf.write(open(f, 'rb').read())
8283+
size = os.path.getsize(f_gz)
8284+
try_delete(f_gz)
8285+
return size
8286+
8287+
obtained_results = {}
8288+
total_output_size = 0
8289+
total_expected_size = 0
8290+
total_output_size_gz = 0
8291+
total_expected_size_gz = 0
8292+
for f in outputs:
8293+
f_gz = f + '.gz'
8294+
expected_size = expected_results[f] if f in expected_results else float('inf')
8295+
expected_size_gz = expected_results[f_gz] if f_gz in expected_results else float('inf')
8296+
size = os.path.getsize(f)
8297+
size_gz = get_file_gzipped_size(f)
8298+
8299+
obtained_results[f] = size
8300+
obtained_results[f_gz] = size_gz
8301+
8302+
if size != expected_size and (f.endswith('.js') or f.endswith('.html')):
8303+
print('Contents of ' + f + ': ')
8304+
print(open(f, 'r').read())
8305+
8306+
print('size of ' + f + ' == ' + str(size) + ', expected ' + str(expected_size) + ', delta=' + str(size - expected_size) + print_percent(size, expected_size))
8307+
print('size of ' + f_gz + ' == ' + str(size_gz) + ', expected ' + str(expected_size_gz) + ', delta=' + str(size_gz - expected_size_gz) + print_percent(size_gz, expected_size_gz))
8308+
8309+
# Hack: Generated .mem initializer files have different sizes on different
8310+
# platforms (Windows gives x, CircleCI Linux gives x-17 bytes, my home
8311+
# Linux gives x+2 bytes..). Likewise asm.js files seem to be affected by
8312+
# the LLVM IR text names, which lead to asm.js names, which leads to
8313+
# difference code size, which leads to different relooper choices,
8314+
# as a result leading to slightly different total code sizes.
8315+
# Also as of July 16, 2020, wasm2js files have different sizes on
8316+
# different platforms (Windows and MacOS improved to give a slightly
8317+
# better thing than Linux does, which didn't change; this just
8318+
# started to happen on CI, not in response to a code update, so it
8319+
# may have been present all along but just noticed now; it only
8320+
# happens in wasm2js, so it may be platform-nondeterminism in closure
8321+
# compiler).
8322+
# TODO: identify what is causing this. meanwhile allow some amount of slop
8323+
if not os.environ.get('EMTEST_REBASELINE'):
82498324
if js:
8250-
outputs += ['a.mem']
8251-
args += wasm2js
8252-
test_name += '_wasm2js'
8325+
slop = 30
82538326
else:
8254-
outputs += ['a.wasm']
8255-
test_name += '_wasm'
8256-
8257-
if 'SINGLE_FILE=1' in sources:
8258-
outputs = ['a.html']
8327+
slop = 20
8328+
if size <= expected_size + slop and size >= expected_size - slop:
8329+
size = expected_size
82598330

8260-
results_file = path_from_root('tests', 'code_size', test_name + '.json')
8331+
# N.B. even though the test code above prints out gzip compressed sizes, regression testing is done against uncompressed sizes
8332+
# this is because optimizing for compressed sizes can be unpredictable and sometimes counterproductive
8333+
total_output_size += size
8334+
total_expected_size += expected_size
82618335

8262-
print('\n-----------------------------\n' + test_name)
8336+
total_output_size_gz += size_gz
8337+
total_expected_size_gz += expected_size_gz
82638338

8264-
expected_results = {}
8265-
try:
8266-
expected_results = json.loads(open(results_file, 'r').read())
8267-
except Exception:
8268-
if not os.environ.get('EMTEST_REBASELINE'):
8269-
raise
8339+
obtained_results['total'] = total_output_size
8340+
obtained_results['total_gz'] = total_output_size_gz
8341+
print('Total output size=' + str(total_output_size) + ' bytes, expected total size=' + str(total_expected_size) + ', delta=' + str(total_output_size - total_expected_size) + print_percent(total_output_size, total_expected_size))
8342+
print('Total output size gzipped=' + str(total_output_size_gz) + ' bytes, expected total size gzipped=' + str(total_expected_size_gz) + ', delta=' + str(total_output_size_gz - total_expected_size_gz) + print_percent(total_output_size_gz, total_expected_size_gz))
82708343

8271-
args = [EMCC, '-o', 'a.html'] + args + sources
8272-
print('\n' + ' '.join(args))
8273-
self.run_process(args)
8274-
print('\n')
8275-
8276-
def get_file_gzipped_size(f):
8277-
f_gz = f + '.gz'
8278-
with gzip.open(f_gz, 'wb') as gzf:
8279-
gzf.write(open(f, 'rb').read())
8280-
size = os.path.getsize(f_gz)
8281-
try_delete(f_gz)
8282-
return size
8283-
8284-
obtained_results = {}
8285-
total_output_size = 0
8286-
total_expected_size = 0
8287-
total_output_size_gz = 0
8288-
total_expected_size_gz = 0
8289-
for f in outputs:
8290-
f_gz = f + '.gz'
8291-
expected_size = expected_results[f] if f in expected_results else float('inf')
8292-
expected_size_gz = expected_results[f_gz] if f_gz in expected_results else float('inf')
8293-
size = os.path.getsize(f)
8294-
size_gz = get_file_gzipped_size(f)
8295-
8296-
obtained_results[f] = size
8297-
obtained_results[f_gz] = size_gz
8298-
8299-
if size != expected_size and (f.endswith('.js') or f.endswith('.html')):
8300-
print('Contents of ' + f + ': ')
8301-
print(open(f, 'r').read())
8302-
8303-
print('size of ' + f + ' == ' + str(size) + ', expected ' + str(expected_size) + ', delta=' + str(size - expected_size) + print_percent(size, expected_size))
8304-
print('size of ' + f_gz + ' == ' + str(size_gz) + ', expected ' + str(expected_size_gz) + ', delta=' + str(size_gz - expected_size_gz) + print_percent(size_gz, expected_size_gz))
8305-
8306-
# Hack: Generated .mem initializer files have different sizes on different
8307-
# platforms (Windows gives x, CircleCI Linux gives x-17 bytes, my home
8308-
# Linux gives x+2 bytes..). Likewise asm.js files seem to be affected by
8309-
# the LLVM IR text names, which lead to asm.js names, which leads to
8310-
# difference code size, which leads to different relooper choices,
8311-
# as a result leading to slightly different total code sizes.
8312-
# Also as of July 16, 2020, wasm2js files have different sizes on
8313-
# different platforms (Windows and MacOS improved to give a slightly
8314-
# better thing than Linux does, which didn't change; this just
8315-
# started to happen on CI, not in response to a code update, so it
8316-
# may have been present all along but just noticed now; it only
8317-
# happens in wasm2js, so it may be platform-nondeterminism in closure
8318-
# compiler).
8319-
# TODO: identify what is causing this. meanwhile allow some amount of slop
8320-
if not os.environ.get('EMTEST_REBASELINE'):
8321-
if js:
8322-
slop = 30
8323-
else:
8324-
slop = 20
8325-
if size <= expected_size + slop and size >= expected_size - slop:
8326-
size = expected_size
8327-
8328-
# N.B. even though the test code above prints out gzip compressed sizes, regression testing is done against uncompressed sizes
8329-
# this is because optimizing for compressed sizes can be unpredictable and sometimes counterproductive
8330-
total_output_size += size
8331-
total_expected_size += expected_size
8332-
8333-
total_output_size_gz += size_gz
8334-
total_expected_size_gz += expected_size_gz
8335-
8336-
obtained_results['total'] = total_output_size
8337-
obtained_results['total_gz'] = total_output_size_gz
8338-
print('Total output size=' + str(total_output_size) + ' bytes, expected total size=' + str(total_expected_size) + ', delta=' + str(total_output_size - total_expected_size) + print_percent(total_output_size, total_expected_size))
8339-
print('Total output size gzipped=' + str(total_output_size_gz) + ' bytes, expected total size gzipped=' + str(total_expected_size_gz) + ', delta=' + str(total_output_size_gz - total_expected_size_gz) + print_percent(total_output_size_gz, total_expected_size_gz))
8340-
8341-
if os.environ.get('EMTEST_REBASELINE'):
8342-
open(results_file, 'w').write(json.dumps(obtained_results, indent=2) + '\n')
8343-
else:
8344-
if total_output_size > total_expected_size:
8345-
print('Oops, overall generated code size regressed by ' + str(total_output_size - total_expected_size) + ' bytes!')
8346-
if total_output_size < total_expected_size:
8347-
print('Hey amazing, overall generated code size was improved by ' + str(total_expected_size - total_output_size) + ' bytes! Rerun test with other.test_minimal_runtime_code_size with EMTEST_REBASELINE=1 to update the expected sizes!')
8348-
self.assertEqual(total_output_size, total_expected_size)
8344+
if os.environ.get('EMTEST_REBASELINE'):
8345+
open(results_file, 'w').write(json.dumps(obtained_results, indent=2) + '\n')
8346+
else:
8347+
if total_output_size > total_expected_size:
8348+
print('Oops, overall generated code size regressed by ' + str(total_output_size - total_expected_size) + ' bytes!')
8349+
if total_output_size < total_expected_size:
8350+
print('Hey amazing, overall generated code size was improved by ' + str(total_expected_size - total_output_size) + ' bytes! Rerun test with other.test_minimal_runtime_code_size with EMTEST_REBASELINE=1 to update the expected sizes!')
8351+
self.assertEqual(total_output_size, total_expected_size)
83498352

83508353
# Test that legacy settings that have been fixed to a specific value and their value can no longer be changed,
83518354
def test_legacy_settings_forbidden_to_change(self):

0 commit comments

Comments
 (0)