#!/bin/bash # Copyright JS Foundation and other contributors, http://js.foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. trap "exit 2" INT function pr_err() { echo -e "\e[91mError: $@\e[39m" } function exit_err() { pr_err $@ exit 1 } # Check if the specified build supports memory statistics options function is_mem_stats_build() { [ -x "$1" ] || fail_msg "Engine '$1' is not executable" tmpfile=`mktemp` "$1" --mem-stats $tmpfile 2>&1 | grep -- "Ignoring JERRY_INIT_MEM_STATS flag because of !JMEM_STATS configuration." 2>&1 > /dev/null code=$? rm $tmpfile return $code } USAGE="Usage:\n tools/run-perf-test.sh OLD_ENGINE NEW_ENGINE REPEATS TIMEOUT BENCH_FOLDER [-m result-file-name.md]" if [ "$#" -lt 5 ] then echo -e "${USAGE}" exit_err "Argument number mismatch..." fi ENGINE_OLD="$1" ENGINE_NEW="$2" REPEATS="$3" TIMEOUT="$4" BENCH_FOLDER="$5" OUTPUT_FORMAT="$6" OUTPUT_FILE="$7" if [ "$#" -gt 5 ] then if [ "${OUTPUT_FORMAT}" != "-m" ] then exit_err "Please, use '-m result-file-name.md' as last arguments" fi if [ -z "${OUTPUT_FILE}" ] then exit_err "Missing md file name. Please, define the filename. Ex.: '-m result-file-name.md'" fi rm -rf "${OUTPUT_FILE}" fi if [ "${REPEATS}" -lt 1 ] then exit_err "REPEATS must be greater than 0" fi if [ "${TIMEOUT}" -lt 1 ] then exit_err "TIMEOUT must be greater than 0" fi perf_n=0 mem_n=0 perf_rel_mult=1.0 perf_rel_inaccuracy_tmp=0 mem_rel_mult=1.0 mem_rel_inaccuracy_tmp="-1" # Unicode "figure space" character FIGURE_SPACE=$(echo -e -n "\xE2\x80\x87") # Unicode "approximately equal" character APPROXIMATELY_EQUAL=$(echo -n -e "\xE2\x89\x88") function run-compare() { COMMAND=$1 PRE=$2 TEST=$3 PRECISION=$4 UNIT=$5 ABS_FP_FMT="%$((PRECISION + 4)).$((PRECISION))f$UNIT" REL_FP_FMT="%0.3f" REL_SHOW_PLUS_SIGN_FP_FMT="%+0.3f" OLD=$(timeout "${TIMEOUT}" ${COMMAND} "${ENGINE_OLD}" "${TEST}") || return 1 NEW=$(timeout "${TIMEOUT}" ${COMMAND} "${ENGINE_NEW}" "${TEST}") || return 1 #check result ! $OLD || ! $NEW || return 1 OLD_value=$(echo "$OLD " | cut -d ' ' -f 1) OLD_inaccuracy=$(echo "$OLD " | cut -d ' ' -f 2) NEW_value=$(echo "$NEW " | cut -d ' ' -f 1) NEW_inaccuracy=$(echo "$NEW " | cut -d ' ' -f 2) #calc relative speedup eval "rel_mult=\$${PRE}_rel_mult" rel=$(echo "${OLD_value}" "${NEW_value}" | awk '{ print $2 / $1; }') #increment n ((${PRE}_n++)) #calc percent to display PERCENT=$(echo "$rel" | awk '{print (1.0 - $1) * 100; }') if [[ "$OLD_inaccuracy" != "" && "$NEW_inaccuracy" != "" ]] then DIFF=$(printf "$ABS_FP_FMT -> $ABS_FP_FMT" $OLD_value $NEW_value) rel_inaccuracy=$(echo "$OLD_value $OLD_inaccuracy $NEW_value $NEW_inaccuracy" | \ awk "{ OLD_value=\$1 OLD_inaccuracy=\$2 NEW_value=\$3 NEW_inaccuracy=\$4 rel_inaccuracy = (NEW_value / OLD_value) * sqrt ((OLD_inaccuracy / OLD_value) ^ 2 + (NEW_inaccuracy / NEW_value) ^ 2) if (rel_inaccuracy < 0) { rel_inaccuracy = -rel_inaccuracy } print rel_inaccuracy }") PERCENT_inaccuracy=$(echo "$rel_inaccuracy" | awk '{ print $1 * 100.0 }') ext=$(echo "$PERCENT $PERCENT_inaccuracy" | \ awk "{ PERCENT=\$1 PERCENT_inaccuracy=\$2 if (PERCENT > 0.0 && PERCENT > PERCENT_inaccuracy) { print \"[+]\" } else if (PERCENT < 0 && -PERCENT > PERCENT_inaccuracy) { print \"[-]\" } else { print \"[$APPROXIMATELY_EQUAL]\" } }") if [[ $rel_inaccuracy_tmp -lt 0 ]] then return 1 fi eval "rel_inaccuracy_tmp=\$${PRE}_rel_inaccuracy_tmp" rel_inaccuracy_tmp=$(echo "$rel $rel_inaccuracy $rel_inaccuracy_tmp" | \ awk "{ rel=\$1 rel_inaccuracy=\$2 rel_inaccuracy_tmp=\$3 print rel_inaccuracy_tmp + (rel_inaccuracy / rel) ^ 2 }") eval "${PRE}_rel_inaccuracy_tmp=\$rel_inaccuracy_tmp" PERCENT=$(printf "%8s %11s" $(printf "$REL_SHOW_PLUS_SIGN_FP_FMT%%" $PERCENT) $(printf "(+-$REL_FP_FMT%%)" $PERCENT_inaccuracy)) PERCENT="$PERCENT : $ext" if [ "${OUTPUT_FORMAT}" == "-m" ] then WIDTH=42 MD_DIFF=$(printf "%s%s" "$DIFF" "$(printf "%$(($WIDTH - ${#DIFF}))s")") MD_PERCENT=$(printf "%s%s" "$(printf "%$(($WIDTH - ${#PERCENT}))s")" "$PERCENT") MD_FORMAT="\`%s\`
\`%s\`" fi CONSOLE_FORMAT="%20s : %19s" else ext="" if [[ "$OLD_inaccuracy" != "" || "$NEW_inaccuracy" != "" ]] then return 1; fi DIFF=$(printf "$ABS_FP_FMT -> $ABS_FP_FMT" $OLD_value $NEW_value) PERCENT=$(printf "$REL_SHOW_PLUS_SIGN_FP_FMT%%" $PERCENT) if [ "${OUTPUT_FORMAT}" == "-m" ] then WIDTH=20 MD_DIFF=$(printf "%s%s" "$DIFF" "$(printf "%$(($WIDTH - ${#DIFF}))s")") MD_PERCENT=$(printf "%s%s" "$(printf "%$(($WIDTH - ${#PERCENT}))s")" "$PERCENT") MD_FORMAT="\`%s\`
\`%s\`" fi CONSOLE_FORMAT="%14s : %8s" fi rel_mult=$(echo "$rel_mult" "$rel" | awk '{print $1 * $2;}') eval "${PRE}_rel_mult=\$rel_mult" if [ "${OUTPUT_FORMAT}" == "-m" ] then printf "$MD_FORMAT" "$MD_DIFF" "$MD_PERCENT" | sed "s/ /$FIGURE_SPACE/g" >> "${OUTPUT_FILE}" fi printf "$CONSOLE_FORMAT" "$DIFF" "$PERCENT" } function run-test() { TEST=$1 # print only filename if [ "${OUTPUT_FORMAT}" == "-m" ] then printf "%s | " "${TEST##*/}" >> "${OUTPUT_FILE}" fi printf "%50s | " "${TEST##*/}" if [ "$IS_MEM_STAT" -ne 0 ] then run-compare "./tools/mem-stats-measure.sh" "mem" "${TEST}" 0 || return 1 else run-compare "./tools/rss-measure.sh" "mem" "${TEST}" 0 k || return 1 fi if [ "${OUTPUT_FORMAT}" == "-m" ] then printf " | " >> "${OUTPUT_FILE}" fi printf " | " run-compare "./tools/perf.sh ${REPEATS}" "perf" "${TEST}" 3 s || return 1 if [ "${OUTPUT_FORMAT}" == "-m" ] then printf "\n" >> "${OUTPUT_FILE}" fi printf "\n" } function run-suite() { FOLDER=$1 for BENCHMARK in ${FOLDER}/*.js do run-test "${BENCHMARK}" 2> /dev/null || printf "\n" "${BENCHMARK}"; done } date is_mem_stats_build "${ENGINE_OLD}" || is_mem_stats_build "${ENGINE_NEW}" IS_MEM_STAT=$? if [ "${OUTPUT_FORMAT}" == "-m" ] then if [ "$IS_MEM_STAT" -ne 0 ] then echo "Benchmark | Peak alloc.
(+ is better) | Perf
(+ is better)" >> "${OUTPUT_FILE}" else echo "Benchmark | RSS
(+ is better) | Perf
(+ is better)" >> "${OUTPUT_FILE}" fi echo "---------: | --------- | ---------" >> "${OUTPUT_FILE}" fi if [ "$IS_MEM_STAT" -ne 0 ] then printf "%50s | %25s | %35s\n" "Benchmark" "Peak alloc.(+ is better)" "Perf(+ is better)" else printf "%50s | %25s | %35s\n" "Benchmark" "RSS(+ is better)" "Perf(+ is better)" fi run-suite "${BENCH_FOLDER}" mem_rel_gmean=$(echo "$mem_rel_mult" "$mem_n" | awk '{print $1 ^ (1.0 / $2);}') mem_percent_gmean=$(echo "$mem_rel_gmean" | awk '{print (1.0 - $1) * 100;}') if [[ $mem_rel_inaccuracy_tmp != "-1" ]] then exit_err "Incorrect inaccuracy calculation for memory consumption geometric mean" fi perf_rel_gmean=$(echo "$perf_rel_mult" "$perf_n" | awk '{print $1 ^ (1.0 / $2);}') perf_percent_gmean=$(echo "$perf_rel_gmean" | awk '{print (1.0 - $1) * 100;}') if [[ "$perf_rel_inaccuracy_tmp" == "-1" ]] then exit_err "Incorrect inaccuracy calculation for performance geometric mean" else perf_percent_inaccuracy=$(echo "$perf_rel_gmean $perf_rel_inaccuracy_tmp $perf_n" | \ awk "{ perf_rel_gmean=\$1 perf_rel_inaccuracy_tmp=\$2 perf_n=\$3 print 100.0 * (perf_rel_gmean ^ (1.0 / perf_n) * sqrt (perf_rel_inaccuracy_tmp) / perf_n) }") perf_ext=$(echo "$perf_percent_gmean $perf_percent_inaccuracy" | \ awk "{ perf_percent_gmean=\$1 perf_percent_inaccuracy=\$2 if (perf_percent_gmean > 0.0 && perf_percent_gmean > perf_percent_inaccuracy) { print \"[+]\" } else if (perf_percent_gmean < 0 && -perf_percent_gmean > perf_percent_inaccuracy) { print \"[-]\" } else { print \"[$APPROXIMATELY_EQUAL]\" } }") perf_percent_inaccuracy=$(printf "(+-%0.3f%%) : $perf_ext" $perf_percent_inaccuracy) fi gmean_label_text="Geometric mean:" if [ "${OUTPUT_FORMAT}" == "-m" ] then mem_percent_gmean_text=$(printf "RSS reduction: \`%0.3f%%\`" "$mem_percent_gmean") perf_percent_gmean_text=$(printf "Speed up: \`%0.3f%% %s\`" "$perf_percent_gmean" "$perf_percent_inaccuracy") printf "%s | %s | %s\n" "$gmean_label_text" "$mem_percent_gmean_text" "$perf_percent_gmean_text" >> "${OUTPUT_FILE}" fi mem_percent_gmean_text=$(printf "RSS reduction: %0.3f%%" "$mem_percent_gmean") perf_percent_gmean_text=$(printf "Speed up: %0.3f%% %s" "$perf_percent_gmean" "$perf_percent_inaccuracy") printf "%50s | %25s | %51s\n" "$gmean_label_text" "$mem_percent_gmean_text" "$perf_percent_gmean_text" date