|
Criterion.Main | Portability | GHC | Stability | experimental | Maintainer | bos@serpentine.com |
|
|
|
|
|
Description |
Wrappers for compiling and running benchmarks quickly and easily.
See defaultMain below for an example.
|
|
Synopsis |
|
|
|
|
How to write benchmarks
|
|
The Benchmarkable typeclass represents the class of all code that
can be benchmarked. Every instance must run a benchmark a given
number of times. We are most interested in benchmarking two things:
- IO actions. Any IO action can be benchmarked directly.
- Pure functions. GHC optimises aggressively when compiling with
-O, so it is easy to write innocent-looking benchmark code that
doesn't measure the performance of a pure function at all. We
work around this by benchmarking both a function and its final
argument together.
|
|
Benchmarking IO actions
|
|
Any IO action can be benchmarked easily if its type resembles
this:
IO a
|
|
Benchmarking pure code
|
|
Because GHC optimises aggressively when compiling with -O, it is
potentially easy to write innocent-looking benchmark code that will
only be evaluated once, for which all but the first iteration of
the timing loop will be timing the cost of doing nothing.
To work around this, we provide a special type, Pure, for
benchmarking pure code. Values of this type are constructed using
one of two functions.
The first is a function which will cause results to be evaluated to
head normal form (NF):
nf :: NFData b => (a -> b) -> a -> Pure
The second will cause results to be evaluated to weak head normal
form (the Haskell default):
whnf :: (a -> b) -> a -> Pure
As both of these types suggest, when you want to benchmark a
function, you must supply two values:
- The first element is the function, saturated with all but its
last argument.
- The second element is the last argument to the function.
Here is an example that makes the use of these functions clearer.
Suppose we want to benchmark the following function:
firstN :: Int -> [Int]
firstN k = take k [(0::Int)..]
So in the easy case, we construct a benchmark as follows:
nf firstN 1000
The compiler will correctly infer that the number 1000 must have
the type Int, and the type of the expression is Pure.
|
|
Fully evaluating a result
|
|
The whnf harness for evaluating a pure function only evaluates
the result to weak head normal form (WHNF). If you need the result
evaluated all the way to normal form, use the nf function to
force its complete evaluation.
Using the firstN example from earlier, to naive eyes it might
appear that the following code ought to benchmark the production
of the first 1000 list elements:
whnf firstN 1000
Because in this case the result will only be forced until it
reaches WHNF, what this would actually benchmark is merely the
production of the first list element!
|
|
Types
|
|
class Benchmarkable a where | Source |
|
A benchmarkable function or action.
| | Methods | | :: a | The function or action to benchmark.
| -> Int | The number of times to run or evaluate it.
| -> IO () | | Run a function or action the specified number of times.
|
|
| | Instances | |
|
|
|
A benchmark may consist of either a single Benchmarkable item
with a name, created with bench, or a (possibly nested) group of
Benchmarks, created with bgroup.
| Instances | |
|
|
|
A container for a pure function to benchmark, and an argument to
supply to it each time it is evaluated.
| Instances | |
|
|
Constructing benchmarks
|
|
|
|
|
|
:: String | A name to identify the group of benchmarks.
| -> [Benchmark] | Benchmarks to group under this name.
| -> Benchmark | | Group several benchmarks together under a common name.
|
|
|
|
Apply an argument to a function, and evaluate the result to head
normal form (NF).
|
|
|
Perform an action, then evaluate its result to head normal form.
This is particularly useful for forcing a lazy IO action to be
completely performed.
|
|
|
Apply an argument to a function, and evaluate the result to weak
head normal form (WHNF).
|
|
Running benchmarks
|
|
|
An entry point that can be used as a main function.
import Criterion.Main
fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
main = defaultMain [
bgroup "fib" [ bench "fib 10" $ B fib 10
, bench "fib 35" $ B fib 35
, bench "fib 37" $ B fib 37
]
]
|
|
|
:: Config | | -> Criterion () | Prepare data prior to executing the first benchmark.
| -> [Benchmark] | | -> IO () | | An entry point that can be used as a main function, with
configurable defaults.
Example:
import Criterion.Config
import qualified Criterion.MultiMap as M
myConfig = defaultConfig {
-- Always display an 800x600 window with curves.
cfgPlot = M.singleton KernelDensity (Window 800 600)
}
main = defaultMainWith myConfig (return ()) [
bench "fib 30" $ B fib 30
]
If you save the above example as "Fib.hs", you should be able
to compile it as follows:
ghc -O --make Fib
Run "Fib --help" on the command line to get a list of command
line options.
|
|
|
Other useful code
|
|
|
The standard options accepted on the command line.
|
|
|
Parse command line options.
|
|
Produced by Haddock version 2.6.0 |