From: "Martin Liška" <mliska@suse.cz>
To: "Jørgen Kvalsvik" <jorgen.kvalsvik@woven-planet.global>,
gcc-patches@gcc.gnu.org
Cc: "Jørgen Kvalsvik" <j@lambda.is>
Subject: Re: [PATCH v2] Add condition coverage profiling
Date: Thu, 1 Dec 2022 16:05:24 +0100 [thread overview]
Message-ID: <8a187659-7f64-e760-5732-6bbd6f18eb11@suse.cz> (raw)
In-Reply-To: <20221111052141.29815-1-jorgen.kvalsvik@woven-planet.global>
On 11/11/22 06:21, Jørgen Kvalsvik wrote:
> From: Jørgen Kvalsvik <j@lambda.is>
>
> This patch adds support in gcc+gcov for modified condition/decision
> coverage (MC/DC) with the -fprofile-conditions flag. MC/DC is a type of
> test/code coverage and it is particularly important in the avation and
> automotive industries for safety-critical applications. MC/DC it is
> required for or recommended by:
>
> * DO-178C for the most critical software (Level A) in avionics
> * IEC 61508 for SIL 4
> * ISO 26262-6 for ASIL D
>
> From the SQLite webpage:
>
> Two methods of measuring test coverage were described above:
> "statement" and "branch" coverage. There are many other test
> coverage metrics besides these two. Another popular metric is
> "Modified Condition/Decision Coverage" or MC/DC. Wikipedia defines
> MC/DC as follows:
>
> * Each decision tries every possible outcome.
> * Each condition in a decision takes on every possible outcome.
> * Each entry and exit point is invoked.
> * Each condition in a decision is shown to independently affect
> the outcome of the decision.
>
> In the C programming language where && and || are "short-circuit"
> operators, MC/DC and branch coverage are very nearly the same thing.
> The primary difference is in boolean vector tests. One can test for
> any of several bits in bit-vector and still obtain 100% branch test
> coverage even though the second element of MC/DC - the requirement
> that each condition in a decision take on every possible outcome -
> might not be satisfied.
>
> https://sqlite.org/testing.html#mcdc
>
> Wahlen, Heimdahl, and De Silva "Efficient Test Coverage Measurement for
> MC/DC" describes an algorithm for adding instrumentation by carrying
> over information from the AST, but my algorithm analyses the the control
> flow graph to instrument for coverage. This has the benefit of being
> programming language independent and faithful to compiler decisions
> and transformations, although I have only tested it on constructs in C
> and C++, see testsuite/gcc.misc-tests and testsuite/g++.dg.
>
> Like Wahlen et al this implementation records coverage in fixed-size
> bitsets which gcov knows how to interpret. This is very fast, but
> introduces a limit on the number of terms in a single boolean
> expression, the number of bits in a gcov_unsigned_type (which is
> typedef'd to uint64_t), so for most practical purposes this would be
> acceptable. This limitation is in the implementation and not the
> algorithm, so support for more conditions can be added by also
> introducing arbitrary-sized bitsets.
>
> For space overhead, the instrumentation needs two accumulators
> (gcov_unsigned_type) per condition in the program which will be written
> to the gcov file. In addition, every function gets a pair of local
> accumulators, but these accmulators are reused between conditions in the
> same function.
>
> For time overhead, there is a zeroing of the local accumulators for
> every condition and one or two bitwise operation on every edge taken in
> the an expression.
>
> In action it looks pretty similar to the branch coverage. The -g short
> opt carries no significance, but was chosen because it was an available
> option with the upper-case free too.
>
> gcov --conditions:
>
> 3: 17:void fn (int a, int b, int c, int d) {
> 3: 18: if ((a && (b || c)) && d)
> condition outcomes covered 3/8
> condition 0 not covered (true false)
> condition 1 not covered (true)
> condition 2 not covered (true)
> condition 3 not covered (true)
> 1: 19: x = 1;
> -: 20: else
> 2: 21: x = 2;
> 3: 22:}
>
> gcov --conditions --json-format:
>
> "conditions": [
> {
> "not_covered_false": [
> 0
> ],
> "count": 8,
> "covered": 3,
> "not_covered_true": [
> 0,
> 1,
> 2,
> 3
> ]
> }
> ],
>
> Some expressions, mostly those without else-blocks, are effectively
> "rewritten" in the CFG construction making the algorithm unable to
> distinguish them:
>
> and.c:
>
> if (a && b && c)
> x = 1;
>
> ifs.c:
>
> if (a)
> if (b)
> if (c)
> x = 1;
>
> gcc will build the same graph for both these programs, and gcov will
> report boths as 3-term expressions. It is vital that it is not
> interpreted the other way around (which is consistent with the shape of
> the graph) because otherwise the masking would be wrong for the and.c
> program which is a more severe error. While surprising, users would
> probably expect some minor rewriting of semantically-identical
> expressions.
>
> and.c.gcov:
> #####: 2: if (a && b && c)
> condition outcomes covered 6/6
> #####: 3: x = 1;
>
> ifs.c.gcov:
> #####: 2: if (a)
> #####: 3: if (b)
> #####: 4: if (c)
> #####: 5: x = 1;
> condition outcomes covered 6/6
>
> Adding else clauses alters the program (ifs.c can have 3 elses, and.c
> only 1) and coverage becomes less surprising
>
> ifs.c.gcov:
> #####: 2: if (a)
> condition outcomes covered 2/2
> #####: 4: {
> #####: 4: if (b)
> condition outcomes covered 2/2
> 5: {
> #####: 6: if (c)
> condition outcomes covered 2/2
> #####: 7: x = 1;
> #####: 8: }
> #####: 9: else
> #####: 10: x = 2;
> #####: 11: }
> #####: 12: else
> #####: 13: x = 3;
>
> Since the algorithm works on CFGs, it cannot detect some ternary
> operator introduced conditionals. For example, int x = a ? 0 : 1 in
> gimple becomes _x = (_a == 0). From source you would expect coverage,
> but it gets neither branch nor condition coverage. For completeness, it
> could be achieved by scanning all gimple statements for such
> comparisons, and insert an extra instruction for recording the outcome.
>
Hello.
Thanks for the rebased version of the patch. Please, update the documentation
bits as the Sphinx conversion didn't make it. Sorry for that.
I approve the GCOV-part of the patch and I'm fine with the rest of the patch
(though I can't approve it).
What a nice work!
Cheers,
Martin
next prev parent reply other threads:[~2022-12-01 15:05 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-11 5:21 Jørgen Kvalsvik
2022-12-01 15:05 ` Martin Liška [this message]
2022-12-02 1:03 ` Jørgen Kvalsvik
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=8a187659-7f64-e760-5732-6bbd6f18eb11@suse.cz \
--to=mliska@suse.cz \
--cc=gcc-patches@gcc.gnu.org \
--cc=j@lambda.is \
--cc=jorgen.kvalsvik@woven-planet.global \
/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).