From: "Jørgen Kvalsvik" <jorgen.kvalsvik@woven.toyota>
To: Jan Hubicka <hubicka@ucw.cz>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: Ping [PATCH v4] Add condition coverage profiling
Date: Fri, 30 Jun 2023 15:53:29 +0900 [thread overview]
Message-ID: <92d1bd15-662a-9765-d61c-babdf34abb57@woven.toyota> (raw)
In-Reply-To: <ZJVz36AR8Daxpj8H@kam.mff.cuni.cz>
On 23/06/2023 19:28, Jan Hubicka wrote:
>>>
>>> gcc/ChangeLog:
>>>
>>> * builtins.cc (expand_builtin_fork_or_exec): Check
>>> profile_condition_flag.
>>> * collect2.cc (main): Add -fno-profile-conditions to OBSTACK.
>>> * common.opt: Add new options -fprofile-conditions and
>>> * doc/gcov.texi: Add --conditions documentation.
>>> * doc/invoke.texi: Add -fprofile-conditions documentation.
>>> * gcc.cc: Link gcov on -fprofile-conditions.
>>> * gcov-counter.def (GCOV_COUNTER_CONDS): New.
>>> * gcov-dump.cc (tag_conditions): New.
>>> * gcov-io.h (GCOV_TAG_CONDS): New.
>>> (GCOV_TAG_CONDS_LENGTH): Likewise.
>>> (GCOV_TAG_CONDS_NUM): Likewise.
>>> * gcov.cc (class condition_info): New.
>>> (condition_info::condition_info): New.
>>> (condition_info::popcount): New.
>>> (struct coverage_info): New.
>>> (add_condition_counts): New.
>>> (output_conditions): New.
>>> (print_usage): Add -g, --conditions.
>>> (process_args): Likewise.
>>> (output_intermediate_json_line): Output conditions.
>>> (read_graph_file): Read conditions counters.
>>> (read_count_file): Read conditions counters.
>>> (file_summary): Print conditions.
>>> (accumulate_line_info): Accumulate conditions.
>>> (output_line_details): Print conditions.
>>> * ipa-inline.cc (can_early_inline_edge_p): Check
>>> profile_condition_flag.
>>> * ipa-split.cc (pass_split_functions::gate): Likewise.
>>> * passes.cc (finish_optimization_passes): Likewise.
>>> * profile.cc (find_conditions): New declaration.
>>> (cov_length): Likewise.
>>> (cov_blocks): Likewise.
>>> (cov_masks): Likewise.
>>> (cov_free): Likewise.
>>> (instrument_decisions): New.
>>> (read_thunk_profile): Control output to file.
>>> (branch_prob): Call find_conditions, instrument_decisions.
>>> (init_branch_prob): Add total_num_conds.
>>> (end_branch_prob): Likewise.
>>> * tree-profile.cc (struct conds_ctx): New.
>>> (CONDITIONS_MAX_TERMS): New.
>>> (EDGE_CONDITION): New.
>>> (cmp_index_map): New.
>>> (index_of): New.
>>> (block_conditional_p): New.
>>> (edge_conditional_p): New.
>>> (single): New.
>>> (single_edge): New.
>>> (contract_edge): New.
>>> (contract_edge_up): New.
>>> (ancestors_of): New.
>>> (struct outcomes): New.
>>> (conditional_succs): New.
>>> (condition_index): New.
>>> (masking_vectors): New.
>>> (cond_reachable_from): New.
>>> (neighborhood): New.
>>> (isolate_expression): New.
>>> (emit_bitwise_op): New.
>>> (make_index_map_visit): New.
>>> (make_index_map): New.
>>> (collect_conditions): New.
>>> (yes): New.
>>> (struct condcov): New.
>>> (cov_length): New.
>>> (cov_blocks): New.
>>> (cov_masks): New.
>>> (cov_free): New.
>>> (find_conditions): New.
>>> (instrument_decisions): New.
>>> (tree_profiling): Check profile_condition_flag.
>>> (pass_ipa_tree_profile::gate): Likewise.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> * lib/gcov.exp: Add condition coverage test function.
>>> * g++.dg/gcov/gcov-18.C: New test.
>>> * gcc.misc-tests/gcov-19.c: New test.
>>> * gcc.misc-tests/gcov-20.c: New test.
>>> * gcc.misc-tests/gcov-21.c: New test.
>>> ---
>>>
>>> v2:
>>> * Moved the docs to rst/sphinx
>>> * Output and message uses the 'conditions outcomes' vocabulary
>>> * Fixed errors reported by contrib/style-check. Note that a few
>>> warnings persist but are either in comments (ascii art) or because
>>> the surrounding code (typically lists) are formatted the same way
>>> v3:
>>> * Revert docs from rst/sphinx to texinfo
>>> v4:
>>> * Rebased on trunk, removed @gol from texi
>>>
>>> gcc/builtins.cc | 2 +-
>>> gcc/collect2.cc | 7 +-
>>> gcc/common.opt | 8 +
>>> gcc/doc/gcov.texi | 37 +
>>> gcc/doc/invoke.texi | 19 +
>>> gcc/gcc.cc | 4 +-
>>> gcc/gcov-counter.def | 3 +
>>> gcc/gcov-dump.cc | 24 +
>>> gcc/gcov-io.h | 3 +
>>> gcc/gcov.cc | 200 +++-
>>> gcc/ipa-inline.cc | 2 +-
>>> gcc/ipa-split.cc | 3 +-
>>> gcc/passes.cc | 3 +-
>>> gcc/profile.cc | 84 +-
>>> gcc/testsuite/g++.dg/gcov/gcov-18.C | 234 +++++
>>> gcc/testsuite/gcc.misc-tests/gcov-19.c | 1250 ++++++++++++++++++++++++
>>> gcc/testsuite/gcc.misc-tests/gcov-20.c | 22 +
>>> gcc/testsuite/gcc.misc-tests/gcov-21.c | 16 +
>>> gcc/testsuite/lib/gcov.exp | 191 +++-
>>> gcc/tree-profile.cc | 1048 +++++++++++++++++++-
>>> libgcc/libgcov-merge.c | 5 +
>>> 21 files changed, 3137 insertions(+), 28 deletions(-)
>>> create mode 100644 gcc/testsuite/g++.dg/gcov/gcov-18.C
>>> create mode 100644 gcc/testsuite/gcc.misc-tests/gcov-19.c
>>> create mode 100644 gcc/testsuite/gcc.misc-tests/gcov-20.c
>>> create mode 100644 gcc/testsuite/gcc.misc-tests/gcov-21.c
>>>
>>> diff --git a/gcc/builtins.cc b/gcc/builtins.cc
>>> index 8400adaf5b4..c71124a5615 100644
>>> --- a/gcc/builtins.cc
>>> +++ b/gcc/builtins.cc
>>> @@ -5902,7 +5902,7 @@ expand_builtin_fork_or_exec (tree fn, tree exp, rtx target, int ignore)
>>> tree call;
>>>
>>> /* If we are not profiling, just call the function. */
>>> - if (!profile_arc_flag)
>>> + if (!profile_arc_flag && !profile_condition_flag)
>
> I think profile_condition_flag can simpy imply profile_arc_flag.
> This is an information you always measure in adition to the usual bb
> profile, right?
>
> This can be arranged in opts.c and would avoid need to test both flags
> throughout the compiler.
> Or can both profiles be used independently?
Both can be used independently, and you might actually want to - for branch
coverage (was every branch taken at least once?) the profile-arc instrumentation
was sufficient, but redundant if you also want condition coverage. However,
profile-arcs also give you branch *counts* which is useful for data-driven
decisions.
Now, we might want to have --coverage imply profile-conditions.
>>> return NULL_RTX;
>>>
>>> /* Otherwise call the wrapper. This should be equivalent for the rest of
>>> diff --git a/gcc/collect2.cc b/gcc/collect2.cc
>>> index 63b9a0c233a..12ff5d81424 100644
>>> --- a/gcc/collect2.cc
>>> +++ b/gcc/collect2.cc
>>> @@ -1032,9 +1032,9 @@ main (int argc, char **argv)
>>> lto_mode = LTO_MODE_LTO;
>>> }
>>>
>>> - /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities
>>> - -fno-exceptions -w -fno-whole-program */
>>> - num_c_args += 6;
>>> + /* -fno-profile-arcs -fno-profile-conditions -fno-test-coverage
>>> + -fno-branch-probabilities -fno-exceptions -w -fno-whole-program */
>>> + num_c_args += 7;
>>>
>>> c_argv = XCNEWVEC (char *, num_c_args);
>>> c_ptr = CONST_CAST2 (const char **, char **, c_argv);
>>> @@ -1230,6 +1230,7 @@ main (int argc, char **argv)
>>> }
>>> obstack_free (&temporary_obstack, temporary_firstobj);
>>> *c_ptr++ = "-fno-profile-arcs";
>>> + *c_ptr++ = "-fno-profile-conditions";
> If this was initialized from an array of strings, we can avoid need for
> num_c_args to be computed by hand....
>>> *c_ptr++ = "-fno-test-coverage";
>>> *c_ptr++ = "-fno-branch-probabilities";
>>> *c_ptr++ = "-fno-exceptions";
>>> diff --git a/gcc/common.opt b/gcc/common.opt
>>> index a28ca13385a..e32a5f7b0db 100644
>>> --- a/gcc/common.opt
>>> +++ b/gcc/common.opt
>>> @@ -862,6 +862,10 @@ Wcoverage-invalid-line-number
>>> Common Var(warn_coverage_invalid_linenum) Init(1) Warning
>>> Warn in case a function ends earlier than it begins due to an invalid linenum macros.
>>>
>>> +Wcoverage-too-many-conditions
>>> +Common Var(warn_too_many_conditions) Init(1) Warning
>>> +Warn when a conditional has too many terms and coverage gives up.
>
> Maybe when user reads it in --help, he/she will not know what coverage
> you means. It is called condition coverage profiling later, so we can
> stick to this term here.
>>> +
>>> Wmissing-profile
>>> Common Var(warn_missing_profile) Init(1) Warning
>>> Warn in case profiles in -fprofile-use do not exist.
>>> @@ -2351,6 +2355,10 @@ fprofile-arcs
>>> Common Var(profile_arc_flag)
>>> Insert arc-based program profiling code.
>>>
>>> +fprofile-conditions
>>> +Common Var(profile_condition_flag)
>>> +Insert condition coverage profiling code.
>>> +
>>> fprofile-dir=
>>> Common Joined RejectNegative Var(profile_data_prefix)
>>> Set the top-level directory for storing the profile data.
>>> diff --git a/gcc/doc/gcov.texi b/gcc/doc/gcov.texi
>>> index 3019efc4674..10cfdcf24aa 100644
>>> --- a/gcc/doc/gcov.texi
>>> +++ b/gcc/doc/gcov.texi
>>> @@ -124,6 +124,7 @@ gcov [@option{-v}|@option{--version}] [@option{-h}|@option{--help}]
>>> [@option{-a}|@option{--all-blocks}]
>>> [@option{-b}|@option{--branch-probabilities}]
>>> [@option{-c}|@option{--branch-counts}]
>>> + [@option{-g}|@option{--conditions}]
>>> [@option{-d}|@option{--display-progress}]
>>> [@option{-f}|@option{--function-summaries}]
>>> [@option{-j}|@option{--json-format}]
>>> @@ -169,6 +170,13 @@ be shown, unless the @option{-u} option is given.
>>> Write branch frequencies as the number of branches taken, rather than
>>> the percentage of branches taken.
>>>
>>> +@item -g
>>> +@itemx --conditions
>>> +Write condition coverage to the output file, and write condition summary info
>>> +to the standard output. This option allows you to see if the conditions in
>>> +your program at least once had an independent effect on the outcome of the
>>> +boolean expression (modified condition/decision coverage).
>
> Maybe you want to like -fprofile-conditions flag here, since that is
> needed at the instrumentaiton time.
>>> +@opindex Wno-coverage-too-many-conditions
>>> +@opindex Wcoverage-too-many-conditions
>>> +@item -Wno-coverage-too-many-conditions
>>> +Warn in case a condition have too many terms and GCC gives up coverage.
>>> +Coverage is given up when there are more terms in the conditional than there
>>> +are bits in a @code{gcov_type_unsigned}. This warning is enabled by default.
>
> Here you can explicitly mention -fprofile-conditions so user knows what
> kind of coverage you refer to.
>>> +
>>> @opindex Wno-coverage-invalid-line-number
>>> @opindex Wcoverage-invalid-line-number
>>> @item -Wno-coverage-invalid-line-number
>>> @@ -16430,6 +16438,13 @@ Note that if a command line directly links source files, the corresponding
>>> E.g. @code{gcc a.c b.c -o binary} would generate @file{binary-a.gcda} and
>>> @file{binary-b.gcda} files.
>>>
>>> +@item -fprofile-conditions
>>> +@opindex fprofile-conditions
>>> +Add code so that program conditions are instrumented. During execution the
>>> +program records what terms in a conditional contributes to a decision. The
>>> +data may be used to verify that all terms in a booleans are tested and have an
>>> +effect on the outcome of a condition.
>
> I would say that the result can be read with gcov --conditions
>>> @@ -392,6 +394,28 @@ tag_arcs (const char *filename ATTRIBUTE_UNUSED,
>>> }
>>> }
>>>
>>> +static void
>>> +tag_conditions (const char *filename ATTRIBUTE_UNUSED,
>>> + unsigned tag ATTRIBUTE_UNUSED, int length ATTRIBUTE_UNUSED,
>>> + unsigned depth)
> Coding style wants us to have a comment before functions
> summarizing what they do.
> Also with C++, one can ust skip "filename ATTRIBUTE_UNUSED" for unused
> args.
>>> diff --git a/gcc/gcov.cc b/gcc/gcov.cc
>>> index 2fad6aa7ede..ffedbb37483 100644
>>> --- a/gcc/gcov.cc
>>> +++ b/gcc/gcov.cc
>>> @@ -81,6 +81,7 @@ using namespace std;
>>> class function_info;
>>> class block_info;
>>> class source_info;
>>> +class condition_info;
>>>
>>> /* Describes an arc between two basic blocks. */
>>>
>>> @@ -134,6 +135,28 @@ public:
>>> vector<unsigned> lines;
>>> };
>>>
>>> +class condition_info
> Also block comment here.
>>> +{
>>> +public:
>>> + condition_info ();
>>> +
>>> + int popcount () const;
>>> +
>>> + gcov_type_unsigned truev;
>>> + gcov_type_unsigned falsev;
>>> +
>>> + unsigned n_terms;
>>> +};
>>> +
>>> +condition_info::condition_info (): truev (0), falsev (0), n_terms (0)
>>> +{
>>> +}
>>> +
>>> +int condition_info::popcount () const
>>> +{
>>> + return __builtin_popcountll (truev) + __builtin_popcountll (falsev);
> If you build with --disable-bootstrap and use non-GCC host compiler, I
> don't think we have a promise of __builtin_popcountll being supported.
> THere is popcount_hwi in hwint.h
>>> @@ -2456,6 +2573,13 @@ add_branch_counts (coverage_info *coverage, const arc_info *arc)
>>> }
>>> }
>>>
>>> +static void
>>> +add_condition_counts (coverage_info *coverage, const block_info *block)
> Similarly here block comment will make coding conventions happy
>>> +{
>>> + coverage->conditions += 2 * block->conditions.n_terms;
>>> + coverage->conditions_covered += block->conditions.popcount ();
>>> +}
>>> +
>>> /* Format COUNT, if flag_human_readable_numbers is set, return it human
>>> readable format. */
>>>
>>> @@ -2559,6 +2683,18 @@ file_summary (const coverage_info *coverage)
>>> coverage->calls);
>>> else
>>> fnotice (stdout, "No calls\n");
>>> +
>>> + }
>>> +
>>> + if (flag_conditions)
>>> + {
>>> + if (coverage->conditions)
>>> + fnotice (stdout, "Condition outcomes covered:%s of %d\n",
>>> + format_gcov (coverage->conditions_covered,
>>> + coverage->conditions, 2),
>>> + coverage->conditions);
>>> + else
>>> + fnotice (stdout, "No conditions\n");
>>> }
>>> }
>>>
>>> @@ -2793,6 +2929,12 @@ static void accumulate_line_info (line_info *line, source_info *src,
>>> it != line->branches.end (); it++)
>>> add_branch_counts (&src->coverage, *it);
>>>
>>> + if (add_coverage)
>>> + for (vector<block_info *>::iterator it = line->blocks.begin ();
>>> + it != line->blocks.end (); it++)
>>> + add_condition_counts (&src->coverage, *it);
>>> +
>>> +
>>> if (!line->blocks.empty ())
>>> {
>>> /* The user expects the line count to be the number of times
>>> @@ -2894,6 +3036,33 @@ accumulate_line_counts (source_info *src)
>>> }
>>> }
>>>
>>> +static void
>>> +output_conditions (FILE *gcov_file, const block_info *binfo)
> Again, I think we want a comment (even though it is easy to figure out
> what it does).
>>> +{
>>> + const condition_info& info = binfo->conditions;
>>> + if (info.n_terms == 0)
>>> + return;
>>> +
>>> + const int expected = 2 * info.n_terms;
>>> + const int got = info.popcount ();
>>> +
>>> + fnotice (gcov_file, "condition outcomes covered %d/%d\n", got, expected);
>>> + if (expected == got)
>>> + return;
>>> +
>>> + for (unsigned i = 0; i < info.n_terms; i++)
>>> + {
>>> + gcov_type_unsigned index = 1;
>>> + index <<= i;
>>> + if ((index & info.truev & info.falsev))
>>> + continue;
>>> +
>>> + const char *t = (index & info.truev) ? "" : "true";
>>> + const char *f = (index & info.falsev) ? "" : " false";
>>> + fnotice (gcov_file, "condition %2u not covered (%s%s)\n", i, t, f + !t[0]);
>>> + }
>>> +}
>>> +
>>> /* Output information about ARC number IX. Returns nonzero if
>>> anything is output. */
>>>
>>> @@ -3104,16 +3273,29 @@ output_line_details (FILE *f, const line_info *line, unsigned line_num)
>>> if (flag_branches)
>>> for (arc = (*it)->succ; arc; arc = arc->succ_next)
>>> jx += output_branch_count (f, jx, arc);
>>> +
>>> + if (flag_conditions)
>>> + output_conditions (f, *it);
>>> }
>>> }
>>> - else if (flag_branches)
>>> + else
>>> {
>>> - int ix;
>>> + if (flag_branches)
>>> + {
>>> + int ix;
>>> +
>>> + ix = 0;
>>> + for (vector<arc_info *>::const_iterator it = line->branches.begin ();
>>> + it != line->branches.end (); it++)
>>> + ix += output_branch_count (f, ix, (*it));
>>> + }
>>>
>>> - ix = 0;
>>> - for (vector<arc_info *>::const_iterator it = line->branches.begin ();
>>> - it != line->branches.end (); it++)
>>> - ix += output_branch_count (f, ix, (*it));
>>> + if (flag_conditions)
>>> + {
>>> + for (vector<block_info *>::const_iterator it = line->blocks.begin ();
>>> + it != line->blocks.end (); it++)
>>> + output_conditions (f, *it);
>>> + }
>
> The gcov tool bits seems good to me except the nits above. I will
> continue reading the instrumentation part and write incrementally.
>
> Honza
I kept the profile-arcs/profille-coverage inline, but for the other feedback you
can consider it applied. I'll create some new patches to address them, then
squash them post-review. Thanks!
Jørgen
prev parent reply other threads:[~2023-06-30 6:53 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-13 0:59 Jørgen Kvalsvik
2023-06-23 10:11 ` Ping " Jørgen Kvalsvik
2023-06-23 10:28 ` Jan Hubicka
2023-06-30 6:53 ` Jørgen Kvalsvik [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=92d1bd15-662a-9765-d61c-babdf34abb57@woven.toyota \
--to=jorgen.kvalsvik@woven.toyota \
--cc=gcc-patches@gcc.gnu.org \
--cc=hubicka@ucw.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).