Stabilise benchmarks wrt. GC
[nofib.git] / README.md
1 # NoFib: Haskell Benchmark Suite
2
3 This is the root directory of the "NoFib Haskell benchmark suite". It
4 should be part of a GHC source tree, that is the 'nofib' directory
5 should be at the same level in the tree as 'compiler' and 'libraries'.
6 This makes sure that NoFib picks up the stage 2 compiler from the
7 surrounding GHC source tree.
8
9 You can also clone this repository in isolation, in which case it will
10 pick `$(which ghc)` or whatever the `HC` environment variable is set to.
11
12 Additional information can also be found on
13 [NoFib's wiki page](https://ghc.haskell.org/trac/ghc/wiki/Building/RunningNoFib).
14
15 ## Package Depedencies
16
17 Please make sure you have the following packages installed for your
18 system GHC:
19  * html
20  * regex-compat (will install: mtl, regex-base, regex-posix)
21
22 ## Using
23
24 Then, to run the tests, execute:
25
26 ```
27 $ make clean # or git clean -fxd, it's faster
28 $ # Generates input files for the benchmarks and builds compilation
29 $ # dependencies for make (ghc -M)
30 $ make boot
31 $ # Builds the benchmarks and runs them $NoFibRuns (default: 5) times
32 $ make
33 ```
34
35 This will put the results in the file `nofib-log`. You can pass extra
36 options to a nofib run using the `EXTRA_HC_OPTS` variable like this:
37
38 ```
39 $ make clean
40 $ make boot
41 $ make EXTRA_HC_OPTS="-fllvm"
42 ```
43
44 To compare the results of multiple runs, save the output in a logfile
45 and use the program in `../utils/nofib-analyse`, for example:
46
47 ```
48 ...
49 $ make 2>&1 | tee nofib-log-6.4.2
50 ...
51 $ make 2>&1 | tee nofib-log-6.6
52 $ nofib-analyse nofib-log-6.4.2 nofib-log-6.6 | less
53 ```
54
55 to generate a comparison of the runs in captured in `nofib-log-6.4.2`
56 and `nofib-log-6.6`. When making comparisons, be careful to ensure
57 that the things that changed between the builds are only the things
58 that you _wanted_ to change. There are lots of variables: machine,
59 GHC version, GCC version, C libraries, static vs. dynamic GMP library,
60 build options, run options, and probably lots more. To be on the safe
61 side, make both runs on the same unloaded machine.
62
63 ## Modes
64
65 Each benchmark is runnable in three different time `mode`s:
66
67 - `fast`: 0.1-0.2s
68 - `norm`: 1-2s
69 - `slow`: 5-10s
70
71 You can control which mode to run by setting an additional `mode` variable for
72 `make`. The default is `mode=norm`. Example for `mode=fast`:
73
74 ```
75 $ make clean
76 $ make boot mode=fast
77 $ make mode=fast
78 ```
79
80 Note that the `mode`s set in `make boot` and `make` need to agree. Otherwise you
81 will get output errors, because `make boot` will generate input files for a
82 different `mode`. A more DRY way to control the `mode` would be
83
84 ```
85 $ make clean
86 $ export mode=fast
87 $ make boot
88 $ make
89 ```
90
91 As CPU architectures advance, the above running times may drift and
92 occasionally, all benchmarks will need adjustments.
93
94 Be aware that `nofib-analyse` will ignore the result if it falls below 0.2s.
95 This is the default of its `-i` option, which is of course incompatible with
96 `mode=fast`. In that case, you should just set `-i` as appropriate, even
97 deactivate it with `-i 0`.
98
99 ## Configuration
100
101 There are some options you might want to tweak; search for nofib in
102 `../mk/config.mk`, and override settings in `../mk/build.mk` as usual.
103
104 ## Extra Metrics: Valgrind
105
106 To get instruction counts, memory reads/writes, and "cache misses",
107 you'll need to get hold of Cachegrind, which is part of
108 [Valgrind](http://valgrind.org).
109
110 You can then pass `-cachegrind` as `EXTRA_RUNTEST_OPTS`. Counting
111 instructions slows down execution by a factor of ~30. But it's
112 a deterministic metric, so you can combine it with `NoFibRuns=1`:
113
114 ```
115 $ (make EXTRA_RUNTEST_OPTS="-cachegrind" NoFibRuns=1) 2>&1 | tee nofib-log
116 ```
117
118 Optionally combine this with `mode=fast`, see [Modes](#modes).
119
120 ## Extra Packages
121
122 Some benchmarks aren't run by default and require extra packages are
123 installed for the GHC compiler being tested. These packages include:
124  * stm - for smp benchmarks
125
126 ## Adding benchmarks
127
128 If you add a benchmark try to set the problem sizes for
129 fast/normal/slow reasonably. [Modes](#modes) lists the recommended brackets for
130 each mode.
131
132 ### Stability wrt. GC paramerisations
133
134 Additionally, pay attention that your benchmarks are stable wrt. different 
135 GC paramerisations, so that small changes in allocation don't lead to big,
136 unexplicable jumps in performance. See Trac #15999 for details. Also make sure
137 that you run the benchmark with the default GC settings, as enlarging Gen 0 or
138 Gen 1 heaps just amplifies the problem.
139
140 As a rule of thumb on how to ensure this: Make sure that your benchmark doesn't
141 just build up one big data and consume it in a final step, but rather that the
142 working set grows and shrinks (e.g. is approximately constant) over the whole
143 run of the benchmark. You can ensure this by iterating your main logic $n times
144 (how often depends on your program, but in the ball park of 100-1000).
145 You can test stability by plotting productivity curves for your `fast` settings
146 with the `prod.py` script attached to Trac #15999.
147
148 If in doubt, ask Sebastian Graf for help.