aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/g++.dg
diff options
context:
space:
mode:
authorJørgen Kvalsvik <j@lambda.is>2024-03-29 13:01:37 +0100
committerJørgen Kvalsvik <j@lambda.is>2024-07-11 09:13:16 +0200
commit1e43ea7bb3598e3ee19119c54c69a7c4b8745d0f (patch)
treea386dd6db13eb8ac99c42d53040a9378a7d0b8c8 /gcc/testsuite/g++.dg
parent2b3fbac8e37384857cd594c0800fccd99e4d39a1 (diff)
downloadgcc-1e43ea7bb3598e3ee19119c54c69a7c4b8745d0f.zip
gcc-1e43ea7bb3598e3ee19119c54c69a7c4b8745d0f.tar.gz
gcc-1e43ea7bb3598e3ee19119c54c69a7c4b8745d0f.tar.bz2
Add function filtering to gcov
Add the --include and --exclude flags to gcov to control what functions to report on. This is meant to make gcov more practical as an when writing test suites or performing other coverage experiments, which tends to focus on a few functions at the time. This really shines in combination with the -t/--stdout flag. With support for more expansive metrics in gcov like modified condition/decision coverage (MC/DC) and path coverage, output quickly gets overwhelming without filtering. The approach is quite simple: filters are egrep regexes and are evaluated left-to-right, and the last filter "wins", that is, if a function matches an --include and a subsequent --exclude, it should not be included in the output. All of the output machinery works on the function table, so by optionally (not) adding function makes the even the json output work as expected, and only minor changes are needed to suppress the filtered-out functions. Demo: math.c int mul (int a, int b) { return a * b; } int sub (int a, int b) { return a - b; } int sum (int a, int b) { return a + b; } Plain matches: $ gcov -t math --include=sum -: 0:Source:math.c -: 0:Graph:math.gcno -: 0:Data:- -: 0:Runs:0 #####: 9:int sum (int a, int b) { #####: 10: return a + b; -: 11:} $ gcov -t math --include=mul -: 0:Source:math.c -: 0:Graph:math.gcno -: 0:Data:- -: 0:Runs:0 #####: 1:int mul (int a, int b) { #####: 2: return a * b; -: 3:} Regex match: $ gcov -t math --include=su -: 0:Source:math.c -: 0:Graph:math.gcno -: 0:Data:- -: 0:Runs:0 #####: 5:int sub (int a, int b) { #####: 6: return a - b; -: 7:} #####: 9:int sum (int a, int b) { #####: 10: return a + b; -: 11:} And similar for exclude: $ gcov -t math --exclude=sum -: 0:Source:math.c -: 0:Graph:math.gcno -: 0:Data:- -: 0:Runs:0 #####: 1:int mul (int a, int b) { #####: 2: return a * b; -: 3:} #####: 5:int sub (int a, int b) { #####: 6: return a - b; -: 7:} And json, for good measure: $ gcov -t math --include=sum --json | jq ".files[].lines[]" { "line_number": 9, "function_name": "sum", "count": 0, "unexecuted_block": true, "block_ids": [], "branches": [], "calls": [] } { "line_number": 10, "function_name": "sum", "count": 0, "unexecuted_block": true, "block_ids": [ 2 ], "branches": [], "calls": [] } Matching generally work well for mangled names, as the mangled names also have the base symbol name in it. By default, functions are matched by the mangled name, which means matching on base names always work as expected. The -M flag makes the matching work on the demangled name which is quite useful when you only want to report on specific overloads and can use the full type names. Why not just use grep? grep is not really sufficient as grep is very line oriented, and the reports that benefit the most from filtering often unpredictably span multiple lines based on the state of coverage. For example, a condition coverage report for 3 terms/6 outcomes only outputs 1 line when all conditions are covered, and 7 with no lines covered. gcc/ChangeLog: * doc/gcov.texi: Add --include, --exclude, --match-on-demangled documentation. * gcov.cc (struct fnfilter): New. (print_usage): Add --include, --exclude, -M, --match-on-demangled. (process_args): Likewise. (release_structures): Release filters. (read_graph_file): Only add function_infos matching filters. (output_lines): Likewise. gcc/testsuite/ChangeLog: * lib/gcov.exp: Add filtering test function. * g++.dg/gcov/gcov-19.C: New test. * g++.dg/gcov/gcov-20.C: New test. * g++.dg/gcov/gcov-21.C: New test. * gcc.misc-tests/gcov-25.c: New test. * gcc.misc-tests/gcov-26.c: New test. * gcc.misc-tests/gcov-27.c: New test. * gcc.misc-tests/gcov-28.c: New test.
Diffstat (limited to 'gcc/testsuite/g++.dg')
-rw-r--r--gcc/testsuite/g++.dg/gcov/gcov-19.C35
-rw-r--r--gcc/testsuite/g++.dg/gcov/gcov-20.C38
-rw-r--r--gcc/testsuite/g++.dg/gcov/gcov-21.C32
3 files changed, 105 insertions, 0 deletions
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-19.C b/gcc/testsuite/g++.dg/gcov/gcov-19.C
new file mode 100644
index 0000000..3f898cf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/gcov-19.C
@@ -0,0 +1,35 @@
+/* { dg-options "-fprofile-arcs -ftest-coverage" } */
+/* { dg-do run { target native } } */
+
+/* Filtering on the function base name generally works well, because it becomes
+ an unadultered part of the symbol. */
+
+template <typename T>
+T
+fn1 (T x)
+{
+ /* fst */
+ return x;
+}
+
+template <typename T>
+T
+fn2 (T x)
+{
+ /* snd */
+ return 2 * x;
+}
+
+int
+main ()
+{
+ fn1 (2);
+ fn1 (2.0);
+ fn1 (2.0f);
+
+ fn2 (2);
+ fn2 (2.0);
+ fn2 (2.0f);
+}
+
+/* { dg-final { run-gcov { filters { fn1 } { fn2 } } { --include=fn1 gcov-19.C } } } */
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-20.C b/gcc/testsuite/g++.dg/gcov/gcov-20.C
new file mode 100644
index 0000000..fb33f7e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/gcov-20.C
@@ -0,0 +1,38 @@
+/* { dg-options "-fprofile-arcs -ftest-coverage" } */
+/* { dg-do run { target native } } */
+
+/* Filtering also works by targeting the mangled symbol directly, but the
+ subtlety is not really caught by the test framework. Matching on fn1I[df]
+ prints the "overlapping blocks" of both the float and double instantiation,
+ but *not* the int instantiation. The extra {} around the --include argument
+ is quoting for tcl/dejagnu. */
+
+template <typename T>
+T
+fn1 (T x)
+{
+ /* fst */
+ return x;
+}
+
+template <typename T>
+T
+fn2 (T x)
+{
+ /* snd */
+ return 2 * x;
+}
+
+int
+main ()
+{
+ fn1 (2);
+ fn1 (2.0);
+ fn1 (2.0f);
+
+ fn2 (2);
+ fn2 (2.0);
+ fn2 (2.0f);
+}
+
+/* { dg-final { run-gcov { filters { fst } { snd } } { {--include=fn1I[fd]} gcov-20.C } } } */
diff --git a/gcc/testsuite/g++.dg/gcov/gcov-21.C b/gcc/testsuite/g++.dg/gcov/gcov-21.C
new file mode 100644
index 0000000..67f6d79
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gcov/gcov-21.C
@@ -0,0 +1,32 @@
+/* { dg-options "-fprofile-arcs -ftest-coverage" } */
+/* { dg-do run { target native } } */
+
+/* Filters can be applied to demangled names. This support matching on
+ types and class hierarchies as well as function names. */
+
+template <typename T>
+T
+fn1 (T x)
+{
+ /* fst */
+ return x;
+}
+
+template <typename T>
+T
+fn2 (T x)
+{
+ /* snd */
+ return 2 * x;
+}
+
+int
+main ()
+{
+ fn1 (2);
+
+ fn2 (2.0);
+ fn2 (2.0f);
+}
+
+/* { dg-final { run-gcov { filters { fst } } { --filter-on-demangled --include int gcov-21.C } } } */