From d07a37e39426f7051fcca1aab13beba2d7ec0956 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 10 Oct 2011 19:58:29 -0700 Subject: [PATCH 1/3] EMSCRIPTEN_COMMENT for source comments --- src/jsifier.js | 6 ++++++ system/include/emscripten.h | 20 ++++++++++++++++++-- tests/runner.py | 8 +++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index cd59d43c0..9c34ddf1e 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -838,6 +838,12 @@ function JSify(data, functionsOnly, givenFunctions, givenGlobalVariables) { return makeSetValue(params[0].ident, 0, data, 'void*'); } else if (ident == '_llvm_va_end') { return ';'; + } else if (ident == '_EMSCRIPTEN_COMMENT') { + var param = finalizeParam(params[0]); + if (param.indexOf('CHECK_OVERFLOW') >= 0) { + param = param.split('(')[1].split(',')[0]; + } + return '// ' + GLOBAL_VARIABLES[param].value.text.replace('\\00', '') + ' '; } var func = Functions.currFunctions[ident] || Functions.currExternalFunctions[ident]; diff --git a/system/include/emscripten.h b/system/include/emscripten.h index 5f3689c97..4d321b2c9 100644 --- a/system/include/emscripten.h +++ b/system/include/emscripten.h @@ -7,7 +7,23 @@ * http://emscripten.org */ -// Interface to the underlying JS engine. This function will -// eval() the given script. +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Interface to the underlying JS engine. This function will + * eval() the given script. + */ extern void emscripten_run_script(const char *script); +/* + * This macro-looking function will cause Emscripten to + * generate a comment in the generated code. + */ +extern void EMSCRIPTEN_COMMENT(const char *text); + +#ifdef __cplusplus +} +#endif + diff --git a/tests/runner.py b/tests/runner.py index 3f124df74..bf71cf2c3 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -1430,11 +1430,17 @@ if 'benchmark' not in str(sys.argv): #include "emscripten.h" int main() { + EMSCRIPTEN_COMMENT("hello from the source"); emscripten_run_script("print('hello world' + '!')"); return 0; } ''' - self.do_test(src, 'hello world!') + + def check(filename): + src = open(filename, 'r').read() + assert '// hello from the source' in src + + self.do_test(src, 'hello world!', post_build=check) def test_ssr(self): # struct self-ref src = ''' From 29f60bc74814d5ac436528b92aba153d32d50f96 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 11 Oct 2011 17:42:00 -0700 Subject: [PATCH 2/3] improve benchmark output --- tests/runner.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index bf71cf2c3..3b6eec29f 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -4270,11 +4270,11 @@ else: TOTAL_TESTS = 6 tests_done = 0 - total_times = map(lambda x: 0., range(TEST_REPS)) - total_native_times = map(lambda x: 0., range(TEST_REPS)) + total_times = map(lambda x: 0., range(TOTAL_TESTS)) + total_native_times = map(lambda x: 0., range(TOTAL_TESTS)) class benchmark(RunnerCore): - def print_stats(self, times, native_times): + def print_stats(self, times, native_times, normalize_by_native=False): mean = sum(times)/len(times) squared_times = map(lambda x: x*x, times) mean_of_squared = sum(squared_times)/len(times) @@ -4285,9 +4285,17 @@ else: mean_of_squared_native = sum(squared_native_times)/len(native_times) std_native = math.sqrt(mean_of_squared_native - mean_native*mean_native) + if not normalize_by_native: + final = mean / mean_native + else: + final = 0 + for i in range(len(times)): + final += times[i]/native_times[i] + final /= len(times) + print print ' JavaScript : mean: %.3f (+-%.3f) seconds (max: %.3f, min: %.3f, noise/signal: %.3f) (%d runs)' % (mean, std, max(times), min(times), std/mean, TEST_REPS) - print ' Native (gcc): mean: %.3f (+-%.3f) seconds (max: %.3f, min: %.3f, noise/signal: %.3f) JS is %.2f times slower' % (mean_native, std_native, max(native_times), min(native_times), std_native/mean_native, mean/mean_native) + print ' Native (gcc): mean: %.3f (+-%.3f) seconds (max: %.3f, min: %.3f, noise/signal: %.3f) JS is %.2f X slower' % (mean_native, std_native, max(native_times), min(native_times), std_native/mean_native, final) def do_benchmark(self, src, args=[], expected_output='FAIL', main_file=None, llvm_opts=False, handpicked=False): global USE_TYPED_ARRAYS, LLVM_OPTS @@ -4322,14 +4330,14 @@ else: final_filename = filename + '.cc.js' # Run JS - global total_times + global total_times, tests_done times = [] for i in range(TEST_REPS): start = time.time() js_output = self.run_generated_code(JS_ENGINE, final_filename, args, check_timeout=False) curr = time.time()-start times.append(curr) - total_times[i] += curr + total_times[tests_done] += curr if i == 0: # Sanity check on output self.assertContained(expected_output, js_output) @@ -4343,16 +4351,15 @@ else: self.run_native(filename, args) curr = time.time()-start native_times.append(curr) - total_native_times[i] += curr + total_native_times[tests_done] += curr self.print_stats(times, native_times) - global tests_done tests_done += 1 if tests_done == TOTAL_TESTS: print print 'Total stats:' - self.print_stats(total_times, total_native_times) + self.print_stats(total_times, total_native_times, True) def test_primes(self): src = ''' From 5c8918ceb32bb1abf735d39f73e67e10b8da409f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 11 Oct 2011 19:04:06 -0700 Subject: [PATCH 3/3] use eliminator in benchmarks --- tests/runner.py | 65 ++++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/tests/runner.py b/tests/runner.py index 3b6eec29f..1178c2bfd 100644 --- a/tests/runner.py +++ b/tests/runner.py @@ -4238,14 +4238,11 @@ else: assert(os.path.exists(CLOSURE_COMPILER)) - USE_CLOSURE_COMPILER = 1 - - if USE_CLOSURE_COMPILER: - try: - index = SPIDERMONKEY_ENGINE.index("options('strict')") - SPIDERMONKEY_ENGINE = SPIDERMONKEY_ENGINE[:index-1] + SPIDERMONKEY_ENGINE[index+1:] # closure generates non-strict - except: - pass + try: + index = SPIDERMONKEY_ENGINE.index("options('strict')") + SPIDERMONKEY_ENGINE = SPIDERMONKEY_ENGINE[:index-1] + SPIDERMONKEY_ENGINE[index+1:] # closure generates non-strict + except: + pass COMPILER = CLANG JS_ENGINE = SPIDERMONKEY_ENGINE @@ -4310,24 +4307,30 @@ else: final_filename = filename + '.o.js' - if USE_CLOSURE_COMPILER: - # Optimize using closure compiler - try: - os.remove(filename + '.cc.js') - except: - pass - # Something like this (adjust memory as needed): - # java -Xmx1024m -jar CLOSURE_COMPILER --compilation_level ADVANCED_OPTIMIZATIONS --variable_map_output_file src.cpp.o.js.vars --js src.cpp.o.js --js_output_file src.cpp.o.cc.js + for post in POST_OPTIMIZATIONS: + if post == 'closure': + # Something like this (adjust memory as needed): + # java -Xmx1024m -jar CLOSURE_COMPILER --compilation_level ADVANCED_OPTIMIZATIONS --variable_map_output_file src.cpp.o.js.vars --js src.cpp.o.js --js_output_file src.cpp.o.cc.js - cc_output = Popen(['java', '-jar', CLOSURE_COMPILER, - '--compilation_level', 'ADVANCED_OPTIMIZATIONS', - '--formatting', 'PRETTY_PRINT', - '--variable_map_output_file', filename + '.vars', - '--js', filename + '.o.js', '--js_output_file', filename + '.cc.js'], stdout=PIPE, stderr=STDOUT).communicate()[0] - if 'ERROR' in cc_output: - raise Exception('Error in cc output: ' + cc_output) - - final_filename = filename + '.cc.js' + cc_output = Popen(['java', '-jar', CLOSURE_COMPILER, + '--compilation_level', 'ADVANCED_OPTIMIZATIONS', + '--formatting', 'PRETTY_PRINT', + '--variable_map_output_file', final_filename + '.vars', + '--js', final_filename, '--js_output_file', final_filename + '.cc.js'], stdout=PIPE, stderr=STDOUT).communicate()[0] + if 'ERROR' in cc_output: + raise Exception('Error in cc output: ' + cc_output) + final_filename += '.cc.js' + elif post == 'eliminator': + coffee = path_from_root('tools', 'eliminator', 'node_modules', 'coffee-script', 'bin', 'coffee') + eliminator = path_from_root('tools', 'eliminator', 'eliminator.coffee') + input = open(final_filename, 'r').read() + output = Popen([coffee, eliminator], stdin=PIPE, stdout=PIPE, stderr=PIPE).communicate(input)[0] + final_filename += '.el.js' + f = open(final_filename, 'w') + f.write(output) + f.close() + else: + raise Exception('Unknown post-optimization: ' + post) # Run JS global total_times, tests_done @@ -4362,6 +4365,8 @@ else: self.print_stats(total_times, total_native_times, True) def test_primes(self): + global POST_OPTIMIZATIONS; POST_OPTIMIZATIONS = ['eliminator', 'closure'] + src = ''' #include #include @@ -4387,6 +4392,8 @@ else: self.do_benchmark(src, [], 'lastprime: 1297001.', llvm_opts=True, handpicked=False) def test_memops(self): + global POST_OPTIMIZATIONS; POST_OPTIMIZATIONS = ['eliminator', 'closure'] + # memcpy would also be interesting, however native code uses SSE/NEON/etc. and is much, much faster than JS can be src = ''' #include @@ -4411,15 +4418,21 @@ else: self.do_benchmark(src, [], 'final: 720.', llvm_opts=True, handpicked=True) def test_fannkuch(self): + global POST_OPTIMIZATIONS; POST_OPTIMIZATIONS = ['eliminator', 'closure'] + src = open(path_from_root('tests', 'fannkuch.cpp'), 'r').read() self.do_benchmark(src, ['10'], 'Pfannkuchen(10) = 38.', llvm_opts=True, handpicked=True) def test_fasta(self): + global POST_OPTIMIZATIONS; POST_OPTIMIZATIONS = ['eliminator'] + src = open(path_from_root('tests', 'fasta.cpp'), 'r').read() self.do_benchmark(src, ['2100000'], '''GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA\nTCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT\nAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG\nGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG\nCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT\nGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA\nGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA\nTTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG\nAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA\nGCCTGGGCGA''', llvm_opts=True, handpicked=False) def test_raytrace(self): + global POST_OPTIMIZATIONS; POST_OPTIMIZATIONS = ['closure'] + global QUANTUM_SIZE, USE_TYPED_ARRAYS old_quantum = QUANTUM_SIZE old_use_typed_arrays = USE_TYPED_ARRAYS @@ -4433,6 +4446,8 @@ else: USE_TYPED_ARRAYS = old_use_typed_arrays def test_dlmalloc(self): + global POST_OPTIMIZATIONS; POST_OPTIMIZATIONS = ['eliminator'] + global COMPILER_TEST_OPTS; COMPILER_TEST_OPTS = ['-g'] global CORRECT_SIGNS; CORRECT_SIGNS = 2 global CORRECT_SIGNS_LINES; CORRECT_SIGNS_LINES = ['src.cpp:' + str(i+4) for i in [4816, 4191, 4246, 4199, 4205, 4235, 4227]]