The line coverage library provides a means to ascertain exactly how many times individual clauses are called during the evaluation of a query.
The library works by placing coverage counters at strategic points throughout the code being analysed. These counters are incremented each time the evaluation of a query passes them. There are three locations in which coverage counters can be inserted.
|
Locations where coverage counters can be placed A code block is defined to be a conjunction of predicate calls. ie. a sequence of goals separated by commas.
As previously mentioned, by default, code coverage counters are inserted before and after every subgoal in the code. For instance, in the clause
p :- q, r, s. |
four counters would be inserted: before the call to q
, between
q
and r
, between r
and s
, and after
s
:
p :- point(1), q, point(2), r, point(3), s, point(4).
This is the most precise form provided. The counter values do not only show whether all code points were reached but also whether subgoals failed or aborted (in which case the counter before a subgoal will have a higher value than the counter after it). For example, the result of running the above code is:
p :- 43 q, 25 r, 25 s 0 .
which indicates that q
was called 43 times, but succeeded only
25 times, r
was called 25 times and succeeded always, and
s
was called 25 times and never succeeded. Coverage counts of
zero are displayed in red (the final box) because they indicate
unreached code. The format of the display is explained in the next
section.
In order to add the coverage counters to code, it must be compiled with the ccompile/1 predicate which can be found in the coverage library.
The predicate ccompile/1
(note the initial ‘c’ stands for
coverage) can be used in place of the normal compile/1
predicate to compile a file with coverage counters.
Here we see the results of compiling the n-queens example given in the previous section.
?- coverage:ccompile(queens). coverage: inserted 22 coverage counters into module eclipse foo.ecl compiled traceable 5744 bytes in 0.00 seconds Yes (0.00s cpu)
Once compiled, predicates can be called as usual and will (by default)
have no visible side effects. Internally however, the counters will
be incremented as the execution progresses. To see this in action,
consider issuing the following query having compiled the previously
defined code using ccompile/1
.
?- queens([1,2,3,4,5,6,7,8,9], Out).
The default behaviour of the ccompile/1
predicate is to place
coverage counters as explained above, however such a level of detail
may be unnecessary. If one is interested in reachability analysis the
two argument predicate ccompile/2
can take a list of name:value
pairs
which can be used to control the exact manner in which coverage
counters are inserted.
In particular by specifying the
option blocks_only:on
, counters will only be inserted at the
beginning and end of code blocks. Reusing the above example this would
result in counters at point(1) and point(4).
p :- 43 q, r, s 0 .
This can be useful in tracking down unexpected failures by looking for exit counters which differ from entry counters, for example.
To generate an html file containing the coverage counter results issue the following query.
?- coverage:result(queens).
This will create the result file coverage/queens.html which can be viewed using any browser. It contains a pretty-printed form of the source, annotated with the values of the code coverage counters as described above. An example is shown in figure 6.1.
For extra convenience the
predicate result/0
is provided which will create results for
all files which have been compiled with coverage counters.
- result/0
- Creates results for all files which have been compiled with coverage counters.
- result/1
- This predicate takes a single argument which is the name of the file to print the coverage counters for.
- result/2
- The result predicate has a two argument form, the second argument defining a number of flags which control (amongst other things)
- The directory in which to create the results file. Default: coverage.
- The format of the results file (html or text). Default: html.
- ⊙
- See coverage library and pretty_printer library for more details
Having generated and viewed results for one run, the coverage counters can be reset by calling
?- coverage:reset_counters. Yes (0.00s cpu)