Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
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. &nbsp; &nbsp; &nbsp; &nbsp; <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. &nbsp; &nbsp; &nbsp; &nbsp; <br />'
                textual_results_html2 += 'JS ' + result[
                    'category'] + ': JS scalar is ' + format_comparison(
                        hsc, nsc
                    ) + ' than native scalar. &nbsp; &nbsp; &nbsp; &nbsp; <br />'
                textual_results_html3 += 'JS ' + result[
                    'category'] + ': JS SSE is ' + format_comparison(
                        hsi, nsi
                    ) + ' than native SSE. &nbsp; &nbsp; &nbsp; &nbsp; <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 + '.'