87 lines
3.5 KiB
Bash
Executable File
87 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# The speed half of cost.sh, on programs that are long enough to time.
|
|
#
|
|
# Why this exists beside cost.sh rather than inside it: every program in
|
|
# test/programs runs in about two and a half milliseconds, of which nearly
|
|
# all is fork, exec and the dynamic loader. Best-of-five does not rescue a
|
|
# signal that is not there, and a table of 97 rows that all say "2.5ms vs
|
|
# 2.6ms" would be a measurement of execve. So the corpus answers the size
|
|
# question and these four answer the speed one, each written so that one
|
|
# suspected cost is most of what the program does.
|
|
#
|
|
# Four builds of each, and the third column is the one to read:
|
|
#
|
|
# llvm as shipped, -O2. Frequently the loop is simply gone; that is a
|
|
# true number about the toolchain and a useless one about codegen.
|
|
# llvm -O0 via --debug, which forces it. LLVM's instruction selection with
|
|
# its optimiser off -- the fair comparison for a backend that has
|
|
# no optimiser.
|
|
# x86 this backend.
|
|
# x86 nbc --no-bounds-checks, for b2, where the difference is the check.
|
|
#
|
|
# And --dev on both sides, which is the one suspected cost the two backends
|
|
# share: every cross-function call goes through an indirection cell, so it is
|
|
# a load and an indirect call where a release build has a direct one. b1 is
|
|
# where that has to show.
|
|
#
|
|
# Usage: spike/x86/bench.sh [name-substring ...]
|
|
set -u
|
|
orig=$(pwd)
|
|
here=$(cd "$(dirname "$0")" && pwd)
|
|
root=$(cd "$here/../.." && pwd)
|
|
cd "$root" || exit 1
|
|
|
|
if [ -n "${FLAN:-}" ]; then
|
|
case $FLAN in /*) flan=$FLAN;; *) flan=$orig/$FLAN;; esac
|
|
else
|
|
dune build --root . bin/main.exe 2>&1 | head -30
|
|
flan=$root/_build/default/bin/main.exe
|
|
fi
|
|
test -x "$flan" || { echo "build failed" >&2; exit 1; }
|
|
|
|
out=${COST_OUT:-${TMPDIR:-/tmp}/flan-bench.$$}
|
|
mkdir -p "$out" || exit 1
|
|
trap 'rm -rf "$out"' EXIT
|
|
|
|
REPS=${COST_REPS:-5}
|
|
|
|
best () {
|
|
min=
|
|
for i in $(seq "$REPS"); do
|
|
t0=$(date +%s%N)
|
|
timeout 120 "$1" >/dev/null 2>&1 </dev/null
|
|
t1=$(date +%s%N)
|
|
d=$(( (t1 - t0) / 1000 ))
|
|
if [ -z "$min" ] || [ "$d" -lt "$min" ]; then min=$d; fi
|
|
done
|
|
echo "$min"
|
|
}
|
|
|
|
own () {
|
|
nm --defined-only -S "$1" 2>/dev/null \
|
|
| awk 'NF==4 && ($3=="T"||$3=="t") && $4 ~ /^flan\./ {n+=strtonum("0x"$2)} END{print n+0}'
|
|
}
|
|
|
|
printf 'name\tllvm_us\to0_us\tx86_us\tllvm_nbc_us\tx86_nbc_us\tllvm_dev_us\tx86_dev_us\tllvm_own\to0_own\tx86_own\tx86_dev_own\n'
|
|
|
|
for src in "$root"/spike/x86/bench/*.flan; do
|
|
name=$(basename "$src" .flan)
|
|
if [ $# -gt 0 ]; then
|
|
want=0
|
|
for pat in "$@"; do case "$name" in *"$pat"*) want=1;; esac; done
|
|
[ $want = 1 ] || continue
|
|
fi
|
|
"$flan" build "$src" -o "$out/l" >/dev/null 2>&1 || { echo "$name: llvm build failed" >&2; continue; }
|
|
"$flan" build "$src" --debug -o "$out/d" >/dev/null 2>&1 || { echo "$name: -O0 build failed" >&2; continue; }
|
|
"$flan" build "$src" --x86 -o "$out/x" >/dev/null 2>&1 || { echo "$name: x86 build failed" >&2; continue; }
|
|
"$flan" build "$src" --no-bounds-checks -o "$out/ln" >/dev/null 2>&1
|
|
"$flan" build "$src" --x86 --no-bounds-checks -o "$out/xn" >/dev/null 2>&1
|
|
"$flan" build "$src" --dev -o "$out/lv" >/dev/null 2>&1
|
|
"$flan" build "$src" --x86 --dev -o "$out/xv" >/dev/null 2>&1
|
|
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' "$name" \
|
|
"$(best "$out/l")" "$(best "$out/d")" "$(best "$out/x")" \
|
|
"$(best "$out/ln")" "$(best "$out/xn")" \
|
|
"$(best "$out/lv")" "$(best "$out/xv")" \
|
|
"$(own "$out/l")" "$(own "$out/d")" "$(own "$out/x")" "$(own "$out/xv")"
|
|
done
|