def run(): if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'): print('''\ emmake is a helper for make, setting various environment variables so that emcc etc. are used. Typical usage: emmake make [FLAGS] (but you can run any command instead of make)''', file=sys.stderr) return 1 args = sys.argv[1:] env = building.get_building_env() # On Windows prefer building with mingw32-make instead of make, if it exists. if utils.WINDOWS: if args[0] == 'make': mingw32_make = utils.which('mingw32-make') if mingw32_make: args[0] = mingw32_make if 'mingw32-make' in args[0]: env = building.remove_sh_exe_from_path(env) # On Windows, run the execution through shell to get PATH expansion and # executable extension lookup, e.g. 'sdl2-config' will match with # 'sdl2-config.bat' in PATH. print('make: ' + ' '.join(args), file=sys.stderr) try: shared.check_call(args, shell=utils.WINDOWS, env=env) return 0 except CalledProcessError as e: return e.returncode
def run(): if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'): print('''\ emconfigure is a helper for configure, setting various environment variables so that emcc etc. are used. Typical usage: emconfigure ./configure [FLAGS] (but you can run any command instead of configure)''', file=sys.stderr) return 1 args = sys.argv[1:] if 'cmake' in args: print( 'error: use `emcmake` rather then `emconfigure` for cmake projects', file=sys.stderr) return 1 env = building.get_building_env() # When we configure via a ./configure script, don't do config-time # compilation with emcc, but instead do builds natively with Clang. This # is a heuristic emulation that may or may not work. env['EMMAKEN_JUST_CONFIGURE'] = '1' print('configure: ' + shared.shlex_join(args), file=sys.stderr) try: shared.check_call(args, env=env) return 0 except CalledProcessError as e: return e.returncode
def run(): if len(sys.argv) < 2 or sys.argv[1] in ('--version', '--help'): print('''\ emcmake is a helper for cmake, setting various environment variables so that emcc etc. are used. Typical usage: emcmake cmake [FLAGS] ''', file=sys.stderr) return 1 args = sys.argv[1:] env = building.get_building_env() def has_substr(args, substr): return any(substr in s for s in args) # Append the Emscripten toolchain file if the user didn't specify one. if not has_substr(args, '-DCMAKE_TOOLCHAIN_FILE'): args.append('-DCMAKE_TOOLCHAIN_FILE=' + utils.path_from_root( 'cmake', 'Modules', 'Platform', 'Emscripten.cmake')) if not has_substr(args, '-DCMAKE_CROSSCOMPILING_EMULATOR'): node_js = config.NODE_JS[0] args.append(f'-DCMAKE_CROSSCOMPILING_EMULATOR={node_js}') # On Windows specify MinGW Makefiles or ninja if we have them and no other # toolchain was specified, to keep CMake from pulling in a native Visual # Studio, or Unix Makefiles. if utils.WINDOWS and '-G' not in args: if utils.which('mingw32-make'): args += ['-G', 'MinGW Makefiles'] elif utils.which('ninja'): args += ['-G', 'Ninja'] else: print( 'emcmake: no compatible cmake generator found; Please install ninja or mingw32-make, or specify a generator explicitly using -G', file=sys.stderr) return 1 # CMake has a requirement that it wants sh.exe off PATH if MinGW Makefiles # is being used. This happens quite often, so do this automatically on # behalf of the user. See # http://www.cmake.org/Wiki/CMake_MinGW_Compiler_Issues if utils.WINDOWS and 'MinGW Makefiles' in args: env = building.remove_sh_exe_from_path(env) print('configure: ' + shared.shlex_join(args), file=sys.stderr) try: shared.check_call(args, env=env) return 0 except CalledProcessError as e: return e.returncode
def get_clang_native_env(): global CACHED_CLANG_NATIVE_ENV if CACHED_CLANG_NATIVE_ENV is not None: return CACHED_CLANG_NATIVE_ENV env = os.environ.copy() env['CC'] = CLANG_CC env['CXX'] = CLANG_CXX env['LD'] = CLANG_CXX # get a non-native one, and see if we have some of its effects - remove them if so non_native = building.get_building_env() # the ones that a non-native would modify EMSCRIPTEN_MODIFIES = ['LDSHARED', 'AR', 'CROSS_COMPILE', 'NM', 'RANLIB'] for dangerous in EMSCRIPTEN_MODIFIES: if env.get(dangerous) and env.get(dangerous) == non_native.get(dangerous): del env[dangerous] # better to delete it than leave it, as the non-native one is definitely wrong if MACOS: path = run_process(['xcrun', '--show-sdk-path'], stdout=PIPE).stdout.strip() logger.debug('Using MacOS SDKROOT: ' + path) env['SDKROOT'] = path elif WINDOWS: # If already running in Visual Studio Command Prompt manually, no need to # add anything here, so just return. if 'VSINSTALLDIR' in env and 'INCLUDE' in env and 'LIB' in env: CACHED_CLANG_NATIVE_ENV = env return env # Guess where VS2015 is installed (VSINSTALLDIR env. var in VS2015 X64 Command Prompt) if 'VSINSTALLDIR' in env: visual_studio_path = env['VSINSTALLDIR'] elif 'VS140COMNTOOLS' in env: visual_studio_path = os.path.normpath(os.path.join(env['VS140COMNTOOLS'], '../..')) elif 'ProgramFiles(x86)' in env: visual_studio_path = os.path.normpath(os.path.join(env['ProgramFiles(x86)'], 'Microsoft Visual Studio 14.0')) elif 'ProgramFiles' in env: visual_studio_path = os.path.normpath(os.path.join(env['ProgramFiles'], 'Microsoft Visual Studio 14.0')) else: visual_studio_path = 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0' if not os.path.isdir(visual_studio_path): raise Exception('Visual Studio 2015 was not found in "' + visual_studio_path + '"! Run in Visual Studio X64 command prompt to avoid the need to autoguess this location (or set VSINSTALLDIR env var).') # Guess where Program Files (x86) is located if 'ProgramFiles(x86)' in env: prog_files_x86 = env['ProgramFiles(x86)'] elif 'ProgramFiles' in env: prog_files_x86 = env['ProgramFiles'] elif os.path.isdir('C:\\Program Files (x86)'): prog_files_x86 = 'C:\\Program Files (x86)' elif os.path.isdir('C:\\Program Files'): prog_files_x86 = 'C:\\Program Files' else: raise Exception('Unable to detect Program files directory for native Visual Studio build!') # Guess where Windows 8.1 SDK is located if 'WindowsSdkDir' in env: windows8_sdk_dir = env['WindowsSdkDir'] else: windows8_sdk_dir = os.path.join(prog_files_x86, 'Windows Kits', '8.1') if not os.path.isdir(windows8_sdk_dir): raise Exception('Windows 8.1 SDK was not found in "' + windows8_sdk_dir + '"! Run in Visual Studio command prompt to avoid the need to autoguess this location (or set WindowsSdkDir env var).') # Guess where Windows 10 SDK is located if os.path.isdir(os.path.join(prog_files_x86, 'Windows Kits', '10')): windows10_sdk_dir = os.path.join(prog_files_x86, 'Windows Kits', '10') if not os.path.isdir(windows10_sdk_dir): raise Exception('Windows 10 SDK was not found in "' + windows10_sdk_dir + '"! Run in Visual Studio command prompt to avoid the need to autoguess this location.') env.setdefault('VSINSTALLDIR', visual_studio_path) env.setdefault('VCINSTALLDIR', os.path.join(visual_studio_path, 'VC')) windows10sdk_kits_include_dir = os.path.join(windows10_sdk_dir, 'Include') windows10sdk_kit_version_name = [x for x in os.listdir(windows10sdk_kits_include_dir) if os.path.isdir(os.path.join(windows10sdk_kits_include_dir, x))][0] # e.g. "10.0.10150.0" or "10.0.10240.0" def append_item(key, item): if key not in env or len(env[key].strip()) == 0: env[key] = item else: env[key] = env[key] + ';' + item append_item('INCLUDE', os.path.join(env['VCINSTALLDIR'], 'INCLUDE')) append_item('INCLUDE', os.path.join(env['VCINSTALLDIR'], 'ATLMFC', 'INCLUDE')) append_item('INCLUDE', os.path.join(windows10_sdk_dir, 'include', windows10sdk_kit_version_name, 'ucrt')) # append_item('INCLUDE', 'C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\include\\um') # VS2015 X64 command prompt has this, but not needed for Emscripten append_item('INCLUDE', os.path.join(env['VCINSTALLDIR'], 'ATLMFC', 'INCLUDE')) append_item('INCLUDE', os.path.join(windows8_sdk_dir, 'include', 'shared')) append_item('INCLUDE', os.path.join(windows8_sdk_dir, 'include', 'um')) append_item('INCLUDE', os.path.join(windows8_sdk_dir, 'include', 'winrt')) logger.debug('VS2015 native build INCLUDE: ' + env['INCLUDE']) append_item('LIB', os.path.join(env['VCINSTALLDIR'], 'LIB', 'amd64')) append_item('LIB', os.path.join(env['VCINSTALLDIR'], 'ATLMFC', 'LIB', 'amd64')) append_item('LIB', os.path.join(windows10_sdk_dir, 'lib', windows10sdk_kit_version_name, 'ucrt', 'x64')) # append_item('LIB', 'C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\lib\\um\\x64') # VS2015 X64 command prompt has this, but not needed for Emscripten append_item('LIB', os.path.join(windows8_sdk_dir, 'lib', 'winv6.3', 'um', 'x64')) logger.debug('VS2015 native build LIB: ' + env['LIB']) env['PATH'] = env['PATH'] + ';' + os.path.join(env['VCINSTALLDIR'], 'BIN') logger.debug('VS2015 native build PATH: ' + env['PATH']) # Current configuration above is all Visual Studio -specific, so on non-Windowses, no action needed. CACHED_CLANG_NATIVE_ENV = env return env
def run_benchmark(benchmark_file, results_file, build_args): # Run native build out_file = os.path.join(temp_dir, 'benchmark_sse_native') if WINDOWS: out_file += '.exe' cmd = [CLANG_CXX] + building.get_native_building_args() + [ benchmark_file, '-O3', '-o', out_file ] print 'Building native version of the benchmark:' print ' '.join(cmd) build = Popen(cmd, env=building.get_building_env(native=True)) out = build.communicate() if build.returncode != 0: sys.exit(1) native_results = Popen([out_file], stdout=PIPE, stderr=PIPE).communicate() print native_results[0] # Run emscripten build out_file = os.path.join(temp_dir, 'benchmark_sse_html.js') cmd = [ EMCC, benchmark_file, '-O3', '-s', 'TOTAL_MEMORY=536870912', '-o', out_file ] + build_args print 'Building Emscripten version of the benchmark:' print ' '.join(cmd) build = Popen(cmd) out = build.communicate() if build.returncode != 0: sys.exit(1) cmd = V8_ENGINE + ['--experimental-wasm-simd', os.path.basename(out_file)] print ' '.join(cmd) old_dir = os.getcwd() os.chdir(os.path.dirname(out_file)) wasm_results = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() os.chdir(old_dir) if not wasm_results: raise Exception('Unable to run benchmark in V8!') if not wasm_results[0].strip(): print wasm_results[1] sys.exit(1) print wasm_results[0] def strip_comments(text): return re.sub('//.*?\n|/\*.*?\*/', '', text, re.S) benchmark_results = strip_comments(wasm_results[0]) # Strip out unwanted print output. benchmark_results = benchmark_results[benchmark_results.find('{'):].strip() if '*************************' in benchmark_results: benchmark_results = benchmark_results[:benchmark_results.find( '*************************')].strip() print benchmark_results shutil.rmtree(temp_dir) native_results = json.loads(native_results[0]) benchmark_results = benchmark_results[ benchmark_results.index('{'):benchmark_results.rindex('}') + 1] wasm_results = json.loads(benchmark_results) native_workload = native_results['workload'] html_workload = wasm_results['workload'] html = '''<html><head></head><body><h1>SSE JavaScript Benchmark</h1> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> <script src="https://code.highcharts.com/highcharts.js"></script> <script src="https://code.highcharts.com/modules/exporting.js"></script><b>System Info:</b><br/> ''' + system_info[0].replace('\n', '<br/>') + ''' <b>Native Clang Compiler:</b><br/> ''' + native_info[1].replace('\n', '<br/>') + ''' <b>Emscripten Compiler:</b><br/> ''' + emscripten_info[0].replace('\n', '<br/>') charts_native = {} charts_html = {} for result in native_results['results']: ch = result['chart'] if ch not in charts_native: charts_native[ch] = [] charts_native[ch] += [result] for result in wasm_results['results']: ch = result['chart'] if ch not in charts_html: charts_html[ch] = [] charts_html[ch] += [result] def find_result_in_category(results, category): for result in results: if result['category'] == category: return result return None def format_comparison(a, b): if a < b and a != 0: return "<span style='color:green;font-weight:bold;'> {:10.2f}".format( b / a) + 'x FASTER</span>' elif b != 0: return "<span style='color:red;font-weight:bold;'> {:10.2f}".format( a / b) + 'x SLOWER</span>' else: return "<span style='color:red;font-weight:bold;'> NaN </span>" chartNumber = 0 total_time_native_scalar = 0 total_time_native_simd = 0 total_time_html_scalar = 0 total_time_html_simd = 0 for chart_name in charts_native.keys(): # Extract data for each chart. categories = [] nativeScalarResults = [] nativeSimdResults = [] htmlScalarResults = [] htmlSimdResults = [] native_results = charts_native[chart_name] wasm_results = charts_html[chart_name] textual_results_native = '<p>' textual_results_html = '<p>' textual_results_html2 = '<p>' textual_results_html3 = '<p>' for result in native_results: categories += ["'" + result['category'] + "'"] nsc = result['scalar'] nsi = result['simd'] nativeScalarResults += [str(nsc)] nativeSimdResults += [str(nsi)] html_result = find_result_in_category(wasm_results, result['category']) textual_results_native += 'Native ' + result[ 'category'] + ': ' + "{:10.4f}".format( nsc) + 'ns -> ' + "{:10.4f}".format(nsi) + 'ns. ' textual_results_native += 'Native SSE is ' + format_comparison( nsi, nsc ) + ' than native scalar. <br />' if html_result is not None: hsc = html_result['scalar'] htmlScalarResults += [str(hsc)] hsi = html_result['simd'] htmlSimdResults += [str(hsi)] textual_results_html += 'JS ' + result[ 'category'] + ': ' + "{:10.4f}".format( hsc) + 'ns -> ' + "{:10.4f}".format(hsi) + 'ns. ' textual_results_html += 'JS SSE is ' + format_comparison( hsi, hsc ) + ' than JS scalar. <br />' textual_results_html2 += 'JS ' + result[ 'category'] + ': JS scalar is ' + format_comparison( hsc, nsc ) + ' than native scalar. <br />' textual_results_html3 += 'JS ' + result[ 'category'] + ': JS SSE is ' + format_comparison( hsi, nsi ) + ' than native SSE. <br />' total_time_native_scalar += nsc total_time_native_simd += nsi total_time_html_scalar += hsc total_time_html_simd += hsi else: htmlScalarResults += [str(-1)] htmlSimdResults += [str(-1)] chartNumber += 1 html += '<div id="chart' + str( chartNumber ) + '" style="width:100%; height:400px; margin-top: 100px;"></div>' html += '''<script>$(function () { $('#chart''' + str(chartNumber) + '''').highcharts({ chart: { type: 'column' }, title: { text: "''' + chart_name + '''" }, subtitle: { text: 'Time per operation in nanoseconds' }, xAxis: { categories: [''' + ','.join(categories) + ''' ] }, yAxis: { min: 0, title: { text: 'Time (nanoseconds)' } }, tooltip: { headerFormat: '<span style="font-size:10px">{point.key}</span><table>', pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' + '<td style="padding:0"><b>{point.y:.3f} ns</b></td></tr>', footerFormat: '</table>', shared: true, useHTML: true }, plotOptions: { column: { pointPadding: 0.2, borderWidth: 0 } }, series: [{ name: 'Native scalar', data: [''' + ','.join(nativeScalarResults) + '''] }, { name: 'Native SSE', data: [''' + ','.join(nativeSimdResults) + '''] }, { name: 'JS scalar', data: [''' + ','.join(htmlScalarResults) + '''] }, { name: 'JS SSE', data: [''' + ','.join(htmlSimdResults) + '''] }] }); });</script>''' + '<table><tr><td>' + textual_results_native + '</td><td>' + textual_results_html + '</td></tr><tr><td>' + textual_results_html2 + '</td><td>' + textual_results_html3 + '</td></tr></table>' # Final overall score html += '<div id="overallscore" style="width:100%; height:400px; margin-top: 100px;"></div>' html += '''<script>$(function () { $('#overallscore').highcharts({ chart: { type: 'column' }, title: { text: "Overall Execution Time" }, xAxis: { categories: ['Total time normalized to native'] }, yAxis: { min: 0, title: { text: 'Relative time' } }, tooltip: { headerFormat: '<span style="font-size:10px">{point.key}</span><table>', pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' + '<td style="padding:0"><b>{point.y:.3f}x</b></td></tr>', footerFormat: '</table>', shared: true, useHTML: true }, plotOptions: { column: { pointPadding: 0.2, borderWidth: 0 } }, series: [{ name: 'Native scalar', data: [''' + str(1.0) + '''] }, { name: 'Native SSE', data: [''' + (str(total_time_native_simd / total_time_native_scalar) if total_time_native_scalar != 0 else 'N/A') + '''] }, { name: 'JS scalar', data: [''' + (str(total_time_html_scalar / total_time_native_scalar) if total_time_native_scalar != 0 else 'N/A') + '''] }, { name: 'JS SSE', data: [''' + (str(total_time_html_simd / total_time_native_scalar) if total_time_native_scalar != 0 else 'N/A') + '''] }] }); });</script>''' html += '</body></html>' open(results_file, 'w').write(html) print 'Wrote ' + str(len(html)) + ' bytes to file ' + results_file + '.'