diff options
Diffstat (limited to 'tests/runner.py')
-rw-r--r-- | tests/runner.py | 214 |
1 files changed, 145 insertions, 69 deletions
diff --git a/tests/runner.py b/tests/runner.py index 3b5b03f2..f26ac370 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -35,6 +35,7 @@ class RunnerCore(unittest.TestCase): save_JS = 0 def setUp(self): + Settings.reset() self.banned_js_engines = [] if not self.save_dir: dirname = tempfile.mkdtemp(prefix="ems_" + self.__class__.__name__ + "_", dir=TEMP_DIR) @@ -211,6 +212,8 @@ class RunnerCore(unittest.TestCase): ################################################################################################### +sys.argv = map(lambda arg: arg if not arg.startswith('test_') else 'default.' + arg, sys.argv) + if 'benchmark' not in str(sys.argv): # Tests @@ -509,6 +512,36 @@ if 'benchmark' not in str(sys.argv): def test_unaligned(self): if Settings.QUANTUM_SIZE == 1: return self.skip('No meaning to unaligned addresses in q1') + + src = r''' + #include<stdio.h> + + struct S { + double x; + int y; + }; + + int main() { + // the 64-bit value here will not always be 8-byte aligned + S s[3] = { {0x12a751f430142, 22}, {0x17a5c85bad144, 98}, {1, 1}}; + printf("*%d : %d : %d\n", sizeof(S), ((unsigned int)&s[0]) % 8 != ((unsigned int)&s[1]) % 8, + ((unsigned int)&s[1]) - ((unsigned int)&s[0])); + s[0].x++; + s[0].y++; + s[1].x++; + s[1].y++; + printf("%.1f,%d,%.1f,%d\n", s[0].x, s[0].y, s[1].x, s[1].y); + return 0; + } + ''' + + # TODO: A version of this with int64s as well + self.do_run(src, '*12 : 1 : 12\n328157500735811.0,23,416012775903557.0,99\n') + + return # TODO: continue to the next part here + + # Test for undefined behavior in C. This is not legitimate code, but does exist + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('No meaning to unaligned addresses without t2') src = r''' @@ -693,7 +726,7 @@ if 'benchmark' not in str(sys.argv): #include <cmath> int main() { - printf("*%.2f,%.2f,%f,%f", M_PI, -M_PI, 1/0.0, -1/0.0); + printf("*%.2f,%.2f,%d", M_PI, -M_PI, (1/0.0) > 1e300); // could end up as infinity, or just a very very big number printf(",%d", finite(NAN) != 0); printf(",%d", finite(INFINITY) != 0); printf(",%d", finite(-INFINITY) != 0); @@ -706,9 +739,11 @@ if 'benchmark' not in str(sys.argv): return 0; } ''' - self.do_run(src, '*3.14,-3.14,inf,-inf,0,0,0,1,0,1,1,0*') + self.do_run(src, '*3.14,-3.14,1,0,0,0,1,0,1,1,0*') def test_math_hyperbolic(self): + if Settings.DOUBLE_MODE == 1: return self.skip('store-load doubles will make NaNs into actual numbers') + src = open(path_from_root('tests', 'hyperbolic', 'src.c'), 'r').read() expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read() self.do_run(src, expected) @@ -1578,13 +1613,14 @@ if 'benchmark' not in str(sys.argv): def test_emscripten_api(self): #if Settings.MICRO_OPTS or Settings.RELOOP or Building.LLVM_OPTS: return self.skip('FIXME') - src = ''' + src = r''' #include <stdio.h> #include "emscripten.h" int main() { // EMSCRIPTEN_COMMENT("hello from the source"); emscripten_run_script("print('hello world' + '!')"); + printf("*%d*\n", emscripten_run_script_int("5*20")); return 0; } ''' @@ -1593,7 +1629,47 @@ if 'benchmark' not in str(sys.argv): src = open(filename, 'r').read() # TODO: restore this (see comment in emscripten.h) assert '// hello from the source' in src - self.do_run(src, 'hello world!', post_build=check) + self.do_run(src, 'hello world!\n*100*', post_build=check) + + def test_memorygrowth(self): + # With typed arrays in particular, it is dangerous to use more memory than TOTAL_MEMORY, + # since we then need to enlarge the heap(s). + src = r''' + #include <stdio.h> + #include <stdlib.h> + #include <string.h> + #include <assert.h> + #include "emscripten.h" + + int main() + { + char *buf1 = (char*)malloc(100); + char *data1 = "hello"; + memcpy(buf1, data1, strlen(data1)+1); + + float *buf2 = (float*)malloc(100); + float pie = 4.955; + memcpy(buf2, &pie, sizeof(float)); + + printf("*pre: %s,%.3f*\n", buf1, buf2[0]); + + int totalMemory = emscripten_run_script_int("TOTAL_MEMORY"); + char *buf3 = (char*)malloc(totalMemory+1); + char *buf4 = (char*)malloc(100); + float *buf5 = (float*)malloc(100); + //printf("totalMemory: %d bufs: %d,%d,%d,%d,%d\n", totalMemory, buf1, buf2, buf3, buf4, buf5); + assert((int)buf4 > (int)totalMemory && (int)buf5 > (int)totalMemory); + + printf("*%s,%.3f*\n", buf1, buf2[0]); // the old heap data should still be there + + memcpy(buf4, buf1, strlen(data1)+1); + memcpy(buf5, buf2, sizeof(float)); + printf("*%s,%.3f*\n", buf4, buf5[0]); // and the new heap space should work too + + return 0; + } + ''' + self.do_run(src, '*pre: hello,4.955*\n*hello,4.955*\n*hello,4.955*') def test_ssr(self): # struct self-ref src = ''' @@ -1964,7 +2040,6 @@ if 'benchmark' not in str(sys.argv): def test_time(self): # XXX Not sure what the right output is here. Looks like the test started failing with daylight savings changes. Modified it to pass again. - if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Typed arrays = 2 truncate i64s') src = open(path_from_root('tests', 'time', 'src.c'), 'r').read() expected = open(path_from_root('tests', 'time', 'output.txt'), 'r').read() self.do_run(src, expected, @@ -2610,7 +2685,6 @@ if 'benchmark' not in str(sys.argv): self.do_run(src, re.sub(r'(^|\n)\s+', r'\1', expected)) def test_strtod(self): - if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Typed arrays = 2 truncate doubles') src = r''' #include <stdio.h> #include <stdlib.h> @@ -2665,18 +2739,16 @@ if 'benchmark' not in str(sys.argv): self.do_run(src, re.sub(r'\n\s+', '\n', expected)) def test_parseInt(self): - if Settings.USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64') + Settings.I64_MODE = 1 # Necessary to prevent i64s being truncated into i32s, but we do still get doubling + # FIXME: The output here is wrong, due to double rounding of i64s! src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read() - if Settings.I64_MODE == 0: - expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read() - else: - expected = open(path_from_root('tests', 'parseInt', 'output_i64mode1.txt'), 'r').read() # some rounding issues, etc. + expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read() self.do_run(src, expected) def test_printf(self): - if Settings.USE_TYPED_ARRAYS != 0: return self.skip('Typed arrays truncate i64') src = open(path_from_root('tests', 'printf', 'test.c'), 'r').read() - expected = open(path_from_root('tests', 'printf', 'output.txt'), 'r').read() + # I64 mode 1 has some rounding and un-NaNing effects + expected = open(path_from_root('tests', 'printf', 'output.txt' if Settings.I64_MODE == 0 else 'output_i64_1.txt'), 'r').read() self.do_run(src, expected) def test_printf_types(self): @@ -2878,8 +2950,6 @@ if 'benchmark' not in str(sys.argv): self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run) def test_stat(self): - if Settings.I64_MODE == 1: return self.skip('TODO') - def add_pre_run(filename): src = open(filename, 'r').read().replace( '// {{PRE_RUN_ADDITIONS}}', @@ -3399,7 +3469,7 @@ if 'benchmark' not in str(sys.argv): self.do_run(src, 'Pfannkuchen(%d) = %d.' % (i,j), [str(i)], no_build=i>1) def test_raytrace(self): - if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Relies on double values') + if Settings.USE_TYPED_ARRAYS == 2: return self.skip('Relies on double value rounding, extremely sensitive') src = open(path_from_root('tests', 'raytrace.cpp'), 'r').read().replace('double', 'float') output = open(path_from_root('tests', 'raytrace.ppm'), 'r').read() @@ -3579,8 +3649,6 @@ if 'benchmark' not in str(sys.argv): def test_the_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long if Building.LLVM_OPTS: Settings.SAFE_HEAP = 0 # Optimizations make it so we do not have debug info on the line we need to ignore - if Settings.USE_TYPED_ARRAYS == 2: return self.skip('We have slightly different rounding here for some reason. TODO: activate this') - # Note: this is also a good test of per-file and per-line changes (since we have multiple files, and correct specific lines) if Settings.SAFE_HEAP: # Ignore bitfield warnings @@ -3600,7 +3668,7 @@ if 'benchmark' not in str(sys.argv): def test_poppler(self): # llvm-link failure when using clang, LLVM bug 9498, still relevant? if Settings.RELOOP or Building.LLVM_OPTS: return self.skip('TODO') - if Settings.USE_TYPED_ARRAYS == 2 or Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix') + if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: Figure out and try to fix') Settings.USE_TYPED_ARRAYS = 0 # XXX bug - we fail with this FIXME @@ -3756,7 +3824,7 @@ if 'benchmark' not in str(sys.argv): output_nicerizer=image_compare)#, build_ll_hook=self.do_autodebug) def test_python(self): - if Settings.QUANTUM_SIZE == 1 or Settings.USE_TYPED_ARRAYS == 2: return self.skip('TODO: make this work') + if Settings.QUANTUM_SIZE == 1: return self.skip('TODO: make this work') # Overflows in string_hash Settings.CORRECT_OVERFLOWS = 1 @@ -3902,8 +3970,6 @@ Block 0: ''', post_build=post1) # Part 2: old JS version - if Settings.USE_TYPED_ARRAYS == 2: return self.skip('LLVM opts inline out the inner func') - Settings.PROFILE = 1 Settings.INVOKE_RUN = 0 @@ -4188,7 +4254,6 @@ Child2:9 def test_typeinfo(self): Settings.RUNTIME_TYPE_INFO = 1 if Settings.QUANTUM_SIZE != 4: return self.skip('We assume normal sizes in the output here') - if Settings.USE_TYPED_ARRAYS == 2: return self.skip('LLVM unsafe opts optimize out the type info') src = ''' #include<stdio.h> @@ -4457,8 +4522,6 @@ Child2:9 Settings.CHECK_SIGNS = 0 Settings.CHECK_OVERFLOWS = 0 - if Settings.USE_TYPED_ARRAYS == 2: return self.skip('LLVM opts optimize out the things we check') - # Signs src = ''' @@ -4579,37 +4642,37 @@ Child2:9 } ''' - Settings.CORRECT_ROUNDINGS = 0 - self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-6**5*') # JS floor operations, always to the negative. This is an undetected error here! - self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # We get these right, since they are 32-bit and we can shortcut using the |0 trick - self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-6**5*') # We fail, since no fast shortcut for 32-bit unsigneds + if Settings.I64_MODE == 0: # the errors here are very specific to non-i64 mode 1 + Settings.CORRECT_ROUNDINGS = 0 + self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-6**5*') # JS floor operations, always to the negative. This is an undetected error here! + self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # We get these right, since they are 32-bit and we can shortcut using the |0 trick + self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-6**5*') # We fail, since no fast shortcut for 32-bit unsigneds Settings.CORRECT_ROUNDINGS = 1 + Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') # Correct self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Correct - Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*') # Correct - return Settings.CORRECT_SIGNS = 0 - Settings.CORRECT_ROUNDINGS = 2 - Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake - self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-5**5*') - self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Here we are lucky and also get the first one right - self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-5**5*') # No such luck here + if Settings.I64_MODE == 0: # the errors here are very specific to non-i64 mode 1 + Settings.CORRECT_ROUNDINGS = 2 + Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:13"] # Fix just the last mistake + self.do_run(src.replace('TYPE', 'long long'), '*-3**2**-5**5*') + self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') # Here we are lucky and also get the first one right + self.do_run(src.replace('TYPE', 'unsigned int'), '*-3**2**-5**5*') # No such luck here # And reverse the check with = 2 - Settings.CORRECT_ROUNDINGS = 3 - Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:999"] - self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') - self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') - Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well - self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*') - Settings.CORRECT_SIGNS = 0 + if Settings.I64_MODE == 0: # the errors here are very specific to non-i64 mode 1 + Settings.CORRECT_ROUNDINGS = 3 + Settings.CORRECT_ROUNDINGS_LINES = ["src.cpp:999"] + self.do_run(src.replace('TYPE', 'long long'), '*-2**2**-5**5*') + self.do_run(src.replace('TYPE', 'int'), '*-2**2**-5**5*') + Settings.CORRECT_SIGNS = 1 # To be correct here, we need sign corrections as well + self.do_run(src.replace('TYPE', 'unsigned int'), '*2147483645**2**-5**5*') + Settings.CORRECT_SIGNS = 0 def test_pgo(self): - if Settings.USE_TYPED_ARRAYS == 2: return self.skip('LLVM opts optimize out the things we check') - Settings.PGO = Settings.CHECK_OVERFLOWS = Settings.CORRECT_OVERFLOWS = Settings.CHECK_SIGNS = Settings.CORRECT_SIGNS = 1 src = ''' @@ -4673,8 +4736,8 @@ Child2:9 ''' self.do_run(src, 'hello, world!\nExit Status: 118') - # Generate tests for all our compilers - def make_run(name, compiler, llvm_opts, embetter, quantum_size, typed_arrays): + # Generate tests for everything + def make_run(name=-1, compiler=-1, llvm_opts=0, embetter=0, quantum_size=0, typed_arrays=0, defaults=False): exec(''' class %s(T): def tearDown(self): @@ -4682,8 +4745,16 @@ class %s(T): def setUp(self): super(%s, self).setUp() - + + Building.COMPILER_TEST_OPTS = ['-g'] + os.chdir(self.get_dir()) # Ensure the directory exists and go there Building.COMPILER = %r + + use_defaults = %d + if use_defaults: + Settings.load_defaults() + return + llvm_opts = %d # 1 is yes, 2 is yes and unsafe embetter = %d quantum_size = %d @@ -4712,6 +4783,7 @@ class %s(T): Settings.CATCH_EXIT_CODE = 0 Settings.TOTAL_MEMORY = Settings.FAST_MEMORY = None Settings.EMULATE_UNALIGNED_ACCESSES = Settings.USE_TYPED_ARRAYS == 2 and Building.LLVM_OPTS == 2 + Settings.DOUBLE_MODE = 1 if Settings.USE_TYPED_ARRAYS and Building.LLVM_OPTS == 0 else 0 if Settings.USE_TYPED_ARRAYS == 2: Settings.I64_MODE = 1 Settings.SAFE_HEAP = 1 # only checks for alignment problems, which is very important with unsafe opts @@ -4723,35 +4795,39 @@ class %s(T): Building.pick_llvm_opts(3, safe=Building.LLVM_OPTS != 2) - Building.COMPILER_TEST_OPTS = ['-g'] - - os.chdir(self.get_dir()) # Ensure the directory exists and go there - TT = %s -''' % (fullname, fullname, fullname, compiler, llvm_opts, embetter, quantum_size, typed_arrays, fullname)) +''' % (fullname, fullname, fullname, compiler, defaults, llvm_opts, embetter, quantum_size, typed_arrays, fullname)) return TT - for name, compiler, quantum, embetter, typed_arrays, llvm_opts in [ - ('clang', CLANG, 1, 0, 0, 0), - ('clang', CLANG, 1, 0, 0, 1), - ('clang', CLANG, 4, 0, 0, 0), - ('clang', CLANG, 4, 0, 0, 1), - ('clang', CLANG, 1, 1, 1, 0), - ('clang', CLANG, 1, 1, 1, 1), - ('clang', CLANG, 4, 1, 1, 0), - ('clang', CLANG, 4, 1, 1, 1), - ('clang', CLANG, 4, 1, 2, 0), - ('clang', CLANG, 4, 1, 2, 1), - #('clang', CLANG, 4, 1, 2, 2), + # Make one run with the defaults + fullname = 'default' + exec(fullname + ' = make_run(compiler=CLANG, defaults=True)') + + # Make custom runs with various options + for compiler, quantum, embetter, typed_arrays, llvm_opts in [ + (CLANG, 1, 0, 0, 0), + (CLANG, 1, 0, 0, 1), + (CLANG, 4, 0, 0, 0), + (CLANG, 4, 0, 0, 1), + (CLANG, 1, 1, 1, 0), + (CLANG, 1, 1, 1, 1), + (CLANG, 4, 1, 1, 0), + (CLANG, 4, 1, 1, 1), + (CLANG, 4, 1, 2, 0), + (CLANG, 4, 1, 2, 1), + #(CLANG, 4, 1, 2, 2), ]: - fullname = '%s_%d_%d%s%s' % ( - name, llvm_opts, embetter, '' if quantum == 4 else '_q' + str(quantum), '' if typed_arrays in [0, 1] else '_t' + str(typed_arrays) + fullname = 's_%d_%d%s%s' % ( + llvm_opts, embetter, '' if quantum == 4 else '_q' + str(quantum), '' if typed_arrays in [0, 1] else '_t' + str(typed_arrays) ) exec('%s = make_run(%r,%r,%d,%d,%d,%d)' % (fullname, fullname, compiler, llvm_opts, embetter, quantum, typed_arrays)) del T # T is just a shape for the specific subclasses, we don't test it itself class other(RunnerCore): + def test_reminder(self): + raise Exception('update Getting Started to use defaults instead of clang_0_0') + def test_emcc(self): pass # TODO: make sure all of these match gcc @@ -4831,6 +4907,8 @@ else: class benchmark(RunnerCore): def setUp(self): + super(benchmark, self).setUp() + Settings.RELOOP = Settings.MICRO_OPTS = 1 Settings.USE_TYPED_ARRAYS = 1 Settings.QUANTUM_SIZE = 1 @@ -4848,8 +4926,6 @@ else: Building.LLVM_OPTS = 1 if Settings.USE_TYPED_ARRAYS != 2 else 2 Building.pick_llvm_opts(2, safe=Building.LLVM_OPTS != 2) - super(benchmark, self).setUp() - def print_stats(self, times, native_times, last=False): mean = sum(times)/len(times) squared_times = map(lambda x: x*x, times) |