2026-07-09 07:16:15 -08:00
|
|
|
# Source-based Code Coverage
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```{contents}
|
|
|
|
|
:local:
|
|
|
|
|
```
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Introduction
|
2016-06-01 16:51:50 -08:00
|
|
|
|
|
|
|
|
This document explains how to use clang's source-based code coverage feature.
|
|
|
|
|
It's called "source-based" because it operates on AST and preprocessor
|
|
|
|
|
information directly. This allows it to generate very precise coverage data.
|
|
|
|
|
|
|
|
|
|
Clang ships two other code coverage implementations:
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- {doc}`SanitizerCoverage` - A low-overhead tool meant for use alongside the
|
2016-06-01 16:51:50 -08:00
|
|
|
various sanitizers. It can provide up to edge-level coverage.
|
2026-07-09 07:16:15 -08:00
|
|
|
- gcov - A GCC-compatible coverage implementation which operates on DebugInfo.
|
|
|
|
|
This is enabled by `-ftest-coverage` or `--coverage`.
|
2016-06-01 16:51:50 -08:00
|
|
|
|
|
|
|
|
From this point onwards "code coverage" will refer to the source-based kind.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## The code coverage workflow
|
2016-06-01 16:51:50 -08:00
|
|
|
|
|
|
|
|
The code coverage workflow consists of three main steps:
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Compiling with coverage enabled.
|
|
|
|
|
- Running the instrumented program.
|
|
|
|
|
- Creating coverage reports.
|
2016-06-01 16:51:50 -08:00
|
|
|
|
|
|
|
|
The next few sections work through a complete, copy-'n-paste friendly example
|
|
|
|
|
based on this program:
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```cpp
|
|
|
|
|
% cat <<EOF > foo.cc
|
|
|
|
|
#define BAR(x) ((x) || (x))
|
|
|
|
|
template <typename T> void foo(T x) {
|
|
|
|
|
for (unsigned I = 0; I < 10; ++I) { BAR(I); }
|
|
|
|
|
}
|
|
|
|
|
int main() {
|
|
|
|
|
foo<int>(0);
|
|
|
|
|
foo<float>(0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
EOF
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Compiling with coverage enabled
|
|
|
|
|
|
|
|
|
|
To compile code with coverage enabled, pass `-fprofile-instr-generate
|
|
|
|
|
-fcoverage-mapping` to the compiler:
|
|
|
|
|
|
|
|
|
|
```console
|
|
|
|
|
# Step 1: Compile with coverage enabled.
|
|
|
|
|
% clang++ -fprofile-instr-generate -fcoverage-mapping foo.cc -o foo
|
|
|
|
|
```
|
2016-06-01 16:51:50 -08:00
|
|
|
|
|
|
|
|
Note that linking together code with and without coverage instrumentation is
|
2016-09-22 07:34:33 -08:00
|
|
|
supported. Uninstrumented code simply won't be accounted for in reports.
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2024-01-22 11:27:16 -09:00
|
|
|
To compile code with Modified Condition/Decision Coverage (MC/DC) enabled,
|
2026-07-09 07:16:15 -08:00
|
|
|
pass `-fcoverage-mcdc` in addition to the clang options specified above.
|
2025-08-18 06:02:15 -08:00
|
|
|
MC/DC is an advanced form of code coverage most applicable to the embedded
|
2024-01-22 11:27:16 -09:00
|
|
|
space.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Running the instrumented program
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2025-08-18 06:02:15 -08:00
|
|
|
The next step is to run the instrumented program. When the program exits, it
|
2026-07-09 07:16:15 -08:00
|
|
|
will write a **raw profile** to the path specified by the `LLVM_PROFILE_FILE`
|
2016-06-01 18:25:13 -08:00
|
|
|
environment variable. If that variable does not exist, the profile is written
|
2026-07-09 07:16:15 -08:00
|
|
|
to `default.profraw` in the current directory of the program. If
|
|
|
|
|
`LLVM_PROFILE_FILE` specifies a path to a non-existent directory, the missing
|
|
|
|
|
directory structure will be created. Additionally, the following special
|
2016-06-01 18:25:13 -08:00
|
|
|
**pattern strings** are rewritten:
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- "%p" expands out to the process ID.
|
|
|
|
|
- "%h" expands out to the hostname of the machine running the program.
|
|
|
|
|
- "%t" expands out to the value of the `TMPDIR` environment variable. On
|
2020-09-08 13:45:41 -08:00
|
|
|
Darwin, this is typically set to a temporary scratch directory.
|
2026-07-09 07:16:15 -08:00
|
|
|
- "%Nm" expands out to the instrumented binary's signature. When this pattern
|
2016-06-13 16:42:12 -08:00
|
|
|
is specified, the runtime creates a pool of N raw profiles which are used for
|
|
|
|
|
on-line profile merging. The runtime takes care of selecting a raw profile
|
2026-07-09 07:16:15 -08:00
|
|
|
from the pool, locking it, and updating it before the program exits. If N is
|
|
|
|
|
not specified (i.e the pattern is "%m"), it's assumed that `N = 1`. The
|
2023-05-11 13:16:16 -08:00
|
|
|
merge pool specifier can only occur once per filename pattern.
|
2026-07-09 07:16:15 -08:00
|
|
|
- "%b" expands out to the binary ID (build ID). It can be used with "%Nm" to
|
2025-02-06 12:05:10 -09:00
|
|
|
avoid binary signature collisions. To use it, the program should be compiled
|
2026-07-09 07:16:15 -08:00
|
|
|
with the build ID linker option (`--build-id` for GNU ld or LLD,
|
|
|
|
|
`/build-id` for lld-link on Windows). Linux, Windows, and AIX are supported.
|
|
|
|
|
- "%c" expands out to nothing, but enables a mode in which profile counter
|
[profile] Add a mode to continuously sync counter updates to a file
Add support for continuously syncing profile counter updates to a file.
The motivation for this is that programs do not always exit cleanly. On
iOS, for example, programs are usually killed via a signal from the OS.
Running atexit() handlers after catching a signal is unreliable, so some
method for progressively writing out profile data is necessary.
The approach taken here is to mmap() the `__llvm_prf_cnts` section onto
a raw profile. To do this, the linker must page-align the counter and
data sections, and the runtime must ensure that counters are mapped to a
page-aligned offset within a raw profile.
Continuous mode is (for the moment) incompatible with the online merging
mode. This limitation is lifted in https://reviews.llvm.org/D69586.
Continuous mode is also (for the moment) incompatible with value
profiling, as I'm not sure whether there is interest in this and the
implementation may be tricky.
As I have not been able to test extensively on non-Darwin platforms,
only Darwin support is included for the moment. However, continuous mode
may "just work" without modification on Linux and some UNIX-likes. AIUI
the default value for the GNU linker's `--section-alignment` flag is set
to the page size on many systems. This appears to be true for LLD as
well, as its `no_nmagic` option is on by default. Continuous mode will
not "just work" on Fuchsia or Windows, as it's not possible to mmap() a
section on these platforms. There is a proposal to add a layer of
indirection to the profile instrumentation to support these platforms.
rdar://54210980
Differential Revision: https://reviews.llvm.org/D68351
2019-09-19 10:56:43 -08:00
|
|
|
updates are continuously synced to a file. This means that if the
|
|
|
|
|
instrumented program crashes, or is killed by a signal, perfect coverage
|
2019-11-12 09:24:23 -09:00
|
|
|
information can still be recovered. Continuous mode does not support value
|
|
|
|
|
profiling for PGO, and is only supported on Darwin at the moment. Support for
|
2019-10-04 12:29:56 -08:00
|
|
|
Linux may be mostly complete but requires testing, and support for Windows
|
|
|
|
|
may require more extensive changes: please get involved if you are interested
|
|
|
|
|
in porting this feature.
|
[profile] Add a mode to continuously sync counter updates to a file
Add support for continuously syncing profile counter updates to a file.
The motivation for this is that programs do not always exit cleanly. On
iOS, for example, programs are usually killed via a signal from the OS.
Running atexit() handlers after catching a signal is unreliable, so some
method for progressively writing out profile data is necessary.
The approach taken here is to mmap() the `__llvm_prf_cnts` section onto
a raw profile. To do this, the linker must page-align the counter and
data sections, and the runtime must ensure that counters are mapped to a
page-aligned offset within a raw profile.
Continuous mode is (for the moment) incompatible with the online merging
mode. This limitation is lifted in https://reviews.llvm.org/D69586.
Continuous mode is also (for the moment) incompatible with value
profiling, as I'm not sure whether there is interest in this and the
implementation may be tricky.
As I have not been able to test extensively on non-Darwin platforms,
only Darwin support is included for the moment. However, continuous mode
may "just work" without modification on Linux and some UNIX-likes. AIUI
the default value for the GNU linker's `--section-alignment` flag is set
to the page size on many systems. This appears to be true for LLD as
well, as its `no_nmagic` option is on by default. Continuous mode will
not "just work" on Fuchsia or Windows, as it's not possible to mmap() a
section on these platforms. There is a proposal to add a layer of
indirection to the profile instrumentation to support these platforms.
rdar://54210980
Differential Revision: https://reviews.llvm.org/D68351
2019-09-19 10:56:43 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```console
|
|
|
|
|
# Step 2: Run the program.
|
|
|
|
|
% LLVM_PROFILE_FILE="foo.profraw" ./foo
|
|
|
|
|
```
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2019-10-04 12:29:56 -08:00
|
|
|
Note that continuous mode is also used on Fuchsia where it's the only supported
|
|
|
|
|
mode, but the implementation is different. The Darwin and Linux implementation
|
|
|
|
|
relies on padding and the ability to map a file over the existing memory
|
|
|
|
|
mapping which is generally only available on POSIX systems and isn't suitable
|
|
|
|
|
for other platforms.
|
|
|
|
|
|
2020-02-10 09:51:23 -09:00
|
|
|
On Fuchsia, we rely on the ability to relocate counters at runtime using a
|
2019-10-04 12:29:56 -08:00
|
|
|
level of indirection. On every counter access, we add a bias to the counter
|
2026-07-09 07:16:15 -08:00
|
|
|
address. This bias is stored in `__llvm_profile_counter_bias` symbol that's
|
2019-10-04 12:29:56 -08:00
|
|
|
provided by the profile runtime and is initially set to zero, meaning no
|
2020-02-10 09:51:23 -09:00
|
|
|
relocation. The runtime can map the profile into memory at arbitrary locations,
|
2019-10-04 12:29:56 -08:00
|
|
|
and set bias to the offset between the original and the new counter location,
|
|
|
|
|
at which point every subsequent counter access will be to the new location,
|
2020-02-10 09:51:23 -09:00
|
|
|
which allows updating profile directly akin to the continuous mode.
|
2019-10-04 12:29:56 -08:00
|
|
|
|
2025-08-18 06:02:15 -08:00
|
|
|
The advantage of this approach is that it doesn't require any special OS support.
|
2019-10-04 12:29:56 -08:00
|
|
|
The disadvantage is the extra overhead due to additional instructions required
|
|
|
|
|
for each counter access (overhead both in terms of binary size and performance)
|
|
|
|
|
plus duplication of counters (i.e. one copy in the binary itself and another
|
|
|
|
|
copy that's mapped into memory). This implementation can be also enabled for
|
2026-07-09 07:16:15 -08:00
|
|
|
other platforms by passing the `-runtime-counter-relocation` option to the
|
2019-10-04 12:29:56 -08:00
|
|
|
backend during compilation.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
For a program such as the [Lit](https://llvm.org/docs/CommandGuide/lit.html)
|
2025-08-18 06:02:15 -08:00
|
|
|
testing tool, which invokes other programs, it may be necessary to set
|
2026-07-09 07:16:15 -08:00
|
|
|
`LLVM_PROFILE_FILE` for each invocation. The pattern strings "%p" or "%Nm"
|
2023-01-28 04:56:22 -09:00
|
|
|
may help to avoid corruption due to concurrency. Note that "%p" is also a Lit
|
|
|
|
|
token and needs to be escaped as "%%p".
|
2023-01-27 16:51:18 -09:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```console
|
|
|
|
|
% clang++ -fprofile-instr-generate -fcoverage-mapping -mllvm -runtime-counter-relocation foo.cc -o foo
|
|
|
|
|
```
|
2019-10-04 12:29:56 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Creating coverage reports
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2025-08-18 06:02:15 -08:00
|
|
|
Raw profiles must be **indexed** before they can be used to generate
|
2026-07-09 07:16:15 -08:00
|
|
|
coverage reports. This is done using the "merge" tool in `llvm-profdata`
|
2016-09-22 07:34:33 -08:00
|
|
|
(which can combine multiple raw profiles and index them at the same time):
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```console
|
|
|
|
|
# Step 3(a): Index the raw profile.
|
|
|
|
|
% llvm-profdata merge -sparse foo.profraw -o foo.profdata
|
|
|
|
|
```
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2023-01-27 16:51:18 -09:00
|
|
|
For an example of merging multiple profiles created by testing,
|
2026-07-09 07:16:15 -08:00
|
|
|
see the LLVM [coverage build script](https://github.com/llvm/llvm-zorg/blob/main/zorg/jenkins/jobs/jobs/llvm-coverage).
|
2023-01-27 16:51:18 -09:00
|
|
|
|
2016-09-22 07:34:33 -08:00
|
|
|
There are multiple different ways to render coverage reports. The simplest
|
|
|
|
|
option is to generate a line-oriented report:
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```console
|
|
|
|
|
# Step 3(b): Create a line-oriented coverage report.
|
|
|
|
|
% llvm-cov show ./foo -instr-profile=foo.profdata
|
|
|
|
|
```
|
2016-06-01 16:51:50 -08:00
|
|
|
|
|
|
|
|
This report includes a summary view as well as dedicated sub-views for
|
|
|
|
|
templated functions and their instantiations. For our example program, we get
|
2026-07-09 07:16:15 -08:00
|
|
|
distinct views for `foo<int>(...)` and `foo<float>(...)`. If
|
|
|
|
|
`-show-line-counts-or-regions` is enabled, `llvm-cov` displays sub-line
|
2016-06-01 16:51:50 -08:00
|
|
|
region counts (even in macro expansions):
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```none
|
|
|
|
|
1| 20|#define BAR(x) ((x) || (x))
|
|
|
|
|
^20 ^2
|
|
|
|
|
2| 2|template <typename T> void foo(T x) {
|
|
|
|
|
3| 22| for (unsigned I = 0; I < 10; ++I) { BAR(I); }
|
|
|
|
|
^22 ^20 ^20^20
|
|
|
|
|
4| 2|}
|
|
|
|
|
------------------
|
|
|
|
|
| void foo<int>(int):
|
|
|
|
|
| 2| 1|template <typename T> void foo(T x) {
|
|
|
|
|
| 3| 11| for (unsigned I = 0; I < 10; ++I) { BAR(I); }
|
|
|
|
|
| ^11 ^10 ^10^10
|
|
|
|
|
| 4| 1|}
|
|
|
|
|
------------------
|
|
|
|
|
| void foo<float>(int):
|
|
|
|
|
| 2| 1|template <typename T> void foo(T x) {
|
|
|
|
|
| 3| 11| for (unsigned I = 0; I < 10; ++I) { BAR(I); }
|
|
|
|
|
| ^11 ^10 ^10^10
|
|
|
|
|
| 4| 1|}
|
|
|
|
|
------------------
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
If `--show-branches=count` and `--show-expansions` are also enabled, the
|
2020-12-28 08:20:48 -09:00
|
|
|
sub-views will show detailed branch coverage information in addition to the
|
|
|
|
|
region counts:
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```none
|
|
|
|
|
------------------
|
|
|
|
|
| void foo<float>(int):
|
|
|
|
|
| 2| 1|template <typename T> void foo(T x) {
|
|
|
|
|
| 3| 11| for (unsigned I = 0; I < 10; ++I) { BAR(I); }
|
|
|
|
|
| ^11 ^10 ^10^10
|
|
|
|
|
| ------------------
|
|
|
|
|
| | | 1| 10|#define BAR(x) ((x) || (x))
|
|
|
|
|
| | | ^10 ^1
|
|
|
|
|
| | | ------------------
|
|
|
|
|
| | | | Branch (1:17): [True: 9, False: 1]
|
|
|
|
|
| | | | Branch (1:24): [True: 0, False: 1]
|
|
|
|
|
| | | ------------------
|
|
|
|
|
| ------------------
|
|
|
|
|
| | Branch (3:23): [True: 10, False: 1]
|
|
|
|
|
| ------------------
|
|
|
|
|
| 4| 1|}
|
|
|
|
|
------------------
|
|
|
|
|
```
|
2020-12-28 08:20:48 -09:00
|
|
|
|
2024-01-22 11:27:16 -09:00
|
|
|
If the application was instrumented for Modified Condition/Decision Coverage
|
2026-07-09 07:16:15 -08:00
|
|
|
(MC/DC) using the clang option `-fcoverage-mcdc`, an MC/DC subview can be
|
|
|
|
|
enabled using `--show-mcdc` that will show detailed MC/DC information for
|
2024-01-22 11:27:16 -09:00
|
|
|
each complex condition boolean expression containing at most six conditions.
|
2020-12-28 08:20:48 -09:00
|
|
|
|
2016-09-22 07:34:33 -08:00
|
|
|
To generate a file-level summary of coverage statistics instead of a
|
|
|
|
|
line-oriented report, try:
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```console
|
|
|
|
|
# Step 3(c): Create a coverage summary.
|
|
|
|
|
% llvm-cov report ./foo -instr-profile=foo.profdata
|
|
|
|
|
Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
/tmp/foo.cc 13 0 100.00% 3 0 100.00% 13 0 100.00% 12 2 83.33%
|
|
|
|
|
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
TOTAL 13 0 100.00% 3 0 100.00% 13 0 100.00% 12 2 83.33%
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The `llvm-cov` tool supports specifying a custom demangler, writing out
|
2025-08-18 06:02:15 -08:00
|
|
|
reports in a directory structure, and generating HTML reports. For the full
|
2026-07-09 07:16:15 -08:00
|
|
|
list of options, please refer to the [command guide](https://llvm.org/docs/CommandGuide/llvm-cov.html).
|
2016-09-22 07:34:33 -08:00
|
|
|
|
2016-06-01 16:51:50 -08:00
|
|
|
A few final notes:
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- The `-sparse` flag is optional but can produce dramatically smaller
|
2016-06-01 16:51:50 -08:00
|
|
|
indexed profiles. This option should not be used if the indexed profile will
|
|
|
|
|
be reused for PGO.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Raw profiles can be discarded after they are indexed. Advanced use of the
|
2016-06-01 16:51:50 -08:00
|
|
|
profile runtime library allows an instrumented program to merge profiling
|
|
|
|
|
information directly into an existing raw profile on disk. The details are
|
|
|
|
|
out of scope.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- The `llvm-profdata` tool can be used to merge multiple raw or
|
2016-06-01 16:51:50 -08:00
|
|
|
indexed profiles. To combine profiling data from multiple runs of a program,
|
|
|
|
|
try e.g:
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```console
|
|
|
|
|
% llvm-profdata merge -sparse foo1.profraw foo2.profdata -o foo3.profdata
|
|
|
|
|
```
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Exporting coverage data
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
Coverage data can be exported into JSON using the `llvm-cov export`
|
2016-09-20 09:11:18 -08:00
|
|
|
sub-command. There is a comprehensive reference which defines the structure of
|
|
|
|
|
the exported data at a high level in the llvm-cov source code.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Interpreting reports
|
2016-09-18 17:42:38 -08:00
|
|
|
|
2024-01-22 11:27:16 -09:00
|
|
|
There are six statistics tracked in a coverage summary:
|
2016-09-18 17:42:38 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Function coverage is the percentage of functions which have been executed at
|
2016-09-22 07:34:33 -08:00
|
|
|
least once. A function is considered to be executed if any of its
|
2016-09-18 17:42:38 -08:00
|
|
|
instantiations are executed.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Instantiation coverage is the percentage of function instantiations which
|
2016-09-20 09:11:18 -08:00
|
|
|
have been executed at least once. Template functions and static inline
|
|
|
|
|
functions from headers are two kinds of functions which may have multiple
|
2021-02-12 11:04:57 -09:00
|
|
|
instantiations. This statistic is hidden by default in reports, but can be
|
2026-07-09 07:16:15 -08:00
|
|
|
enabled via the `-show-instantiation-summary` option.
|
2016-09-18 17:42:38 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Line coverage is the percentage of code lines which have been executed at
|
2016-09-20 09:11:18 -08:00
|
|
|
least once. Only executable lines within function bodies are considered to be
|
2016-09-22 07:34:33 -08:00
|
|
|
code lines.
|
2016-09-18 17:42:38 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Region coverage is the percentage of code regions which have been executed at
|
2016-09-22 07:34:33 -08:00
|
|
|
least once. A code region may span multiple lines (e.g in a large function
|
|
|
|
|
body with no control flow). However, it's also possible for a single line to
|
|
|
|
|
contain multiple code regions (e.g in "return x || y && z").
|
2016-09-20 09:11:18 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Branch coverage is the percentage of "true" and "false" branches that have
|
2020-12-28 08:20:48 -09:00
|
|
|
been taken at least once. Each branch is tied to individual conditions in the
|
2026-07-09 07:16:15 -08:00
|
|
|
source code that may each evaluate to either "true" or "false". These
|
2020-12-28 08:20:48 -09:00
|
|
|
conditions may comprise larger boolean expressions linked by boolean logical
|
|
|
|
|
operators. For example, "x = (y == 2) || (z < 10)" is a boolean expression
|
2025-08-18 06:02:15 -08:00
|
|
|
comprised of two individual conditions, each of which evaluates to
|
2020-12-28 08:20:48 -09:00
|
|
|
either true or false, producing four total branch outcomes.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Modified Condition/Decision Coverage (MC/DC) is the percentage of individual
|
2024-01-22 11:27:16 -09:00
|
|
|
branch conditions that have been shown to independently affect the decision
|
|
|
|
|
outcome of the boolean expression they comprise. This is accomplished using
|
|
|
|
|
the analysis of executed control flow through the expression (i.e. test
|
|
|
|
|
vectors) to show that as a condition's outcome is varied between "true" and
|
|
|
|
|
false", the decision's outcome also varies between "true" and false", while
|
|
|
|
|
the outcome of all other conditions is held fixed (or they are masked out as
|
|
|
|
|
unevaluatable, as happens in languages whose logical operators have
|
2026-07-09 07:16:15 -08:00
|
|
|
short-circuit semantics). MC/DC builds on top of branch coverage and
|
|
|
|
|
requires that all code blocks and all execution paths have been tested. This
|
2024-01-22 11:27:16 -09:00
|
|
|
statistic is hidden by default in reports, but it can be enabled via the
|
2026-07-09 07:16:15 -08:00
|
|
|
`-show-mcdc-summary` option as long as code was also compiled using the
|
|
|
|
|
clang option `-fcoverage-mcdc`.
|
2024-01-22 11:27:16 -09:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Boolean expressions comprised of only one condition (and therefore
|
2024-01-22 11:27:16 -09:00
|
|
|
have no logical operators) are not included in MC/DC analysis and are
|
|
|
|
|
trivially deducible using branch coverage.
|
|
|
|
|
|
|
|
|
|
Of these six statistics, function coverage is usually the least granular while
|
|
|
|
|
branch coverage (with MC/DC) is the most granular. 100% branch coverage for a
|
|
|
|
|
function implies 100% region coverage for a function. The project-wide totals
|
|
|
|
|
for each statistic are listed in the summary.
|
2016-09-18 17:42:38 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Format compatibility guarantees
|
2016-06-01 16:51:50 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- There are no backwards or forwards compatibility guarantees for the raw
|
2016-06-01 16:51:50 -08:00
|
|
|
profile format. Raw profiles may be dependent on the specific compiler
|
|
|
|
|
revision used to generate them. It's inadvisable to store raw profiles for
|
|
|
|
|
long periods of time.
|
2026-07-09 07:16:15 -08:00
|
|
|
- Tools must retain **backwards** compatibility with indexed profile formats.
|
2016-06-01 16:51:50 -08:00
|
|
|
These formats are not forwards-compatible: i.e, a tool which uses format
|
|
|
|
|
version X will not be able to understand format version (X+k).
|
2026-07-09 07:16:15 -08:00
|
|
|
- Tools must also retain **backwards** compatibility with the format of the
|
2016-09-22 07:34:33 -08:00
|
|
|
coverage mappings emitted into instrumented binaries. These formats are not
|
|
|
|
|
forwards-compatible.
|
2026-07-09 07:16:15 -08:00
|
|
|
- The JSON coverage export format has a (major, minor, patch) version triple.
|
2016-09-20 09:11:18 -08:00
|
|
|
Only a major version increment indicates a backwards-incompatible change. A
|
|
|
|
|
minor version increment is for added functionality, and patch version
|
|
|
|
|
increments are for bugfixes.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Impact of llvm optimizations on coverage reports
|
2021-02-12 11:04:27 -09:00
|
|
|
|
|
|
|
|
llvm optimizations (such as inlining or CFG simplification) should have no
|
|
|
|
|
impact on coverage report quality. This is due to the fact that the mapping
|
|
|
|
|
from source regions to profile counters is immutable, and is generated before
|
|
|
|
|
the llvm optimizer kicks in. The optimizer can't prove that profile counter
|
|
|
|
|
instrumentation is safe to delete (because it's not: it affects the profile the
|
|
|
|
|
program emits), and so leaves it alone.
|
|
|
|
|
|
|
|
|
|
Note that this coverage feature does not rely on information that can degrade
|
|
|
|
|
during the course of optimization, such as debug info line tables.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Using the profiling runtime without static initializers
|
2016-06-07 14:25:29 -08:00
|
|
|
|
|
|
|
|
By default the compiler runtime uses a static initializer to determine the
|
|
|
|
|
profile output path and to register a writer function. To collect profiles
|
|
|
|
|
without using static initializers, do this manually:
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Export an `int __llvm_profile_runtime` symbol from each instrumented shared
|
2016-06-08 14:24:52 -08:00
|
|
|
library and executable. When the linker finds a definition of this symbol, it
|
|
|
|
|
knows to skip loading the object which contains the profiling runtime's
|
|
|
|
|
static initializer.
|
2026-07-09 07:16:15 -08:00
|
|
|
- Forward-declare `void __llvm_profile_initialize_file(void)` and call it
|
2016-06-08 14:24:52 -08:00
|
|
|
once from each instrumented executable. This function parses
|
2026-07-09 07:16:15 -08:00
|
|
|
`LLVM_PROFILE_FILE`, sets the output path, and truncates any existing files
|
2016-06-08 14:24:52 -08:00
|
|
|
at that path. To get the same behavior without truncating existing files,
|
2026-07-09 07:16:15 -08:00
|
|
|
pass a filename pattern string to `void __llvm_profile_set_filename(char
|
|
|
|
|
*)`. These calls can be placed anywhere so long as they precede all calls
|
|
|
|
|
to `__llvm_profile_write_file`.
|
|
|
|
|
- Forward-declare `int __llvm_profile_write_file(void)` and call it to write
|
2025-08-18 06:02:15 -08:00
|
|
|
out a profile. This function returns 0 on success, and a non-zero value
|
2016-06-08 14:32:03 -08:00
|
|
|
otherwise. Calling this function multiple times appends profile data to an
|
|
|
|
|
existing on-disk raw profile.
|
2016-06-07 14:25:29 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
In C++ files, declare these as `extern "C"`.
|
2017-01-25 07:01:32 -09:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
### Using the profiling runtime without a filesystem
|
2021-04-21 14:00:51 -08:00
|
|
|
|
|
|
|
|
The profiling runtime also supports freestanding environments that lack a
|
|
|
|
|
filesystem. The runtime ships as a static archive that's structured to make
|
|
|
|
|
dependencies on a hosted environment optional, depending on what features
|
|
|
|
|
the client application uses.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
The first step is to export `__llvm_profile_runtime`, as above, to disable
|
|
|
|
|
the default static initializers. Instead of calling the `*_file()` APIs
|
2021-04-21 14:00:51 -08:00
|
|
|
described above, use the following to save the profile directly to a buffer
|
|
|
|
|
under your control:
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Forward-declare `uint64_t __llvm_profile_get_size_for_buffer(void)` and
|
2021-04-21 14:00:51 -08:00
|
|
|
call it to determine the size of the profile. You'll need to allocate a
|
|
|
|
|
buffer of this size.
|
2026-07-09 07:16:15 -08:00
|
|
|
- Forward-declare `int __llvm_profile_write_buffer(char *Buffer)` and call it
|
|
|
|
|
to copy the current counters to `Buffer`, which is expected to already be
|
2021-04-21 14:00:51 -08:00
|
|
|
allocated and big enough for the profile.
|
2026-07-09 07:16:15 -08:00
|
|
|
- Optionally, forward-declare `void __llvm_profile_reset_counters(void)` and
|
2021-04-21 14:00:51 -08:00
|
|
|
call it to reset the counters before entering a specific section to be
|
|
|
|
|
profiled. This is only useful if there is some setup that should be excluded
|
|
|
|
|
from the profile.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
In C++ files, declare these as `extern "C"`.
|
2021-04-21 14:00:51 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Collecting coverage reports for the llvm project
|
2016-09-20 09:11:18 -08:00
|
|
|
|
|
|
|
|
To prepare a coverage report for llvm (and any of its sub-projects), add
|
2026-07-09 07:16:15 -08:00
|
|
|
`-DLLVM_BUILD_INSTRUMENTED_COVERAGE=On` to the CMake configuration. Raw
|
|
|
|
|
profiles will be written to `$BUILD_DIR/profiles/`. To prepare an html
|
|
|
|
|
report, run `llvm/utils/prepare-code-coverage-artifact.py`.
|
2016-09-20 09:11:18 -08:00
|
|
|
|
|
|
|
|
To specify an alternate directory for raw profiles, use
|
2026-07-09 07:16:15 -08:00
|
|
|
`-DLLVM_PROFILE_DATA_DIR`. To change the size of the profile merge pool, use
|
|
|
|
|
`-DLLVM_PROFILE_MERGE_POOL_SIZE`.
|
2016-09-20 09:11:18 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Drawbacks and limitations
|
2016-06-02 09:19:45 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Prior to version 2.26, the GNU binutils BFD linker cannot link programs
|
|
|
|
|
compiled with `-fcoverage-mapping` in its `--gc-sections` mode. Possible
|
|
|
|
|
workarounds include disabling `--gc-sections`, upgrading to a newer version
|
2017-06-19 13:26:04 -08:00
|
|
|
of BFD, or using the Gold linker.
|
2017-06-19 13:22:05 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
- Code coverage does not handle unpredictable changes in control flow or stack
|
2016-06-06 07:44:40 -08:00
|
|
|
unwinding in the presence of exceptions precisely. Consider the following
|
|
|
|
|
function:
|
2016-06-02 09:19:45 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
```cpp
|
|
|
|
|
int f() {
|
|
|
|
|
may_throw();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
```
|
2016-06-02 09:19:45 -08:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
If the call to `may_throw()` propagates an exception into `f`, the code
|
|
|
|
|
coverage tool may mark the `return` statement as executed even though it is
|
|
|
|
|
not. A call to `longjmp()` can have similar effects.
|
2019-11-21 13:17:04 -09:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
## Clang implementation details
|
2019-11-21 13:17:04 -09:00
|
|
|
|
|
|
|
|
This section may be of interest to those wishing to understand or improve
|
|
|
|
|
the clang code coverage implementation.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
### Gap regions
|
2019-11-21 13:17:04 -09:00
|
|
|
|
|
|
|
|
Gap regions are source regions with counts. A reporting tool cannot set a line
|
|
|
|
|
execution count to the count from a gap region unless that region is the only
|
|
|
|
|
one on a line.
|
|
|
|
|
|
|
|
|
|
Gap regions are used to eliminate unnatural artifacts in coverage reports, such
|
|
|
|
|
as red "unexecuted" highlights present at the end of an otherwise covered line,
|
|
|
|
|
or blue "executed" highlights present at the start of a line that is otherwise
|
|
|
|
|
not executed.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
### Branch regions
|
|
|
|
|
|
2020-12-28 08:20:48 -09:00
|
|
|
When viewing branch coverage details in source-based file-level sub-views using
|
2026-07-09 07:16:15 -08:00
|
|
|
`--show-branches`, it is recommended that users show all macro expansions
|
|
|
|
|
(using option `--show-expansions`) since macros may contain hidden branch
|
|
|
|
|
conditions. The coverage summary report will always include these macro-based
|
2020-12-28 08:20:48 -09:00
|
|
|
boolean expressions in the overall branch coverage count for a function or
|
|
|
|
|
source file.
|
|
|
|
|
|
|
|
|
|
Branch coverage is not tracked for constant folded branch conditions since
|
2026-07-09 07:16:15 -08:00
|
|
|
branches are not generated for these cases. In the source-based file-level
|
|
|
|
|
sub-view, these branches will simply be shown as `[Folded - Ignored]` so that
|
2020-12-28 08:20:48 -09:00
|
|
|
users are informed about what happened.
|
|
|
|
|
|
|
|
|
|
Branch coverage is tied directly to branch-generating conditions in the source
|
2026-07-09 07:16:15 -08:00
|
|
|
code. Users should not see hidden branches that aren't actually tied to the
|
2020-12-28 08:20:48 -09:00
|
|
|
source code.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
### MC/DC Instrumentation
|
2024-01-22 11:27:16 -09:00
|
|
|
|
|
|
|
|
When instrumenting for Modified Condition/Decision Coverage (MC/DC) using the
|
2026-07-09 07:16:15 -08:00
|
|
|
clang option `-fcoverage-mcdc`, there are two hard limits.
|
2024-06-13 03:09:02 -08:00
|
|
|
|
|
|
|
|
The maximum number of terms is limited to 32767, which is practical for
|
|
|
|
|
handwritten expressions. To be more restrictive in order to enforce coding rules,
|
2026-07-09 07:16:15 -08:00
|
|
|
use `-Xclang -fmcdc-max-conditions=n`. Expressions with exceeded condition
|
|
|
|
|
counts `n` will generate warnings and will be excluded in the MC/DC coverage.
|
2024-06-13 03:09:02 -08:00
|
|
|
|
|
|
|
|
The number of test vectors (the maximum number of possible combinations of
|
|
|
|
|
expressions) is limited to 2,147,483,646. In this case, approximately
|
|
|
|
|
256MiB (==2GiB/8) is used to record test vectors.
|
|
|
|
|
|
|
|
|
|
To reduce memory usage, users can limit the maximum number of test vectors per
|
2026-07-09 07:16:15 -08:00
|
|
|
expression with `-Xclang -fmcdc-max-test-vectors=m`.
|
2024-06-13 03:09:02 -08:00
|
|
|
If the number of test vectors resulting from the analysis of an expression
|
2026-07-09 07:16:15 -08:00
|
|
|
exceeds `m`, a warning will be issued and the expression will be excluded
|
2024-06-13 03:09:02 -08:00
|
|
|
from the MC/DC coverage.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
The number of test vectors `m`, for `n` terms in an expression, can be
|
|
|
|
|
`m <= 2^n` in the theoretical worst case, but is usually much smaller.
|
2024-06-13 03:09:02 -08:00
|
|
|
In simple cases, such as expressions consisting of a sequence of single
|
2026-07-09 07:16:15 -08:00
|
|
|
operators, `m == n+1`. For example, `(a && b && c && d && e && f && g)`
|
2024-06-13 03:09:02 -08:00
|
|
|
requires 8 test vectors.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
Expressions such as `((a0 && b0) || (a1 && b1) || ...)` can cause the
|
2024-06-13 03:09:02 -08:00
|
|
|
number of test vectors to increase exponentially.
|
2024-01-22 11:27:16 -09:00
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
### Switch statements
|
2019-11-21 13:17:04 -09:00
|
|
|
|
|
|
|
|
The region mapping for a switch body consists of a gap region that covers the
|
|
|
|
|
entire body (starting from the '{' in 'switch (...) {', and terminating where the
|
|
|
|
|
last case ends). This gap region has a zero count: this causes "gap" areas in
|
|
|
|
|
between case statements, which contain no executable code, to appear uncovered.
|
|
|
|
|
|
|
|
|
|
When a switch case is visited, the parent region is extended: if the parent
|
|
|
|
|
region has no start location, its start location becomes the start of the case.
|
2026-07-09 07:16:15 -08:00
|
|
|
This is used to support switch statements without a `CompoundStmt` body, in
|
2019-11-21 13:17:04 -09:00
|
|
|
which the switch body and the single case share a count.
|
|
|
|
|
|
2026-07-09 07:16:15 -08:00
|
|
|
For switches with `CompoundStmt` bodies, a new region is created at the start
|
2019-11-21 13:17:04 -09:00
|
|
|
of each switch case.
|
2020-12-28 08:20:48 -09:00
|
|
|
|
|
|
|
|
Branch regions are also generated for each switch case, including the default
|
|
|
|
|
case. If there is no explicitly defined default case in the source code, a
|
|
|
|
|
branch region is generated to correspond to the implicit default case that is
|
2026-07-09 07:16:15 -08:00
|
|
|
generated by the compiler. The implicit branch region is tied to the line and
|
2020-12-28 08:20:48 -09:00
|
|
|
column number of the switch statement condition since no source code for the
|
|
|
|
|
implicit case exists.
|