#!/usr/bin/env zsh

# minasm timings - timing summary on stdout, full logs on stderr.
#
# Note: -march=native does not exist for all GCC targets. For such targets,
# it is recommended to try various optimization-related options.
#
# Copyright (C) 2012 Vincent Lefevre <vincent@vinc17.net>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see http://www.gnu.org/licenses/
# or write to the Free Software Foundation, Inc., 51 Franklin St,
# Fifth Floor, Boston, MA 02110-1301, USA.

set -ex

prec=12
n=${1:-1}
: Compiler: ${CC:=gcc}
: Flags: ${CFLAGS:=-O3 -march=native -std=c99}

dir=/tmp/run-cc-tminasm-$USER-$$
mkdir $dir
[[ -O $dir ]]
cp minasm.c $dir/minasm.c
cp table-template $dir/table
pushd $dir

cleanup()
{
  popd
  rm -rf $dir
}

$CC --version | head -n 1 | tee res >&2

trap 'echo; cat res table; cleanup' 0 HUP INT TERM

alias compile="$CC $CFLAGS minasm.c -o minasm"

median()
{
  printf "%.2f" $(( ( $*[$((($#+1)/2))] + $*[$((($#+2)/2))] ) / 2 ))
}

run-minasm()
{
  local exit_status
  # Do not use the following code as it hides some output and errors.
  # rm -f time.out
  # {
  #   { time ./minasm 1 "$@" > minasm.out 2>&3 } 2>&1 | \
  #     sed -n 's/.* \([0-9]*\.[0-9][0-9]\)s user.*/\1/p' > time.out
  # } 3>&2
  # time=$(<time.out)
  { time ./minasm 1 "$@" > minasm.out || exit_status=$? } 2> time.out
  { cat time.out; [[ -n $exit_status ]] && exit $exit_status } 2> /dev/null
  time=$(sed -n 's/.* \([0-9]*\.[0-9][0-9]\)s user.*/\1/p' time.out)
  if test -f minasm-$1; then
    cmp minasm-$1 minasm.out
  else
    mv minasm.out minasm-$1
  fi
}

tminasm()
{
  local time2 time4 time6
  repeat $n
  do
    run-minasm 2 6 "$@"
    time2=($time2 $time)
    run-minasm 4 6 "$@"
    time4=($time4 $time)
    run-minasm 6 5 "$@"
    time6=($time6 $time)
  done
  for i in 2 4 6
  do
    local -a ts
    ts=(${(Pon)$(echo time$i)})
    med=$(median $ts)
    echo "[$m $i g=$g] $med ($ts)" >> res
    alias cmd="printf %${s}s"
    sed "/1 $i [0-9]  $g/ s/$(cmd)/$(cmd $med)/" table > table.new
    mv table.new table
  done
}

tst()
{
  : -================================================================-
  if test "x$1" = x-DMPFR; then arg=$prec; else unset arg; fi
  compile "$@"
  g=-
  tminasm $arg
  : ------------------------------------------------------------
  rm -f minasm.gcda
  compile "$@" -fprofile-generate
  ./minasm 0 2 6 $arg > /dev/null 2> /dev/null
  compile "$@" -fprofile-use
  g=2
  tminasm $arg
  : ------------------------------------------------------------
  rm -f minasm.gcda
  compile "$@" -fprofile-generate
  ./minasm 0 4 5 $arg > /dev/null 2> /dev/null
  compile "$@" -fprofile-use
  g=4
  tminasm $arg
  : ------------------------------------------------------------
  rm -f minasm.gcda
  compile "$@" -fprofile-generate
  ./minasm 0 6 5 $arg > /dev/null 2> /dev/null
  compile "$@" -fprofile-use
  g=6
  tminasm $arg
}

m=double
s=6
tst -lm
m=MPFR
s=9
tst -DMPFR -lmpfr -lgmp
m=SIPE0
s=10
tst -DSIPE=$prec
m=SIPE1
s=10
tst -DSIPE=$prec -DSIPE_ROUND_ZOPT

# $Id: run-cc-tminasm 56954 2012-12-11 15:07:51Z vinc17/ypig $
