Skip to content

Commit 2dbf8c9

Browse files
authored
Add code coverage using bisect_ppx (oxcaml#352)
1 parent fd1e3c8 commit 2dbf8c9

File tree

28 files changed

+187
-5
lines changed

28 files changed

+187
-5
lines changed

.github/workflows/coverage.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: coverage-linux
2+
on: [push, pull_request]
3+
jobs:
4+
build:
5+
name: ${{ matrix.name }}
6+
runs-on: ubuntu-latest
7+
8+
strategy:
9+
fail-fast: false
10+
matrix:
11+
include:
12+
- name: flambda2_coverage
13+
config: --enable-middle-end=flambda2 --enable-coverage
14+
ocamlparam: ''
15+
16+
env:
17+
J: "3"
18+
19+
steps:
20+
- name: Checkout the Flambda backend repo
21+
uses: actions/checkout@master
22+
with:
23+
path: 'flambda_backend'
24+
25+
# This adds a switch at $GITHUB_WORKSPACE/_opam
26+
- name: Set up OCaml 4.12
27+
uses: ocaml/setup-ocaml@v2
28+
with:
29+
ocaml-compiler: 4.12
30+
opam-pin: false
31+
opam-depext: false
32+
33+
- name: Get host build environment from cache
34+
uses: actions/cache@v1
35+
id: cache
36+
with:
37+
path: ${{ github.workspace }}/_opam
38+
key: ${{ matrix.os }}-cache-ocaml-412-dune-2.9.1-g7606d586
39+
40+
- name: Build Dune
41+
if: steps.cache.outputs.cache-hit != 'true'
42+
run: |
43+
opam pin dune --yes \
44+
git+https://github.com/ocaml-flambda/dune#special_dune
45+
46+
- name: Build bisect_ppx
47+
if: steps.cache.outputs.cache-hit != 'true'
48+
run: |
49+
# bisect_ppx fails to build with current ppxlib
50+
opam pin ppxlib 0.23.0 --yes
51+
opam pin bisect_ppx --yes \
52+
git+https://github.com/lukemaurer/bisect_ppx#html-report-collate-fix
53+
54+
- name: Trim cached files
55+
if: steps.cache.outputs.cache-hit != 'true'
56+
run: |
57+
# Remove unneeded parts to shrink cache file
58+
rm -rf _opam/{lib/ocaml/expunge,bin/*.byte}
59+
60+
- name: Configure Flambda backend
61+
working-directory: flambda_backend
62+
run: |
63+
autoconf
64+
./configure \
65+
--prefix=$GITHUB_WORKSPACE/_install \
66+
--with-dune=$GITHUB_WORKSPACE/_opam/bin/dune \
67+
${{ matrix.config }}
68+
69+
70+
- name: Build, install and test Flambda backend
71+
working-directory: flambda_backend
72+
run: opam exec -- make ci
73+
env:
74+
BUILD_OCAMLPARAM: ${{ matrix.ocamlparam }}
75+
76+
- name: Publish coverage report
77+
uses: actions/upload-artifact@v3
78+
with:
79+
name: coverage
80+
path: flambda_backend/_coverage/**

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ _compare/
4343
_runtest/
4444
autom4te.cache
4545
_install/
46+
_coverage/
4647

4748
/Makefile.config
4849
/config.log

HACKING.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ want to modify the Flambda backend. Jump to:
99
- [Rebuilding during dev work](#rebuilding-during-dev-work)
1010
- [Running tests](#running-tests)
1111
- [Running only part of the upstream testsuite](#running-only-part-of-the-upstream-testsuite)
12+
- [Running tests with coverage analysis](#running-tests-with-coverage-analysis)
1213
- [Running the compiler produced by "make hacking" on an example without the stdlib](#running-the-compiler-produced-by-make-hacking-on-an-example-without-the-stdlib)
1314
- [Getting the compilation command for a stdlib file](#getting-the-compilation-command-for-a-stdlib-file)
1415
- [Bootstrapping the ocaml subtree](#bootstrapping-the-ocaml-subtree)
@@ -134,6 +135,27 @@ where `<FLAMBDA_BACKEND>` is the path to your clone.
134135
You may also need the `CAML_LD_LIBRARY_PATH` setting depending on what you are testing (see `Makefile.in` at the
135136
root).
136137

138+
## Running tests with coverage analysis
139+
140+
Coverage analysis is available for the Flambda backend tests (that is, just the
141+
ones run by `make runtest`), which are intended to provide good coverage on
142+
their own. We use `bisect_ppx` to perform the analysis. Since binaries
143+
instrumented with `bisect_ppx` have coverage enabled unconditionally, coverage
144+
support is disabled by default at compile time.
145+
146+
Coverage requires the `bisect_ppx` package to be installed in your OPAM switch.
147+
Since no OPAM environment is available when building the final compiler, we
148+
instead enable coverage on the boot compiler and run the tests directly on the
149+
boot compiler.
150+
151+
To enable coverage, pass the `--enable-coverage` flag to `./configure`.
152+
(Remember to clean, as by `git clean -dfX`, whenever re-running
153+
`./configure`). When coverage is enabled, `make boot-runtest` will
154+
run the tests on the boot compiler and produce coverage data, and
155+
`make coverage` will produce an HTML report in `_coverage/`. Alternatively,
156+
with coverage enabled, `make ci` will build the boot compiler, run the
157+
tests, and produce the report.
158+
137159
## Running the compiler produced by "make hacking" on an example without the stdlib
138160

139161
For small examples that don't need the stdlib or any other library provided by the

Makefile

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ ws_boot = --root=. --workspace=duneconf/boot.ws
77
ws_runstd = --root=. --workspace=duneconf/runtime_stdlib.ws
88
ws_main = --root=. --workspace=duneconf/main.ws
99

10+
ifeq ($(coverage),yes)
11+
coverage_dune_flags=--instrument-with bisect_ppx
12+
ocaml_subdirs_to_ignore=otherlibs
13+
else
14+
coverage_dune_flags=
15+
ocaml_subdirs_to_ignore=
16+
endif
17+
1018
define dune_boot_context
1119
(lang dune 2.8)
1220
; We need to call the boot context "default" so that dune selects it for merlin
@@ -42,15 +50,18 @@ endef
4250

4351

4452
.DEFAULT_GOAL := compiler
45-
.PHONY: boot-compiler runtime-stdlib compiler runtest
53+
.PHONY: boot-compiler boot-runtest runtime-stdlib compiler runtest
4654

4755
boot-compiler: _build/_bootinstall
48-
$(dune) build $(ws_boot) \
56+
$(dune) build $(ws_boot) $(coverage_dune_flags) \
4957
boot_ocamlopt.exe \
5058
ocaml/main_native.exe \
5159
ocaml/tools/ocamlmklib_native.exe \
5260
ocaml/tools/ocamldep_native.exe
5361

62+
boot-runtest: boot-compiler
63+
$(dune) runtest $(ws_boot) $(coverage_dune_flags) --force
64+
5465
runtime-stdlib: boot-compiler
5566
$(dune) build $(ws_runstd) --only-package=ocaml_runtime_stdlib @install
5667
# dune does not believe the compiler can make .cmxs unless the following file exists
@@ -71,7 +82,19 @@ duneconf/main.ws: export contents = $(dune_main_context)
7182
duneconf/%.ws:
7283
echo "$$contents" > $@
7384

74-
_build/_bootinstall: ocaml/Makefile.config duneconf/boot.ws duneconf/runtime_stdlib.ws duneconf/main.ws
85+
# We need to disable ocaml/otherlibs when compiling with coverage, because we
86+
# need to compile against the user's opam instead. Unfortunately, Dune gives us
87+
# no nicer way of declaring data_only_dirs differently in different workspaces,
88+
# so we have to output a file to be included in ocaml/dune.
89+
#
90+
# Also, Dune only allows one (data_only_dirs) declaration per file, so here we
91+
# have to account for the declaration that would already have been in
92+
# ocaml/dune.
93+
ocaml/dirs-to-ignore.inc:
94+
echo "(data_only_dirs yacc $(ocaml_subdirs_to_ignore))" > $@
95+
96+
_build/_bootinstall: ocaml/Makefile.config duneconf/boot.ws duneconf/runtime_stdlib.ws duneconf/main.ws \
97+
ocaml/dirs-to-ignore.inc
7598

7699
# natdynlinkops2:
77100
# We need to augment dune's substitutions so this part isn't so
@@ -267,7 +290,17 @@ runtest-upstream: _install
267290
fi)
268291

269292
.PHONY: ci
270-
ci: runtest runtest-upstream
293+
ifeq ($(coverage),yes)
294+
ci: ci-coverage
295+
else
296+
ci: ci-no-coverage
297+
endif
298+
299+
.PHONY: ci-no-coverage
300+
ci-no-coverage: runtest runtest-upstream
301+
302+
.PHONY: ci-coverage
303+
ci-coverage: boot-runtest coverage
271304

272305
# This target is like a polling version of upstream "make ocamlopt"
273306
.PHONY: hacking
@@ -389,3 +422,12 @@ build_upstream: ocaml/config.status
389422
install_upstream: build_upstream
390423
(cd _build_upstream && $(MAKE) install)
391424
cp ocaml/VERSION $(prefix)/lib/ocaml/
425+
426+
.PHONY: coverage
427+
coverage: boot-runtest
428+
rm -rf _coverage
429+
bisect-ppx-report html --tree -o _coverage \
430+
--coverage-path=_build/default \
431+
--source-path=. \
432+
--source-path=_build/default
433+
@echo Coverage report generated in _coverage/index.html

Makefile.config.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
install_prefix = @prefix@
22
dune = @dune@
33
middle_end = @middle_end@
4+
coverage = @coverage@

configure.ac

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,18 @@ AC_ARG_ENABLE([middle-end],
3636
[*], [AC_MSG_ERROR([Bad middle end (not closure, flambda or flambda2)])])],
3737
[AC_MSG_ERROR([--enable-middle-end=closure|flambda|flambda2 must be provided])])
3838

39+
AC_ARG_ENABLE([coverage],
40+
[AS_HELP_STRING([--enable-coverage],
41+
[Run compiler tests instrumented to output coverage data using bisect_ppx
42+
(WARNING: Cannot build an installable compiler with this flag enabled.
43+
Mainly intended for use in CI.)])],
44+
[coverage=yes],
45+
[coverage=no])
46+
3947
AC_SUBST([prefix])
4048
AC_SUBST([middle_end])
4149
AC_SUBST([dune])
50+
AC_SUBST([coverage])
4251

4352
# Don't error on options that this configure script doesn't understand but
4453
# the ocaml/ one does.

dune

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
(:standard -principal -w -9))
6767
(ocamlopt_flags
6868
(:include %{project_root}/ocamlopt_flags.sexp))
69+
(instrumentation (backend bisect_ppx))
6970
(modules_without_implementation
7071
backend_intf
7172
cmx_format
@@ -282,12 +283,14 @@
282283
))
283284
(ocamlopt_flags
284285
(:include %{project_root}/ocamlopt_flags.sexp))
286+
(instrumentation (backend bisect_ppx))
285287
(libraries ocamlcommon dwarf_flags asm_targets)
286288
(modules flambda_backend_args flambda_backend_flags))
287289

288290
(executable
289291
(name flambda_backend_main)
290292
(modes byte)
293+
(instrumentation (backend bisect_ppx))
291294
(flags (:standard -principal))
292295
(libraries
293296
flambda_backend_driver
@@ -307,6 +310,7 @@
307310
(executable
308311
(name flambda_backend_main_native)
309312
(modes native)
313+
(instrumentation (backend bisect_ppx))
310314
(flags
311315
(:standard -principal))
312316
(libraries
@@ -328,6 +332,7 @@
328332
(executable
329333
(name boot_ocamlopt)
330334
(modes native)
335+
(instrumentation (backend bisect_ppx))
331336
(flags
332337
(:standard -principal))
333338
(libraries

middle_end/flambda2/algorithms/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
(library
44
(name flambda2_algorithms)
55
(wrapped true)
6+
(instrumentation (backend bisect_ppx))
67
(flags
78
(:standard -principal))
89
(ocamlopt_flags

middle_end/flambda2/bound_identifiers/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
(library
44
(name flambda2_bound_identifiers)
55
(wrapped true)
6+
(instrumentation (backend bisect_ppx))
67
(flags
78
(:standard
89
-principal

middle_end/flambda2/cmx/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
(library
44
(name flambda2_cmx)
55
(wrapped true)
6+
(instrumentation (backend bisect_ppx))
67
(flags
78
(:standard
89
-principal

0 commit comments

Comments
 (0)