#!/usr/bin/env bash # Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file # for details. All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. # Script to compile a benchmark using dart2wasm. Assumes the Dart repo's # directory structure. set -e function follow_links() { file="$1" while [ -h "$file" ]; do # On Mac OS, readlink -f doesn't work. file="$(readlink "$file")" done echo "$file" } # Unlike $0, $BASH_SOURCE points to the absolute path of this file. PROG_NAME="$(follow_links "$BASH_SOURCE")" # Handle the case where dart-sdk/bin has been symlinked to. PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" source "$PROG_DIR/utils.sh" # Locate build directory, containing executables, snapshots and platform dill. if [[ `uname` == 'Darwin' ]]; then OUT_DIR="$SDK_DIR/xcodebuild" else OUT_DIR="$SDK_DIR/out" fi HOST_ARCH="$(get_host_arch | tr '[:lower:]' '[:upper:]')" DART_CONFIGURATION=${DART_CONFIGURATION:-Release$HOST_ARCH} BIN_DIR="$OUT_DIR/$DART_CONFIGURATION" BINARYEN="$BIN_DIR/wasm-opt" DART="$BIN_DIR/dart" DART_AOT_RUNTIME="$BIN_DIR/dartaotruntime" LIBRARIES_JSON_ARG="--libraries-spec=$SDK_DIR/sdk/lib/libraries.json" RUN_BINARYEN=1 RUN_SRC=0 GENERATE_SOURCE_MAP=1 COMPILE_BENCHMARK_BASE_NAME="" PLATFORM_FILENAME="$BIN_DIR/dart2wasm_platform.dill" SNAPSHOT_NAME="dart2wasm" RUN_BENCHMARK=0 USE_TEMP_OUTPUT=0 # All arguments will be passed along to dart2wasm except specially recognized # flags. VM_ARGS=() DART2WASM_ARGS=("--require-js-string-builtin") DART_FILE="" OUTPUT_FILE="" PHASES="" while [ $# -gt 0 ]; do case "$1" in --compile-benchmark=*) COMPILE_BENCHMARK_BASE_NAME=$(echo $1 | sed 's/--compile-benchmark=//g') shift ;; --src) RUN_SRC=1 shift ;; --run) RUN_BENCHMARK=1 RUN_BENCHMARK_SHELL="d8" shift ;; --run=*) RUN_BENCHMARK=1 RUN_BENCHMARK_SHELL="${1#--run=}" shift ;; --temp-output) USE_TEMP_OUTPUT=1 shift ;; --js-compatibility) PLATFORM_FILENAME="$BIN_DIR/dart2wasm_js_compatibility_platform.dill" DART2WASM_ARGS+=("--js-compatibility") shift ;; --standalone) PLATFORM_FILENAME="$BIN_DIR/dart2wasm_standalone_platform.dill" DART2WASM_ARGS+=("--standalone") shift ;; --compiler-asserts) SNAPSHOT_NAME="dart2wasm_asserts" VM_ARGS+=("--enable-asserts") shift ;; -O0 | --optimization-level=0 | --extra-compiler-option=-O0 ) DART2WASM_ARGS+=("-O0") RUN_BINARYEN=0 shift ;; -O* | --optimization-level=*) DART2WASM_ARGS+=("$1") RUN_BINARYEN=1 shift ;; --phases=*) PHASES="${1#--phases=}" shift ;; --extra-compiler-option=--platform=*) PLATFORM_FILENAME="${1#--extra-compiler-option=--platform=}" shift ;; --extra-compiler-option=--no-js-compatibility) PLATFORM_FILENAME="$BIN_DIR/dart2wasm_platform.dill" DART2WASM_ARGS+=("--no-js-compatibility") shift ;; --extra-compiler-option=*) DART2WASM_ARGS+=("${1#--extra-compiler-option=}") shift ;; --no-source-maps) GENERATE_SOURCE_MAP=0 shift ;; -o) shift OUTPUT_FILE="$1" shift ;; --* | -*) DART2WASM_ARGS+=("$1") shift ;; *) if [ -z "$DART_FILE" ]; then DART_FILE="$1" shift else if [ -z "$OUTPUT_FILE" ]; then OUTPUT_FILE="$1" shift else echo "Unexpected argument $1" exit 1 fi fi ;; esac done if [ -z "$DART_FILE" ]; then echo "Expected [file.wasm]" exit 1 fi if [ $USE_TEMP_OUTPUT -eq 1 ] && [ -n "$OUTPUT_FILE" ]; then echo "Cannot specify both --temp-output and an explicit output file!" exit 1 fi if [ $USE_TEMP_OUTPUT -eq 0 ] && [ -z "$OUTPUT_FILE" ]; then echo "Expected " exit 1 fi if [ $USE_TEMP_OUTPUT -eq 1 ]; then BASENAME=$(basename "$DART_FILE" .dart) TEMP_DIR=$(mktemp -d) trap "rm -rf $TEMP_DIR" EXIT OUTPUT_FILE="$TEMP_DIR/${BASENAME}.wasm" echo "Compiling to temporary file: $OUTPUT_FILE" fi if [ -z "$PHASES" ]; then PHASES="cfe,tfa,codegen" fi PLATFORM_ARG="--platform=$PLATFORM_FILENAME" DART2WASM_AOT_SNAPSHOT="$BIN_DIR/$SNAPSHOT_NAME.snapshot" DART2WASM_SRC="$SDK_DIR/pkg/dart2wasm/bin/dart2wasm.dart" function measure() { set +e RESULT=$( { /usr/bin/time --format="\nMemory: %M KB, Time: %e s" "$@"; } 2>&1 ) EXIT=$? if [ $EXIT -ne 0 ]; then echo "Running $@ resulted in exit code $EXIT" echo "$RESULT" exit 1 fi set -e MEMORY=$(echo "$RESULT" | tail -n1 | sed 's/Memory: \([0-9.]\+\) KB, Time: \([0-9.]\+\) s.*/\1/g') MEMORY=$(($MEMORY * 1024)) TIME=$(echo "$RESULT" | tail -n1 | sed 's/Memory: \([0-9.]\+\) KB, Time: \([0-9.]\+\) s.*/\2/g') } function measure_size() { SIZE=$(cat $1 | wc -c) GZIP_SIZE=$(cat $1 | gzip -c6 | wc -c) } function run_if_binaryen_enabled() { if [ $RUN_BINARYEN -eq 1 ] && [[ $OUTPUT_FILE == *.wasm ]]; then "$@" fi } COMPILER_SIZE=0 COMPILER_GZIP_SIZE=0 if [ $RUN_SRC -eq 1 ]; then BASE_CMD=("$DART" "${VM_ARGS[@]}" "$DART2WASM_SRC" "$LIBRARIES_JSON_ARG") else BASE_CMD=("$DART_AOT_RUNTIME" "${VM_ARGS[@]}" "$DART2WASM_AOT_SNAPSHOT" "$PLATFORM_ARG") fi function run_compiler() { local dart2wasm_command=("${BASE_CMD[@]}" "${DART2WASM_ARGS[@]}" "--phases=$PHASES" "$DART_FILE" "$OUTPUT_FILE") if [ -n "$COMPILE_BENCHMARK_BASE_NAME" ]; then measure "${dart2wasm_command[@]}" COMPILER_TIME=$TIME COMPILER_MEMORY=$MEMORY measure_size "${OUTPUT_FILE%.wasm}.mjs" MJS_SIZE=$SIZE MJS_GZIP_SIZE=$GZIP_SIZE for OUTPUT_FILE in "${OUTPUT_FILE%.wasm}"*.wasm; do measure_size "$OUTPUT_FILE" (( COMPILER_SIZE+=$SIZE )) (( COMPILER_GZIP_SIZE+=$GZIP_SIZE )) done else "${dart2wasm_command[@]}" fi } BINARYEN_TIME=0 BINARYEN_MEMORY=0 BINARYEN_SIZE=0 BINARYEN_GZIP_SIZE=0 function run_binaryen() { local opt_command=("${BASE_CMD[@]}" "${DART2WASM_ARGS[@]}" "--phases=opt" "--wasm-opt=$BINARYEN" "$OUTPUT_FILE" "$OUTPUT_FILE") if [ -n "$COMPILE_BENCHMARK_BASE_NAME" ]; then # If we're measuring run each binaryen command sequentially. measure "${opt_command[@]}" BINARYEN_TIME=$(echo "$BINARYEN_TIME + $TIME" | bc) BINARYEN_MEMORY=$(($BINARYEN_MEMORY > $MEMORY ? $BINARYEN_MEMORY : $MEMORY )) measure_size "$OUTPUT_FILE" BINARYEN_SIZE=$(echo "$BINARYEN_SIZE + $SIZE" | bc) BINARYEN_GZIP_SIZE=$(echo "$BINARYEN_GZIP_SIZE + $GZIP_SIZE" | bc) MAX_MEMORY=$(($COMPILER_MEMORY > $BINARYEN_MEMORY ? $COMPILER_MEMORY : $BINARYEN_MEMORY )) TOTAL_TIME=$(echo "$COMPILER_TIME + $BINARYEN_TIME" | bc) else "${opt_command[@]}" fi } run_compiler run_if_binaryen_enabled run_binaryen if [ -n "$COMPILE_BENCHMARK_BASE_NAME" ]; then # CompileTime run_if_binaryen_enabled echo "$COMPILE_BENCHMARK_BASE_NAME.Time.Total(CompileTime): $TOTAL_TIME s" echo "$COMPILE_BENCHMARK_BASE_NAME.Time.Dart2Wasm(CompileTime): $COMPILER_TIME s" run_if_binaryen_enabled echo "$COMPILE_BENCHMARK_BASE_NAME.Time.Wasm2WasmOpt(CompileTime): $BINARYEN_TIME s" # CodeSize echo "$COMPILE_BENCHMARK_BASE_NAME.Size.mjs(CodeSize): $MJS_SIZE bytes" echo "$COMPILE_BENCHMARK_BASE_NAME.Size.mjs.gz(CodeSize): $MJS_GZIP_SIZE bytes" echo "$COMPILE_BENCHMARK_BASE_NAME.Size.wasm(CodeSize): $COMPILER_SIZE bytes" echo "$COMPILE_BENCHMARK_BASE_NAME.Size.wasm.gz(CodeSize): $COMPILER_GZIP_SIZE bytes" run_if_binaryen_enabled echo "$COMPILE_BENCHMARK_BASE_NAME.Size.wasm.opt(CodeSize): $BINARYEN_SIZE bytes" run_if_binaryen_enabled echo "$COMPILE_BENCHMARK_BASE_NAME.Size.wasm.opt.gz(CodeSize): $BINARYEN_GZIP_SIZE bytes" # MemoryUse run_if_binaryen_enabled echo "$COMPILE_BENCHMARK_BASE_NAME.MemoryUse.Max(MemoryUse): $MAX_MEMORY bytes" echo "$COMPILE_BENCHMARK_BASE_NAME.MemoryUse.Dart2Wasm(MemoryUse): $COMPILER_MEMORY bytes" run_if_binaryen_enabled echo "$COMPILE_BENCHMARK_BASE_NAME.MemoryUse.Wasm2WasmOpt(MemoryUse): $BINARYEN_MEMORY bytes" fi if [ $RUN_BENCHMARK -eq 1 ]; then echo "" echo "RUNNING $OUTPUT_FILE" "$PROG_DIR/run_benchmark" "--$RUN_BENCHMARK_SHELL" "$OUTPUT_FILE" fi