KallistiOS git master
Independent SDK for the Sega Dreamcast
Loading...
Searching...
No Matches
gcov.h
Go to the documentation of this file.
1/* KallistiOS ##version##
2
3 kos/gcov.h
4 Copyright (C) 2026 Andress Barajas
5
6*/
7
8/** \file kos/gcov.h
9 \brief Code-coverage (.gcda) output on top of GCC's libgcov.
10 \ingroup gcov
11
12 Writes GCC coverage (.gcda) files on a KOS target. The coverage *runtime* is
13 the toolchain's own libgcov; this addon supplies the file I/O that GCC's
14 freestanding libgcov leaves to the platform. Build with --coverage and
15 kos-cc wires everything up; coverage is flushed automatically at exit.
16
17 \author Andress Barajas
18*/
19
20#ifndef __KOS_GCOV_H
21#define __KOS_GCOV_H
22
23#include <sys/cdefs.h>
24__BEGIN_DECLS
25
26/** \defgroup gcov GCOV
27 \brief GCOV coverage and PGO support for KOS
28 \ingroup debugging
29
30 This file provides runtime support for GCOV, a coverage analysis tool built
31 into GCC. GCOV allows you to determine which parts of your code were executed,
32 how often, and which branches were taken. This is especially helpful for
33 analyzing test coverage or identifying unused code paths.
34
35 GCOV's runtime instrumentation writes `.gcda` files that serve two workflows
36 here, both from a plain `--coverage` build:
37
38 1. Code coverage -- which lines/branches ran, for gcov/lcov reports.
39 2. Arc-based PGO -- recompile with `-fprofile-use` and the compiler
40 optimizes from the edge counts (block layout, inlining, branch
41 prediction, function reordering).
42
43 What is NOT available is value-profiling PGO (`-fprofile-generate` /
44 `-fprofile-values`). GCC's freestanding libgcov for these targets ships no
45 value profilers, so those builds fail to link.
46
47 Compile-time flag:
48
49 - `--coverage`: shorthand for `-fprofile-arcs -ftest-coverage`. Instruments
50 edges so per-function execution counts are written to `.gcda` at runtime.
51 Also emits `.gcno` notes that map counters back to source lines and branches;
52 required for human-readable coverage reports.
53
54 When optimizing with `-fprofile-use` (step 4), these companion flags help:
55
56 - `-fprofile-correction`: counter updates are non-atomic by default, so a
57 multi-threaded run (KOS is threaded) can record an inconsistent profile;
58 without this, `-fprofile-use` errors out. This smooths such
59 inconsistencies with heuristics instead.
60
61 - `-fprofile-partial-training`: by default `-fprofile-use` treats any
62 function not seen during the run as cold and optimizes it for size. A
63 single console run rarely exercises everything, so this tells the compiler
64 to optimize un-exercised functions normally rather than pessimizing them.
65
66 - `-fprofile-update=atomic`: (generate side) make counter updates atomic so a
67 threaded run yields an exact, consistent profile, at some runtime cost --
68 an alternative to `-fprofile-correction`.
69
70 See the GCC manual's "Instrumentation Options" and "Optimize Options" for the
71 authoritative descriptions of every flag above.
72
73 Collecting, Analyzing, and Optimizing:
74
75 1. **Compile with coverage support:**
76
77 ```sh
78 CFLAGS += --coverage
79 ```
80
81 This generates `.gcno` files alongside your object files.
82
83 2. **Run your program on hardware:**
84
85 Counts accumulate in memory as the program runs. Getting them out:
86
87 - If your program returns from `main()` (or calls `exit()`), the data is
88 flushed automatically -- this addon registers an `atexit()` handler --
89 so you need not do anything.
90
91 - If your program never exits (an infinite main loop, as many console
92 programs have), that handler never runs. Call `kos_gcov_dump()`
93 yourself to write the data.
94
95 By default each `.gcda` is written at its full build-time path under
96 `/pc` (Ex. /opt/toolchains/dc/kos/examples/dreamcast/profiling/gcov/gcov.gcda),
97 so it matches the source it was generated from. Override the prefix from your
98 program with `setenv(GCOV_PREFIX, "/your/path", 1)` before the data is dumped,
99 and/or set `GCOV_PREFIX_STRIP` to drop leading path components.
100
101 3. **Generate an HTML report with LCOV:**
102
103 Use this Makefile target to capture and visualize results:
104
105 ```make
106 lcov:
107 lcov \
108 --gcov-tool=$(KOS_GCOV) \
109 --directory . \
110 --base-directory . \
111 --capture \
112 --rc geninfo_unexecuted_blocks=1 \
113 --ignore-errors inconsistent,unused,source,empty \
114 --output-file coverage.info
115 genhtml coverage.info --output-directory html \
116 --ignore-errors inconsistent,source
117 open html/index.html
118 ```
119
120 The extra flags keep lcov 2.x (current Homebrew/distro versions, much
121 stricter than 1.x) from aborting on coverage-data quirks that are normal
122 for optimized and inlined/header code.
123
124 This generates a full HTML report with annotated source code in the
125 `html/` directory.
126
127 4. **(Optional) Optimize with the profile (PGO):**
128
129 Recompile the same sources with `-fprofile-use` plus the companion flags
130 above (`-fprofile-correction` is required -- KOS is threaded):
131
132 ```sh
133 CFLAGS += -fprofile-use -fprofile-correction -fprofile-partial-training
134 ```
135
136 `-fprofile-use` reads each object's `.gcda` from the build tree (where
137 step 2 wrote it) and optimizes from the edge counts.
138
139 @{
140*/
141
142/** \brief Environment variable to set the output directory for `.gcda` files.
143 \ingroup gcov
144
145 If set, this value is prepended to the stripped source path to form the
146 final output path.
147*/
148#define GCOV_PREFIX "GCOV_PREFIX"
149
150/** \brief Environment variable to control path stripping.
151 \ingroup gcov
152
153 Number of leading directory components removed from the build-time source
154 path before GCOV_PREFIX is applied.
155*/
156#define GCOV_PREFIX_STRIP "GCOV_PREFIX_STRIP"
157
158/** \brief Write coverage data for every instrumented object.
159
160 Flushes the current in-memory counters to `.gcda` on disk (under GCOV_PREFIX
161 / GCOV_PREFIX_STRIP).
162
163 You normally do NOT need to call this: when a program returns from main()
164 or calls exit(), this addon's atexit handler flushes the data for you. Call
165 it explicitly only when that shutdown path never runs -- most commonly a
166 program with an infinite main loop that never returns.
167
168 \note Existing .gcda files are overwritten, not merged.
169*/
170void kos_gcov_dump(void);
171
172/** @} */
173
174__END_DECLS
175
176#endif /* __KOS_GCOV_H */
void kos_gcov_dump(void)
Write coverage data for every instrumented object.