From: Xinliang David Li <davidxl@google.com>
To: "Sharad Singhai (शरद सिंघई)" <singhai@google.com>
Cc: Richard Guenther <richard.guenther@gmail.com>,
GCC Patches <gcc-patches@gcc.gnu.org>,
reply@codereview.appspotmail.com
Subject: Re: [google] Add intermediate text format for gcov (issue4595053)
Date: Thu, 16 Jun 2011 00:43:00 -0000 [thread overview]
Message-ID: <BANLkTi=Vn=AEGnZnzjZzkd2_aM8+fWoopAzAHAJCGQn3pKtFLw@mail.gmail.com> (raw)
In-Reply-To: <BANLkTinDXGBP+V0fUksgGPRAEzpJFUCPUvESpuT57N+gVC3irQ@mail.gmail.com>
Ok for google/main.
David
On Tue, Jun 14, 2011 at 1:50 PM, Sharad Singhai (शरद सिंघई)
<singhai@google.com> wrote:
> Sorry, Rietveld didn't send out the updated patch along with my mail.
> Here it is.
>
> Sharad
>
> 2011-06-14 Sharad Singhai <singhai@google.com>
>
> Google Ref 39999
>
> * doc/gcov.texi: Document gcov intermediate format.
> * gcov.c (get_gcov_file_intermediate_name): New function.
> (output_intermediate_file): New function.
> * testsuite/lib/gcov.exp: Handle intermediate format.
> * testsuite/g++.dg/gcov/gcov-7.C: New test.
>
> Index: doc/gcov.texi
> ===================================================================
> --- doc/gcov.texi (revision 174926)
> +++ doc/gcov.texi (working copy)
> @@ -130,6 +130,7 @@
> [@option{-f}|@option{--function-summaries}]
> [@option{-o}|@option{--object-directory} @var{directory|file}]
> @var{sourcefiles}
> [@option{-u}|@option{--unconditional-branches}]
> + [@option{-i}|@option{--intermediate-format}]
> [@option{-d}|@option{--display-progress}]
> @c man end
> @c man begin SEEALSO
> @@ -216,6 +217,32 @@
> @itemx --display-progress
> Display the progress on the standard output.
>
> +@item -i
> +@itemx --intermediate-format
> +Output gcov file in an intermediate text format that can be used by
> +@command{lcov} or other applications. It will output a single *.gcov file per
> +*.gcda file. No source code is required.
> +
> +The format of the intermediate @file{.gcov} file is plain text with
> +one entry per line
> +
> +@smallexample
> +SF:@var{source_file_name}
> +FN:@var{line_number},@var{function_name}
> +FNDA:@var{execution_count},@var{function_name}
> +BA:@var{line_num},@var{branch_coverage_type}
> +DA:@var{line number},@var{execution_count}
> +
> +Where the @var{branch_coverage_type} is
> + 0 (Branch not executed)
> + 1 (Branch executed, but not taken)
> + 2 (Branch executed and taken)
> +
> +There can be multiple SF entries in an intermediate gcov file. All
> +entries following SF pertain to that source file until the next SF
> +entry.
> +@end smallexample
> +
> @end table
>
> @command{gcov} should be run with the current directory the same as that
> Index: gcov.c
> ===================================================================
> --- gcov.c (revision 174926)
> +++ gcov.c (working copy)
> @@ -38,6 +38,7 @@
> #include "tm.h"
> #include "intl.h"
> #include "version.h"
> +#include "demangle.h"
>
> #include <getopt.h>
>
> @@ -310,6 +311,9 @@
>
> static int flag_display_progress = 0;
>
> +/* Output *.gcov file in intermediate format used by 'lcov'. */
> +static int flag_intermediate_format = 0;
> +
> /* For included files, make the gcov output file name include the name
> of the input source file. For example, if x.h is included in a.c,
> then the output file name is a.c##x.h.gcov instead of x.h.gcov. */
> @@ -436,6 +440,11 @@
> fnotice (file, " -o, --object-directory DIR|FILE Search for object
> files in DIR or called FILE\n");
> fnotice (file, " -p, --preserve-paths Preserve all
> pathname components\n");
> fnotice (file, " -u, --unconditional-branches Show
> unconditional branch counts too\n");
> + fnotice (file, " -i, --intermediate-format Output .gcov file
> in an intermediate text\n\
> + format that can be used by 'lcov'
> or other\n\
> + applications. It will output a single\n\
> + .gcov file per .gcda file. No
> source file\n\
> + is required.\n");
> fnotice (file, " -d, --display-progress Display progress
> information\n");
> fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
> bug_report_url);
> @@ -472,6 +481,7 @@
> { "object-file", required_argument, NULL, 'o' },
> { "unconditional-branches", no_argument, NULL, 'u' },
> { "display-progress", no_argument, NULL, 'd' },
> + { "intermediate-format", no_argument, NULL, 'i' },
> { 0, 0, 0, 0 }
> };
>
> @@ -482,7 +492,8 @@
> {
> int opt;
>
> - while ((opt = getopt_long (argc, argv, "abcdfhlno:puv", options,
> NULL)) != -1)
> + while ((opt = getopt_long (argc, argv, "abcdfhilno:puv", options, NULL)) !=
> + -1)
> {
> switch (opt)
> {
> @@ -516,6 +527,10 @@
> case 'u':
> flag_unconditional = 1;
> break;
> + case 'i':
> + flag_intermediate_format = 1;
> + flag_gcov_file = 1;
> + break;
> case 'd':
> flag_display_progress = 1;
> break;
> @@ -531,6 +546,109 @@
> return optind;
> }
>
> +/* Get the name of the gcov file. The return value must be free'd.
> +
> + It appends the '.gcov' extension to the *basename* of the file.
> + The resulting file name will be in PWD.
> +
> + e.g.,
> + input: foo.da, output: foo.da.gcov
> + input: a/b/foo.cc, output: foo.cc.gcov */
> +
> +static char *
> +get_gcov_file_intermediate_name (const char *file_name)
> +{
> + const char *gcov = ".gcov";
> + char *result;
> + const char *cptr;
> +
> + /* Find the 'basename'. */
> + cptr = lbasename (file_name);
> +
> + result = XNEWVEC(char, strlen (cptr) + strlen (gcov) + 1);
> + sprintf (result, "%s%s", cptr, gcov);
> +
> + return result;
> +}
> +
> +/* Output the result in intermediate format used by 'lcov'.
> +
> +This format contains a single file named 'foo.cc.gcov', with no source
> +code included.
> +
> +SF:/home/.../foo.h
> +DA:10,1
> +DA:30,0
> +DA:35,1
> +SF:/home/.../bar.h
> +DA:12,0
> +DA:33,0
> +DA:55,1
> +SF:/home/.../foo.cc
> +FN:30,<function_name>
> +FNDA:2,<function_name>
> +DA:42,0
> +DA:53,1
> +BA:55,1
> +BA:55,2
> +DA:95,1
> +...
> +
> +The default format contains 3 separate files: 'foo.h.gcov', 'foo.cc.gcov',
> +'bar.h.gcov', each with source code included. */
> +
> +static void
> +output_intermediate_file (FILE *gcov_file, source_t *src)
> +{
> + unsigned line_num; /* current line number. */
> + const line_t *line; /* current line info ptr. */
> + function_t *fn; /* current function info ptr. */
> +
> + fprintf (gcov_file, "SF:%s\n", src->name); /* source file name */
> +
> + /* NOTE: 'gcov' sometimes output 2 extra lines (including 1 EOF line)
> + in the end, search for string *EOF* in this file.
> +
> + Likely related:
> + http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30257
> + http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24550 */
> +
> + for (fn = src->functions; fn; fn = fn->line_next)
> + {
> + char *demangled_name;
> + demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
> + /* FN:<line_number>,<function_name> */
> + fprintf (gcov_file, "FN:%d,%s\n", fn->line,
> + demangled_name ? demangled_name : fn->name);
> + /* FNDA:<execution_count>,<function_name> */
> + fprintf (gcov_file, "FNDA:%s,%s\n",
> + format_gcov (fn->blocks[0].count, 0, -1),
> + demangled_name ? demangled_name : fn->name);
> + }
> +
> + for (line_num = 1, line = &src->lines[line_num];
> + line_num < src->num_lines;
> + line_num++, line++)
> + {
> + arc_t *arc;
> + if (line->exists)
> + fprintf (gcov_file, "DA:%u,%d\n", line_num,
> + line->count != 0 ? 1 : 0);
> + if (flag_branches)
> + for (arc = line->u.branches; arc; arc = arc->line_next)
> + {
> + /* BA:<line_num>,<branch_coverage_type>
> + branch_coverage_type: 0 (Branch not executed)
> + : 1 (Branch executed, but not taken)
> + : 2 (Branch executed and taken)
> + */
> + if (!arc->is_unconditional && !arc->is_call_non_return)
> + fprintf(gcov_file, "BA:%d,%d\n", line_num,
> + arc->src->count ? (arc->count > 0) + 1 : 0);
> + }
> + }
> +}
> +
> /* Process a single source file. */
>
> static void
> @@ -547,7 +665,7 @@
>
> create_file_names (file_name);
> if (read_graph_file ())
> - return;
> + exit (FATAL_EXIT_CODE);
>
> if (!functions)
> {
> @@ -556,7 +674,7 @@
> }
>
> if (read_count_file ())
> - return;
> + exit (FATAL_EXIT_CODE);
>
> for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn->next)
> solve_flow_graph (fn);
> @@ -570,6 +688,8 @@
> {
> source_t *src;
> function_t *fn;
> + FILE *gcov_file_intermediate = NULL;
> + char *gcov_file_intermediate_name = NULL;
>
> for (src = sources; src; src = src->next)
> src->lines = XCNEWVEC (line_t, src->num_lines);
> @@ -587,32 +707,56 @@
> }
> }
>
> + if (flag_gcov_file && flag_intermediate_format)
> + {
> + /* We open the file now. */
> + gcov_file_intermediate_name =
> + get_gcov_file_intermediate_name (file_name);
> + gcov_file_intermediate = fopen (gcov_file_intermediate_name, "w");
> + }
> for (src = sources; src; src = src->next)
> {
> accumulate_line_counts (src);
> function_summary (&src->coverage, "File");
> if (flag_gcov_file)
> {
> - char *gcov_file_name = make_gcov_file_name (file_name, src->name);
> - FILE *gcov_file = fopen (gcov_file_name, "w");
> + if (flag_intermediate_format)
> + /* Now output in the intermediate format without requiring
> + source files. This outputs a section to a *single* file. */
> + output_intermediate_file (gcov_file_intermediate, src);
> + else
> + {
> + /* Now output the version with source files.
> + This outputs a separate *.gcov file for each source file
> + involved. */
> + char *gcov_file_name = make_gcov_file_name (file_name, src->name);
> + FILE *gcov_file = fopen (gcov_file_name, "w");
>
> - if (gcov_file)
> - {
> - fnotice (stdout, "%s:creating '%s'\n",
> - src->name, gcov_file_name);
> - output_lines (gcov_file, src);
> - if (ferror (gcov_file))
> - fnotice (stderr, "%s:error writing output file '%s'\n",
> - src->name, gcov_file_name);
> - fclose (gcov_file);
> - }
> - else
> - fnotice (stderr, "%s:could not open output file '%s'\n",
> - src->name, gcov_file_name);
> - free (gcov_file_name);
> - }
> - fnotice (stdout, "\n");
> + if (gcov_file)
> + {
> + fnotice (stdout, "%s:creating '%s'\n",
> + src->name, gcov_file_name);
> + output_lines (gcov_file, src);
> + if (ferror (gcov_file))
> + fnotice (stderr, "%s:error writing output file '%s'\n",
> + src->name, gcov_file_name);
> + fclose (gcov_file);
> + }
> + else
> + fnotice (stderr, "%s:could not open output file '%s'\n",
> + src->name, gcov_file_name);
> + free (gcov_file_name);
> + }
> + fnotice (stdout, "\n");
> + }
> }
> +
> + if (flag_gcov_file && flag_intermediate_format)
> + {
> + /* Now we've finished writing the intermediate file. */
> + fclose (gcov_file_intermediate);
> + XDELETEVEC (gcov_file_intermediate_name);
> + }
> }
>
> /* Release all memory used. */
> @@ -841,6 +985,7 @@
> functions = fn;
> current_tag = tag;
>
> + /* NOTE: Here is how *EOF* comes to effect. */
> if (lineno >= src->num_lines)
> src->num_lines = lineno + 1;
> /* Now insert it into the source file's list of
> @@ -949,6 +1094,7 @@
> line_nos[ix++] = src->index;
> }
> line_nos[ix++] = lineno;
> + /* NOTE: Here is how *EOF* comes to effect. */
> if (lineno >= src->num_lines)
> src->num_lines = lineno + 1;
> }
> Index: testsuite/lib/gcov.exp
> ===================================================================
> --- testsuite/lib/gcov.exp (revision 174926)
> +++ testsuite/lib/gcov.exp (working copy)
> @@ -60,6 +60,59 @@
> }
>
> #
> +# verify-intermediate -- check that intermediate file has certain lines
> +#
> +# TESTCASE is the name of the test.
> +# FILE is the name of the gcov output file.
> +#
> +# Checks are very loose, they are based on being certain tags present
> +# in the output. They do not check for exact expected execution
> +# counts. For that the regular gcov format should be checked.
> +#
> +proc verify-intermediate { testcase file } {
> + set failed 0
> + set sf 0
> + set fn 0
> + set fnda 0
> + set da 0
> + set fd [open $file r]
> + while { [gets $fd line] >= 0 } {
> + if [regexp "^SF:" $line] {
> + incr sf
> + }
> + if [regexp "^FN:(\[0-9\]+)," $line] {
> + incr fn
> + }
> + if [regexp "^FNDA:(\[0-9\]+)," $line] {
> + incr fnda
> + }
> + if [regexp "^DA:(\[0-9\]+),(\[0-9\]+)" $line] {
> + incr da
> + }
> + }
> +
> + # We should see at least one tag of each type
> + if {$sf == 0} {
> + fail "expected SF: not found"
> + incr failed
> + }
> + if {$fn == 0} {
> + fail "expected FN: not found"
> + incr failed
> + }
> + if {$fnda == 0} {
> + fail "expected FNDA: not found"
> + incr failed
> + }
> + if {$da == 0} {
> + fail "expected DA: not found"
> + incr failed
> + }
> + return $failed
> +}
> +
> +
> +#
> # verify-branches -- check that branch percentages are as expected
> #
> # TESTCASE is the name of the test.
> @@ -234,6 +287,8 @@
>
> set gcov_verify_calls 0
> set gcov_verify_branches 0
> + set gcov_verify_lines 1
> + set gcov_verify_intermediate 0
> set gcov_execute_xfail ""
> set gcov_verify_xfail ""
>
> @@ -242,6 +297,11 @@
> set gcov_verify_calls 1
> } elseif { $a == "branches" } {
> set gcov_verify_branches 1
> + } elseif { $a == "intermediate" } {
> + set gcov_verify_intermediate 1
> + set gcov_verify_calls 0
> + set gcov_verify_branches 0
> + set gcov_verify_lines 0
> }
> }
>
> @@ -274,8 +334,12 @@
> eval setup_xfail [split $gcov_verify_xfail]
> }
>
> - # Check that line execution counts are as expected.
> - set lfailed [verify-lines $testcase $testcase.gcov]
> + if { $gcov_verify_lines } {
> + # Check that line execution counts are as expected.
> + set lfailed [verify-lines $testcase $testcase.gcov]
> + } else {
> + set lfailed 0
> + }
>
> # If requested via the .x file, check that branch and call information
> # is correct.
> @@ -289,12 +353,18 @@
> } else {
> set cfailed 0
> }
> + if { $gcov_verify_intermediate } {
> + # Check that intermediate format has the expected format
> + set ifailed [verify-intermediate $testcase $testcase.gcov]
> + } else {
> + set ifailed 0
> + }
>
> # Report whether the gcov test passed or failed. If there were
> # multiple failures then the message is a summary.
> - set tfailed [expr $lfailed + $bfailed + $cfailed]
> + set tfailed [expr $lfailed + $bfailed + $cfailed + $ifailed]
> if { $tfailed > 0 } {
> - fail "$subdir/$testcase gcov: $lfailed failures in line counts,
> $bfailed in branch percentages, $cfailed in return percentages"
> + fail "$subdir/$testcase gcov: $lfailed failures in line counts,
> $bfailed in branch percentages, $cfailed in return percentages,
> $ifailed in intermediate format"
> } else {
> pass "$subdir/$testcase gcov"
> clean-gcov $testcase
> Index: testsuite/g++.dg/gcov/gcov-7.C
> ===================================================================
> --- testsuite/g++.dg/gcov/gcov-7.C (revision 0)
> +++ testsuite/g++.dg/gcov/gcov-7.C (revision 0)
> @@ -0,0 +1,32 @@
> +/* Verify that intermediate coverage format can be generated for
> simple code. */
> +
> +/* { dg-options "-fprofile-arcs -ftest-coverage" } */
> +/* { dg-do run { target native } } */
> +
> +class C {
> +public:
> + C()
> + {
> + i = 0; /* count(1) */
> + }
> + ~C() {}
> + void seti (int j)
> + {
> + i = j; /* count(1) */
> + }
> +private:
> + int i;
> +};
> +
> +void foo()
> +{
> + C c; /* count(2) */
> + c.seti (1); /* count(1) */
> +}
> +
> +int main()
> +{
> + foo(); /* count(1) */
> +}
> +
> +/* { dg-final { run-gcov intermediate { -i gcov-7.C } } } */
>
next prev parent reply other threads:[~2011-06-15 23:07 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20cf303b397be95f9504a5b0f417@google.com>
2011-06-14 21:29 ` Sharad Singhai (शरद सिंघई)
2011-06-16 0:43 ` Xinliang David Li [this message]
2011-10-01 13:23 ` Matt Rice
2011-10-01 21:35 ` Sharad Singhai (शरद सिंघई)
2011-06-14 7:13 Sharad Singhai
2011-06-14 10:18 ` Richard Guenther
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='BANLkTi=Vn=AEGnZnzjZzkd2_aM8+fWoopAzAHAJCGQn3pKtFLw@mail.gmail.com' \
--to=davidxl@google.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=reply@codereview.appspotmail.com \
--cc=richard.guenther@gmail.com \
--cc=singhai@google.com \
/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).