diff options
author | Ehsan Akhgari <ehsan.akhgari@gmail.com> | 2012-01-27 15:02:10 -0500 |
---|---|---|
committer | Ehsan Akhgari <ehsan.akhgari@gmail.com> | 2012-01-27 15:02:10 -0500 |
commit | 65febb8bf9e70ebacc252f75374c5c291befa6de (patch) | |
tree | 12f601f70cef7844d3212b10b9505953e8d62120 /tests/runner.py | |
parent | 58d80ab53ea7c71b6e7dd0e56bee1335514a59f6 (diff) | |
parent | fff86540c3c5147e745a038bffad034ea1058d22 (diff) |
Merge branch 'handle_broken_lli' into glgears
Conflicts:
src/preamble.js
Diffstat (limited to 'tests/runner.py')
-rwxr-xr-x | tests/runner.py | 306 |
1 files changed, 200 insertions, 106 deletions
diff --git a/tests/runner.py b/tests/runner.py index b214c202..a824d089 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -14,7 +14,7 @@ will use 4 processes. To install nose do something like ''' from subprocess import Popen, PIPE, STDOUT -import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib, webbrowser +import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib, webbrowser, hashlib # Setup @@ -126,12 +126,18 @@ process(sys.argv[1]) # Build JavaScript code from source code def build(self, src, dirname, filename, output_processor=None, main_file=None, additional_files=[], libraries=[], includes=[], build_ll_hook=None, extra_emscripten_args=[], post_build=None): + Building.pick_llvm_opts(3, safe=Building.LLVM_OPTS != 2) # pick llvm opts here, so we include changes to Settings in the test case code + # Copy over necessary files for compiling the source if main_file is None: f = open(filename, 'w') f.write(src) f.close() - assert len(additional_files) == 0 + final_additional_files = [] + for f in additional_files: + final_additional_files.append(os.path.join(dirname, os.path.basename(f))) + shutil.copyfile(f, final_additional_files[-1]) + additional_files = final_additional_files else: # copy whole directory, and use a specific main .cpp file shutil.rmtree(dirname) @@ -139,10 +145,9 @@ process(sys.argv[1]) shutil.move(os.path.join(dirname, main_file), filename) # the additional files were copied; alter additional_files to point to their full paths now additional_files = map(lambda f: os.path.join(dirname, f), additional_files) + os.chdir(self.get_dir()) # C++ => LLVM binary - os.chdir(dirname) - cwd = os.getcwd() for f in [filename] + additional_files: try: @@ -157,8 +162,6 @@ process(sys.argv[1]) output = Popen(args, stdout=PIPE, stderr=self.stderr_redirect).communicate()[0] assert os.path.exists(f + '.o'), 'Source compilation error: ' + output - os.chdir(cwd) - # Link all files if len(additional_files) + len(libraries) > 0: shutil.move(filename + '.o', filename + '.o.alone') @@ -192,9 +195,6 @@ process(sys.argv[1]) assert 'strict warning:' not in ret, 'We should pass all strict mode checks: ' + ret return ret - def run_llvm_interpreter(self, args): - return Popen([EXEC_LLVM] + args, stdout=PIPE, stderr=self.stderr_redirect).communicate()[0] - def build_native(self, filename): Popen([CLANG, '-O2', filename, '-o', filename+'.native'], stdout=PIPE).communicate()[0] @@ -254,6 +254,8 @@ process(sys.argv[1]) sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv) +Cache.erase() # Wipe the cache, so that we always test populating it in the tests, benchmarks, etc. + if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): # Tests @@ -261,7 +263,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): class T(RunnerCore): # Short name, to make it more fun to use manually on the commandline ## Does a complete test - builds, runs, checks output, etc. - def do_run(self, src, expected_output=None, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]): + def do_run(self, src, expected_output, args=[], output_nicerizer=None, output_processor=None, no_build=False, main_file=None, additional_files=[], js_engines=None, post_build=None, basename='src.cpp', libraries=[], includes=[], force_c=False, build_ll_hook=None, extra_emscripten_args=[]): if force_c or (main_file is not None and main_file[-2:]) == '.c': basename = 'src.c' Building.COMPILER = to_cc(Building.COMPILER) @@ -272,11 +274,6 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): self.build(src, dirname, filename, main_file=main_file, additional_files=additional_files, libraries=libraries, includes=includes, build_ll_hook=build_ll_hook, extra_emscripten_args=extra_emscripten_args, post_build=post_build) - # If not provided with expected output, then generate it right now, using lli - if expected_output is None: - expected_output = self.run_llvm_interpreter([filename + '.o']) - print '[autogenerated expected output: %20s]' % (expected_output[0:30].replace('\n', '|')+'...') - # Run in both JavaScript engines, if optimizing - significant differences there (typed arrays) if js_engines is None: js_engines = JS_ENGINES @@ -651,7 +648,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): return 0; } ''' - self.do_run(src)#, '*4294967295,0,4294967219*\n*-1,1,-1,1*\n*-2,1,-2,1*\n*246,296*\n*1,0*') + self.do_run(src, '*4294967295,0,4294967219*\n*-1,1,-1,1*\n*-2,1,-2,1*\n*246,296*\n*1,0*') # Now let's see some code that should just work in USE_TYPED_ARRAYS == 2, but requires # corrections otherwise @@ -865,7 +862,7 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): } ''' - self.do_run(src) + self.do_run(src, '*1800*') generated = open('src.cpp.o.js', 'r').read() assert '__label__ ==' not in generated, 'We should hoist into the loop' @@ -1174,8 +1171,13 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): self.do_run(src, 'Assertion failed: 1 == false') def test_exceptions(self): + if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") + self.banned_js_engines = [NODE_JS] # node issue 1669, exception causes stdout not to be flushed Settings.DISABLE_EXCEPTION_CATCHING = 0 + if self.emcc_args is None: + if Building.LLVM_OPTS: return self.skip('optimizing bitcode before emcc can confuse libcxx inclusion') + self.emcc_args = [] # libc++ auto-inclusion is only done if we use emcc src = ''' #include <stdio.h> @@ -2354,7 +2356,10 @@ def process(filename): return 0; } ''' - self.do_run(src) + def check(result): + return hashlib.sha1(result).hexdigest() + self.do_run(src, '6c9cdfe937383b79e52ca7a2cce83a21d9f5422c', + output_nicerizer = check) def test_memmove(self): src = ''' @@ -2367,7 +2372,7 @@ def process(filename): return 0; } ''' - self.do_run(src) + self.do_run(src, 'memmove can be very very useful') def test_bsearch(self): if Settings.QUANTUM_SIZE == 1: return self.skip('Test cannot work with q1') @@ -2502,6 +2507,9 @@ def process(filename): def test_runtimelink(self): if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize printf into puts in the parent, and the child will still look for puts') + + Settings.LINKABLE = 1 + self.banned_js_engines = [NODE_JS] # node's global scope behaves differently than everything else, needs investigation FIXME header = r''' @@ -2562,6 +2570,8 @@ def process(filename): self.do_run(main, 'supp: 54,2\nmain: 56\nsupp see: 543\nmain see: 76\nok.') def test_dlfcn_basic(self): + Settings.LINKABLE = 1 + lib_src = ''' #include <cstdio> @@ -2611,6 +2621,8 @@ def process(filename): post_build=add_pre_run_and_checks) def test_dlfcn_qsort(self): + Settings.LINKABLE = 1 + if Settings.USE_TYPED_ARRAYS == 2: Settings.CORRECT_SIGNS = 1 # Needed for unsafe optimizations @@ -2703,6 +2715,8 @@ def process(filename): def test_dlfcn_data_and_fptr(self): if Building.LLVM_OPTS: return self.skip('LLVM opts will optimize out parent_func') + Settings.LINKABLE = 1 + lib_src = ''' #include <stdio.h> @@ -2801,6 +2815,8 @@ def process(filename): post_build=add_pre_run_and_checks) def test_dlfcn_alias(self): + Settings.LINKABLE = 1 + if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize away stuff we expect from the shared library') lib_src = r''' @@ -2853,6 +2869,8 @@ def process(filename): Settings.INCLUDE_FULL_LIBRARY = 0 def test_dlfcn_varargs(self): + Settings.LINKABLE = 1 + if Building.LLVM_OPTS == 2: return self.skip('LLVM LTO will optimize things that prevent shared objects from working') if Settings.QUANTUM_SIZE == 1: return self.skip('FIXME: Add support for this') @@ -3130,21 +3148,21 @@ at function.:blag #include <stdlib.h> int main () { - printf("%d\n", atoi("")); - printf("%d\n", atoi("a")); - printf("%d\n", atoi(" b")); - printf("%d\n", atoi(" c ")); - printf("%d\n", atoi("6")); - printf("%d\n", atoi(" 5")); - printf("%d\n", atoi("4 ")); - printf("%d\n", atoi("3 6")); - printf("%d\n", atoi(" 3 7")); - printf("%d\n", atoi("9 d")); + printf("%d*", atoi("")); + printf("%d*", atoi("a")); + printf("%d*", atoi(" b")); + printf("%d*", atoi(" c ")); + printf("%d*", atoi("6")); + printf("%d*", atoi(" 5")); + printf("%d*", atoi("4 ")); + printf("%d*", atoi("3 6")); + printf("%d*", atoi(" 3 7")); + printf("%d*", atoi("9 d")); printf("%d\n", atoi(" 8 e")); return 0; } ''' - self.do_run(src) + self.do_run(src, '0*0*0*0*6*5*4*3*3*9*8') def test_sscanf(self): src = r''' @@ -3170,7 +3188,8 @@ at function.:blag return 0; } ''' - self.do_run(src) + self.do_run(src, 'en-us : 2*en-r : 99*en : 3*1.234567, 0.000000', + output_nicerizer = lambda x: x.replace('\n', '*')) # Part 2: doubles (issue 148) if Settings.USE_TYPED_ARRAYS == 2: @@ -3221,7 +3240,11 @@ Pass: 123456.789063 123456.789063 Pass: 0.000012 0.000012 Pass: 0.000012 0.000012''') else: - self.do_run(src) + self.do_run(src, '''Pass: 1.234568 1.234568 +Pass: 123456.789000 123456.789000 +Pass: 123456.789000 123456.789000 +Pass: 0.000012 0.000012 +Pass: 0.000012 0.000012''') def test_langinfo(self): src = open(path_from_root('tests', 'langinfo', 'test.c'), 'r').read() @@ -3834,9 +3857,40 @@ def process(filename): self.do_run(src, expected) CORRECT_SIGNS = 0 + def test_atomic(self): + src = ''' + #include <stdio.h> + int main() { + int x = 10; + int y = __sync_add_and_fetch(&x, 5); + printf("*%d,%d*\\n", x, y); + x = 10; + y = __sync_fetch_and_add(&x, 5); + printf("*%d,%d*\\n", x, y); + x = 10; + y = __sync_lock_test_and_set(&x, 6); + printf("*%d,%d*\\n", x, y); + x = 10; + y = __sync_bool_compare_and_swap(&x, 9, 7); + printf("*%d,%d*\\n", x, y); + y = __sync_bool_compare_and_swap(&x, 10, 7); + printf("*%d,%d*\\n", x, y); + return 0; + } + ''' + + self.do_run(src, '*15,15*\n*15,10*\n*6,10*\n*10,0*\n*7,1*') + # libc++ tests def test_iostream(self): + if Settings.QUANTUM_SIZE == 1: return self.skip("we don't support libcxx in q1") + + if self.emcc_args is None: + if Building.LLVM_OPTS: return self.skip('optimizing bitcode before emcc can confuse libcxx inclusion') + self.emcc_args = [] # libc++ auto-inclusion is only done if we use emcc + Settings.SAFE_HEAP = 0 # Some spurious warnings from libc++ internals + src = ''' #include <iostream> @@ -3847,7 +3901,8 @@ def process(filename): } ''' - self.do_run(src, 'hello world\n77.\n') + # FIXME: should not have so many newlines in output here + self.do_run(src, 'hello world\n\n77.\n') def test_stdvec(self): src = ''' @@ -3907,11 +3962,13 @@ def process(filename): self.do_run(src, j, [str(i)], lambda x: x.replace('\n', '*'), no_build=i>1) def test_dlmalloc(self): + if self.emcc_args is None: self.emcc_args = [] # dlmalloc auto-inclusion is only done if we use emcc + Settings.CORRECT_SIGNS = 2 Settings.CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]] Settings.TOTAL_MEMORY = 100*1024*1024 # needed with typed arrays - src = open(path_from_root('src', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read() + src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read() self.do_run(src, '*1,0*', ['200', '1']) self.do_run(src, '*400,0*', ['400', '400'], no_build=True) @@ -3942,13 +3999,9 @@ def process(filename): self.do_run(src.replace('{{{ NEW }}}', new).replace('{{{ DELETE }}}', delete), '*1,0*') def test_libcxx(self): - self.do_run(path_from_root('tests', 'libcxx'), - 'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march', - main_file='main.cpp', additional_files=['hash.cpp']) + self.do_run(open(path_from_root('tests', 'hashtest.cpp')).read(), + 'june -> 30\nPrevious (in alphabetical order) is july\nNext (in alphabetical order) is march') - # This will fail without using libcxx, as libstdc++ (gnu c++ lib) will use but not link in - # __ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_ - # So a way to avoid that problem is to include libcxx, as done here self.do_run(''' #include <set> #include <stdio.h> @@ -3958,7 +4011,7 @@ def process(filename): printf("hello world\\n"); return 1; } - ''', 'hello world', includes=[path_from_root('tests', 'libcxx', 'include')]); + ''', 'hello world'); def test_static_variable(self): Settings.SAFE_HEAP = 0 # LLVM mixes i64 and i8 in the guard check @@ -4079,7 +4132,7 @@ def process(filename): def get_freetype(self): Settings.INIT_STACK = 1 # TODO: Investigate why this is necessary - return self.get_library('freetype', os.path.join('objs', '.libs', 'libfreetype.a.bc')) + return self.get_library('freetype', os.path.join('objs', '.libs', 'libfreetype.a')) def test_freetype(self): if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix') @@ -4109,6 +4162,7 @@ def process(filename): def test_sqlite(self): # gcc -O3 -I/home/alon/Dev/emscripten/tests/sqlite -ldl src.c + if self.emcc_args is None: return self.skip('Very slow without ta2, and we would also need to include dlmalloc manually without emcc') if Settings.QUANTUM_SIZE == 1: return self.skip('TODO FIXME') pgo_data = read_pgo_data(path_from_root('tests', 'sqlite', 'sqlite-autooptimize.fails.txt')) @@ -4146,7 +4200,6 @@ def process(filename): open(path_from_root('tests', 'sqlite', 'benchmark.txt'), 'r').read(), includes=[path_from_root('tests', 'sqlite')], force_c=True, - extra_emscripten_args=['-m'], js_engines=[SPIDERMONKEY_ENGINE], # V8 is slow post_build=post)#,build_ll_hook=self.do_autodebug) @@ -4158,7 +4211,7 @@ def process(filename): self.do_run(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(), open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(), - libraries=[self.get_library('zlib', os.path.join('libz.a.bc'), make_args=['libz.a'])], + libraries=[self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a'])], includes=[path_from_root('tests', 'zlib')], force_c=True) @@ -4175,9 +4228,9 @@ def process(filename): self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(), [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read()], - libraries=[self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletCollision.a.bc'), - os.path.join('src', '.libs', 'libBulletDynamics.a.bc'), - os.path.join('src', '.libs', 'libLinearMath.a.bc')], + libraries=[self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletCollision.a'), + os.path.join('src', '.libs', 'libBulletDynamics.a'), + os.path.join('src', '.libs', 'libLinearMath.a')], configure_args=['--disable-demos','--disable-dependency-tracking'])], includes=[path_from_root('tests', 'bullet', 'src')], js_engines=[SPIDERMONKEY_ENGINE]) # V8 issue 1407 @@ -4223,9 +4276,9 @@ def process(filename): poppler = self.get_library('poppler', [os.path.join('poppler', '.libs', 'libpoppler.so.13.0.0'), - os.path.join('goo', '.libs', 'libgoo.a.bc'), - os.path.join('fofi', '.libs', 'libfofi.a.bc'), - os.path.join('splash', '.libs', 'libsplash.a.bc'), + os.path.join('goo', '.libs', 'libgoo.a'), + os.path.join('fofi', '.libs', 'libfofi.a'), + os.path.join('splash', '.libs', 'libsplash.a'), os.path.join('utils', 'pdftoppm.o'), os.path.join('utils', 'parseargs.o')], configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms']) @@ -4336,8 +4389,7 @@ def process(filename): self.do_ll_run(path_from_root('tests', 'python', 'python.ll'), 'hello python world!\n[0, 2, 4, 6]\n5\n22\n5.470000', - args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47'''], - extra_emscripten_args=['-m']) + args=['-S', '-c' '''print "hello python world!"; print [x*2 for x in range(4)]; t=2; print 10-3-t; print (lambda x: x*2)(11); print '%f' % 5.47''']) # Test cases in separate files. Note that these files may contain invalid .ll! # They are only valid enough for us to read for test purposes, not for llvm-as @@ -4405,7 +4457,28 @@ def process(filename): self.do_autodebug(filename) # Compare to each other, and to expected output - self.do_ll_run(path_from_root('tests', filename+'.o.ll.ll')) + self.do_ll_run(path_from_root('tests', filename+'.o.ll.ll'), '''AD:-1,15 +AD:15,0 +AD:21,5 +AD:24,6 +AD:27,101 +AD:30,7009 +AD:37,5 +AD:40,10 +AD:45,7009 +AD:48,7008 +AD:54,7008 +AD:57,7018 +AD:60,10 +AD:63,6 +AD:66,101 +AD:69,7018 +AD:73,101 +AD:77,7018 +AD:81,101 +AD:85,7018 +*10,6,101,7018,101,7018,101,7018*''') + assert open('stdout').read().startswith('AD:-1'), 'We must note when we enter functions' # Test using build_ll_hook src = ''' @@ -4423,30 +4496,17 @@ def process(filename): return 0; } ''' - self.do_run(src, build_ll_hook=self.do_autodebug) - self.do_run(src, 'AD:', build_ll_hook=self.do_autodebug) - - def test_dfe(self): - def hook(filename): - ll = open(filename + '.o.ll').read() - assert 'unneeded' not in ll, 'DFE should remove the unneeded function' - - src = ''' - #include <stdio.h> - - void unneeded() - { - printf("some totally useless stuff\\n"); - } - - int main() - { - printf("*hello slim world*\\n"); - return 0; - } - ''' - # Using build_ll_hook forces a recompile, which leads to DFE being done even without opts - self.do_run(src, '*hello slim world*', build_ll_hook=hook) + self.do_run(src, '''AD:-1,13 +AD:13,0 +AD:16,25 +AD:20,51 +AD:23,25 +AD:26,25 +AD:29,11.520000 +AD:31,25 +AD:33,51 +AD:36,11.520000 +*25,51,11.52*''', build_ll_hook=self.do_autodebug) def test_profiling(self): src = ''' @@ -4981,26 +5041,6 @@ def process(filename): # This test *should* fail assert 'Assertion failed' in str(e), str(e) - def test_autoassemble(self): - src = r''' - #include <stdio.h> - - int main() { - puts("test\n"); - return 0; - } - ''' - dirname = self.get_dir() - filename = os.path.join(dirname, 'src.cpp') - self.build(src, dirname, filename) - - new_filename = os.path.join(dirname, 'new.bc') - shutil.copy(filename + '.o', new_filename) - Building.emscripten(new_filename, append_ext=False) - - shutil.copy(filename + '.o.js', os.path.join(self.get_dir(), 'new.cpp.o.js')) - self.do_run(None, 'test\n', basename='new.cpp', no_build=True) - def test_linespecific(self): Settings.CHECK_SIGNS = 0 Settings.CHECK_OVERFLOWS = 0 @@ -5361,10 +5401,16 @@ Options that are modified or new in %s include: for args in [['-c'], ['-o', 'src.o'], ['-o', 'src.bc'], ['-o', 'js']]: target = args[1] if len(args) == 2 else 'hello_world.o' clear() - output = Popen([compiler, path_from_root('tests', 'hello_world' + suffix)] + args, stdout=PIPE, stderr=PIPE).communicate() + Popen([compiler, path_from_root('tests', 'hello_world' + suffix)] + args, stdout=PIPE, stderr=PIPE).communicate() + syms = Building.llvm_nm(target) + assert len(syms.defs) == 1 and 'main' in syms.defs, 'Failed to generate valid bitcode' + if target == 'js': # make sure emcc can recognize the target as a bitcode file + shutil.move(target, target + '.bc') + target += '.bc' + output = Popen([compiler, target, '-o', target + '.js'], stdout = PIPE, stderr = PIPE).communicate() assert len(output[0]) == 0, output[0] - assert os.path.exists(target), 'Expected %s to exist since args are %s : %s' % (target, str(args), '\n'.join(output)) - self.assertContained('hello, world!', self.run_llvm_interpreter([target])) + assert os.path.exists(target + '.js'), 'Expected %s to exist since args are %s : %s' % (target + '.js', str(args), '\n'.join(output)) + self.assertContained('hello, world!', run_js(target + '.js')) # emcc src.ll ==> generates .js clear() @@ -5509,8 +5555,12 @@ Options that are modified or new in %s include: try_delete(target) assert not os.path.exists(target) output = Popen([compiler, 'twopart_main.o', 'twopart_side.o', '-o', 'combined.bc'] + args, stdout=PIPE, stderr=PIPE).communicate() - assert os.path.exists('combined.bc'), '\n'.join(output) - self.assertContained('side got: hello from main, over', self.run_llvm_interpreter(['combined.bc'])) + syms = Building.llvm_nm('combined.bc') + assert len(syms.defs) == 2 and 'main' in syms.defs, 'Failed to generate valid bitcode' + output = Popen([compiler, 'combined.bc', '-o', 'combined.bc.js'], stdout = PIPE, stderr = PIPE).communicate() + assert len(output[0]) == 0, output[0] + assert os.path.exists('combined.bc.js'), 'Expected %s to exist' % ('combined.bc.js') + self.assertContained('side got: hello from main, over', run_js('combined.bc.js')) # --js-transform <transform> clear() @@ -5859,7 +5909,7 @@ elif 'benchmark' in str(sys.argv): def test_dlmalloc(self): # XXX This seems to have regressed slightly with emcc. Are -g and the signs lines passed properly? - src = open(path_from_root('src', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read() + src = open(path_from_root('system', 'lib', 'dlmalloc.c'), 'r').read() + '\n\n\n' + open(path_from_root('tests', 'dlmalloc_test.c'), 'r').read() self.do_benchmark(src, ['400', '400'], '*400,0*', emcc_args=['-g', '-s', 'CORRECT_SIGNS=2', '-s', 'CORRECT_SIGNS_LINES=[4820, 4195, 4250, 4203, 4209, 4239, 4231]']) elif 'sanity' in str(sys.argv): @@ -5887,6 +5937,9 @@ elif 'sanity' in str(sys.argv): commands = [[EMCC], ['python', path_from_root('tests', 'runner.py'), 'blahblah']] + def mtime(filename): + return os.stat(filename).st_mtime + class sanity(RunnerCore): def setUp(self): wipe() @@ -5974,9 +6027,6 @@ elif 'sanity' in str(sys.argv): assert os.path.exists('a.out.js') def test_emcc(self): - def mtime(filename): - return os.stat(filename).st_mtime - SANITY_MESSAGE = 'Emscripten: Running sanity checks' SANITY_FAIL_MESSAGE = 'sanity check failed to run' @@ -6014,6 +6064,50 @@ elif 'sanity' in str(sys.argv): assert mtime(SANITY_FILE) >= mtime(CONFIG_FILE) self.assertNotContained(SANITY_FAIL_MESSAGE, output) + def test_emcc_caching(self): + INCLUDING_MESSAGE = 'emcc: including X' + BUILDING_MESSAGE = 'emcc: building X for cache' + + EMCC_CACHE = Cache.dirname + + restore() + + Cache.erase() + assert not os.path.exists(EMCC_CACHE) + + try: + emcc_debug = os.environ.get('EMCC_DEBUG') + os.environ['EMCC_DEBUG'] ='1' + + # Building a file that doesn't need cached stuff should not trigger cache generation + output = self.do([EMCC, path_from_root('tests', 'hello_world.cpp')]) + assert INCLUDING_MESSAGE.replace('X', 'dlmalloc') not in output + assert BUILDING_MESSAGE.replace('X', 'dlmalloc') not in output + self.assertContained('hello, world!', run_js('a.out.js')) + assert not os.path.exists(EMCC_CACHE) + try_delete('a.out.js') + + # Building a file that *does* need dlmalloc *should* trigger cache generation, but only the first time + for filename, libname in [('hello_malloc.cpp', 'dlmalloc'), ('hello_libcxx.cpp', 'libcxx')]: + for i in range(3): + try_delete(os.path.join(EMSCRIPTEN_TEMP_DIR, 'emcc-0-bc.bc')) # we might need to check this file later + output = self.do([EMCC, path_from_root('tests', filename)]) + assert INCLUDING_MESSAGE.replace('X', libname) in output + if libname == 'dlmalloc': + assert INCLUDING_MESSAGE.replace('X', 'libcxx') not in output # we don't need libcxx in this code + else: + assert INCLUDING_MESSAGE.replace('X', 'dlmalloc') in output # libcxx always forces inclusion of dlmalloc + assert (BUILDING_MESSAGE.replace('X', libname) in output) == (i == 0), 'Must only build the first time' + self.assertContained('hello, world!', run_js('a.out.js')) + assert os.path.exists(EMCC_CACHE) + assert os.path.exists(os.path.join(EMCC_CACHE, libname + '.bc')) + if libname == 'libcxx': + assert os.stat(os.path.join(EMCC_CACHE, libname + '.bc')).st_size > 4000000, 'libc++ is big' + assert os.stat(os.path.join(EMSCRIPTEN_TEMP_DIR, 'emcc-0-bc.bc')).st_size < 2000000, 'Dead code elimination must remove most of libc++' + finally: + if emcc_debug: + os.environ['EMCC_DEBUG'] = emcc_debug + else: raise Exception('Test runner is confused: ' + str(sys.argv)) |