Skip to content

Commit

Permalink
Add bench.sh and aeson-benchmark-suite
Browse files Browse the repository at this point in the history
- bench.sh is the runner and comparator for benchmarks we have.
- The idea is to migrate all benchmarks we have into
  `aeson-benchmark-suite`
- I added `criterion-compare-txt` to output textual tables,
  these are easier to copy into pull request etc.
- Added GitHub issues example, we still need more.
  • Loading branch information
phadej committed Apr 13, 2020
1 parent 299293c commit c321210
Show file tree
Hide file tree
Showing 27 changed files with 2,892 additions and 309 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
dist
dist-newstyle
.ghc.environment.*
cabal.project.local
.cabal-sandbox/
cabal.sandbox.config
.stack-work/
.stack-work-bench/
*.yaml.lock
.bench-results

*.o
*.hi
Expand Down
13 changes: 11 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,20 @@ install:
- |
echo "packages: ." >> cabal.project
echo "packages: attoparsec-iso8601" >> cabal.project
echo "packages: examples" >> cabal.project
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package aeson' >> cabal.project ; fi
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package attoparsec-iso8601' >> cabal.project ; fi
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package aeson-examples' >> cabal.project ; fi
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
- |
- "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(aeson|attoparsec-iso8601)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
- "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(aeson|aeson-examples|attoparsec-iso8601)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
- cat cabal.project || true
- cat cabal.project.local || true
- if [ -f "./configure.ac" ]; then (cd "." && autoreconf -i); fi
- if [ -f "attoparsec-iso8601/configure.ac" ]; then (cd "attoparsec-iso8601" && autoreconf -i); fi
- if [ -f "examples/configure.ac" ]; then (cd "examples" && autoreconf -i); fi
- ${CABAL} v2-freeze $WITHCOMPILER ${TEST} ${BENCH}
- "cat cabal.project.freeze | sed -E 's/^(constraints: *| *)//' | sed 's/any.//'"
- rm cabal.project.freeze
Expand All @@ -134,18 +138,22 @@ script:
- find . -maxdepth 1 -type f -name '*.tar.gz' -exec rm '{}' \;
- PKGDIR_aeson="$(find . -maxdepth 1 -type d -regex '.*/aeson-[0-9.]*')"
- PKGDIR_attoparsec_iso8601="$(find . -maxdepth 1 -type d -regex '.*/attoparsec-iso8601-[0-9.]*')"
- PKGDIR_aeson_examples="$(find . -maxdepth 1 -type d -regex '.*/aeson-examples-[0-9.]*')"
# Generate cabal.project
- rm -rf cabal.project cabal.project.local cabal.project.freeze
- touch cabal.project
- |
echo "packages: ${PKGDIR_aeson}" >> cabal.project
echo "packages: ${PKGDIR_attoparsec_iso8601}" >> cabal.project
echo "packages: ${PKGDIR_aeson_examples}" >> cabal.project
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package aeson' >> cabal.project ; fi
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package attoparsec-iso8601' >> cabal.project ; fi
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
- if [ $HCNUMVER -ge 80200 ] ; then echo 'package aeson-examples' >> cabal.project ; fi
- "if [ $HCNUMVER -ge 80200 ] ; then echo ' ghc-options: -Werror=missing-methods' >> cabal.project ; fi"
- |
- "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(aeson|attoparsec-iso8601)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
- "for pkg in $($HCPKG list --simple-output); do echo $pkg | sed 's/-[^-]*$//' | (grep -vE -- '^(aeson|aeson-examples|attoparsec-iso8601)$' || true) | sed 's/^/constraints: /' | sed 's/$/ installed/' >> cabal.project.local; done"
- cat cabal.project || true
- cat cabal.project.local || true
# Building...
Expand All @@ -159,6 +167,7 @@ script:
# HLint..
- if [ $HCNUMVER -ge 80800 ] && [ $HCNUMVER -lt 81000 ] ; then (cd ${PKGDIR_aeson} && hlint -h ${TOP}/.hlint.yaml . attoparsec-iso8601/ pure ffi) ; fi
- if [ $HCNUMVER -ge 80800 ] && [ $HCNUMVER -lt 81000 ] ; then (cd ${PKGDIR_attoparsec_iso8601} && hlint -h ${TOP}/.hlint.yaml .) ; fi
- if [ $HCNUMVER -ge 80800 ] && [ $HCNUMVER -lt 81000 ] ; then (cd ${PKGDIR_aeson_examples} && hlint -h ${TOP}/.hlint.yaml src/) ; fi
# haddock...
- if [ $HCNUMVER -ge 80600 ] ; then ${CABAL} v2-haddock $WITHCOMPILER --with-haddock $HADDOCK ${TEST} ${BENCH} all ; fi
# Building without installed constraints for packages in global-db...
Expand Down
27 changes: 21 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,20 +99,35 @@ Of course before submitting a PR, the following steps are recommended:

### Running benchmarks

You need to install `cabal-plan` and `criterion-compare` with
You need to install `cabal-plan`:

```
cabal install cabal-plan criterion-compare
cabal install cabal-plan
```
Then to build benchmarks we use a different project, which builds
`aeson` as a package with a different name to avoid rebuilding `criterion`
etc tools all the time:
etc tools all the time. There is a helper script which usage
can be as simple as:
```
cabal build --project-file cabal.bench.project all
git checkout master
./bench.sh run -n master
git checkout your-branch
./bench.sh run -n your-branch
./bench.sh compare master your-branch
```
Then to run benchmarks
which will output a table like
... to be completed
```
Benchmark master your-branch
Examples/decode/github-issues/lazy 1.77e-3 1.76e-3 -0.68%
Examples/decode/github-issues/strict 1.75e-3 1.69e-3 -3.29%
Examples/decode/jp100/lazy 1.97e-3 1.98e-3 +0.43%
Examples/decode/jp100/strict 1.94e-3 1.96e-3 +1.10%
Examples/decode/twitter100/lazy 1.54e-3 1.59e-3 +2.98%
Examples/decode/twitter100/strict 1.51e-3 1.51e-3 -0.20%
```
Run `./bench.sh help` for more details.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2011, MailRank, Inc.
Copyright (c) 2011, MailRank, Inc. 2014-2020 Aeson project contributors

All rights reserved.

Expand Down
3 changes: 0 additions & 3 deletions aeson.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ extra-source-files:
benchmarks/json-data/*.json
cbits/*.c
changelog.md
examples/*.cabal
examples/*.hs
examples/Twitter/*.hs
ffi/Data/Aeson/Parser/*.hs
include/*.h
tests/JSONTestSuite/test_parsing/*.json
Expand Down
246 changes: 246 additions & 0 deletions bench.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
#!/bin/sh

# Aeson Benchmark Runner
#######################################################################

# Configuration
#######################################################################

HC=ghc
SAVENAME="auto-$(git rev-parse --short HEAD)"
CONFIDENCE=0.99
RUNS=""
PATTERN=""

AESON_BENCH_DATADIR="benchmarks/json-data"
export AESON_BENCH_DATADIR

# usage
#######################################################################

usage() {
cat <<EOF
./bench.sh - Aeson benchmark runner
Usage: ./bench.sh [help|run|compare] [options]
help - print this message
-------------------------
./bench.sh help
run - run a benchmark suite
---------------------------
./bench.sh run [options]
Options:
-w HC, --with-compiler HC Compiler to use
-n NAME, --name NAME Name to save benchmark results as (current: $SAVENAME)
-p PATTERN, --pattern PATTERN Which benchmarks to run
--confidence CI Confidence interval (default: $CONFIDENCE)
build - only build a benchmark suite
-----------------------------------
./bench.sh build [options]
Options:
-w HC, --with-compiler HC Compiler to use
EOF
}

# "library"
#######################################################################

RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
CYAN='\033[0;96m'
RESET='\033[0m' # No Color

putError() {
echo "${RED}ERROR:${RESET} $*"
}

putInfo() {
echo "${CYAN}INFO:${RESET} $*"
}

command() {
echo "${BLUE}RUN:${RESET} $*"
"$@"
exitcode=$?
if [ $exitcode -ne 0 ]; then
echo "${RED}FAIL:${RESET} $*"
exit 1
fi
}

# build
#######################################################################

cmdBuild() {
# Argument parsing

while [ $# -gt 0 ]; do
arg=$1
case $arg in
-w|--with-compiler)
HC=$2
shift
shift
;;
*)
putError "Unknown argument '$1'"
usage
exit 1
;;
esac
done

# Checking existence of tools
putInfo "Checking tools"
command cabal --version

# Building
putInfo "Building benchmarks"

command cabal build --project-file cabal.bench.project -w "$HC" aeson-benchmark-suite criterion-compare-txt
}

# run
#######################################################################

cmdRun() {
# Argument parsing

while [ $# -gt 0 ]; do
arg=$1
case $arg in
-w|--with-compiler)
HC="$2"
shift
shift
;;
-n|--name)
SAVENAME="$2"
shift
shift
;;
-p|--pattern)
PATTERN="$2"
shift
shift
;;
--confidence)
CONFIDENCE="$2"
shift
shift
;;
*)
putError "Unknown argument '$1'"
usage
exit 1
;;
esac
done

CSV=".bench-results/${SAVENAME}.csv"
if [ -f "$CSV" ]; then
putError "$CSV already exists, aborting..."
exit 1
fi

# Checking if the target file exits

# Checking existence of tools
putInfo "Checking tools"
command cabal --version
command cabal-plan --version

# Building
putInfo "Building benchmarks"
command cabal build --project-file cabal.bench.project -w "$HC" aeson-benchmark-suite

# Running
putInfo "Running benchmarks: $SAVENAME"
command mkdir -p .bench-results
command "$(cabal-plan list-bin aeson-benchmark-suite)" --csv "$CSV" --ci "$CONFIDENCE" -m pattern "$PATTERN"
}

# compare
#######################################################################

cmdCompare() {
# Argument parsing

while [ $# -gt 0 ]; do
arg=$1
case $arg in
-w|--with-compiler)
HC=$2
shift
shift
;;
-n|--name)
SAVENAME=$2
shift
shift
;;
*)
RUNS="$RUNS $1"
shift
;;
esac
done

# Building
putInfo "Building criterion-compare-txt"
command cabal build --project-file cabal.bench.project -w "$HC" criterion-compare-txt

# Comparing th eresults
putInfo "Comparing runs:$RUNS"

# Map runs to CVS files
CSV=""
for run in $RUNS; do
CSV="$CSV .bench-results/${run}.csv"
done

# shellcheck disable=SC2086
command "$(cabal-plan list-bin criterion-compare-txt)" $CSV
}

# main
#######################################################################

if [ $# -le 0 ]; then
usage
exit 1
fi

case $1 in
run)
shift;
cmdRun "$@"
;;
compare)
shift;
cmdCompare "$@"
;;
build)
shift;
cmdBuild "$@"
;;
help)
usage
;;
*)
putError "Unknown command '$1'"
usage
exit 1
;;
esac
Loading

0 comments on commit c321210

Please sign in to comment.