Ping.

Thanks,
Sharad


On Tue, May 28, 2013 at 11:35 AM, Sharad Singhai <sing...@google.com> wrote:
> Sorry, my patch had bad formatting in one of the functions
> (output_gcov_file). Here is the corrected version.
>
> Thanks,
> Sharad
>
> (2013-05-28    <sing...@google.com>
>
> * gcov.c (print_usage): Handle new option.
> (process_args): Ditto.
> (get_gcov_intermediate_filename): New function.
> (output_intermediate_file): New function.
> (output_gcov_file): New function
> (generate_results): Handle new option.
> (release_function): Relase demangled name.
> (read_graph_file): Handle demangled name.
> (output_lines): Ditto.
> * doc/gcov.texi: Document gcov intermediate format.
>
> testsuite/ChangeLog:
>
> 2013-05-28   Sharad Singhai  <sing...@google.com>
>
> * g++.dg/gcov/gcov-8.C: New testcase.
> * lib/gcov.exp: Handle intermediate format.
>
> Index: doc/gcov.texi
> ===================================================================
> --- doc/gcov.texi (revision 199273)
> +++ doc/gcov.texi (working copy)
> @@ -122,15 +122,17 @@ gcov [@option{-v}|@option{--version}] [@option{-h}
>       [@option{-a}|@option{--all-blocks}]
>       [@option{-b}|@option{--branch-probabilities}]
>       [@option{-c}|@option{--branch-counts}]
> -     [@option{-u}|@option{--unconditional-branches}]
> +     [@option{-d}|@option{--display-progress}]
> +     [@option{-f}|@option{--function-summaries}]
> +     [@option{-i}|@option{--intermediate-format}]
> +     [@option{-l}|@option{--long-file-names}]
> +     [@option{-m}|@option{--demangled-names}]
>       [@option{-n}|@option{--no-output}]
> -     [@option{-l}|@option{--long-file-names}]
> +     [@option{-o}|@option{--object-directory} @var{directory|file}]
>       [@option{-p}|@option{--preserve-paths}]
>       [@option{-r}|@option{--relative-only}]
> -     [@option{-f}|@option{--function-summaries}]
> -     [@option{-o}|@option{--object-directory} @var{directory|file}]
>       [@option{-s}|@option{--source-prefix} @var{directory}]
> -     [@option{-d}|@option{--display-progress}]
> +     [@option{-u}|@option{--unconditional-branches}]
>       @var{files}
>  @c man end
>  @c man begin SEEALSO
> @@ -232,6 +234,50 @@ Unconditional branches are normally not interestin
>  @itemx --display-progress
>  Display the progress on the standard output.
>
> +@item -i
> +@itemx --intermediate-format
> +Output gcov file in an easy-to-parse intermediate text format that can
> +be used by @command{lcov} or other tools. The output is a single
> +@file{.gcov} file per @file{.gcda} file. No source code is required.
> +
> +The format of the intermediate @file{.gcov} file is plain text with
> +one entry per line
> +
> +@smallexample
> +file:@var{source_file_name}
> +function:@var{line_number},@var{execution_count},@var{function_name}
> +lcount:@var{line number},@var{execution_count}
> +branch:@var{line_number},@var{branch_coverage_type}
> +
> +Where the @var{branch_coverage_type} is
> +   notexec (Branch not executed)
> +   taken (Branch executed and taken)
> +   nottaken (Branch executed, but not taken)
> +
> +There can be multiple @var{file} entries in an intermediate gcov
> +file. All entries following a @var{file} pertain to that source file
> +until the next @var{file} entry.
> +@end smallexample
> +
> +Here is a sample when @option{-i} is used in conjuction with
> @option{-b} option:
> +
> +@smallexample
> +file:array.cc
> +function:11,1,_Z3sumRKSt6vectorIPiSaIS0_EE
> +function:22,1,main
> +lcount:11,1
> +lcount:12,1
> +lcount:14,1
> +branch:14,taken
> +lcount:26,1
> +branch:28,nottaken
> +@end smallexample
> +
> +@item -m
> +@itemx --demangled-names
> +Display demangled function names in output. The default is to show
> +mangled function names.
> +
>  @end table
>
>  @command{gcov} should be run with the current directory the same as that
> Index: gcov.c
> ===================================================================
> --- gcov.c (revision 199273)
> +++ gcov.c (working copy)
> @@ -37,6 +37,7 @@ along with Gcov; see the file COPYING3.  If not se
>  #include "intl.h"
>  #include "diagnostic.h"
>  #include "version.h"
> +#include "demangle.h"
>
>  #include <getopt.h>
>
> @@ -168,6 +169,7 @@ typedef struct function_info
>  {
>    /* Name of function.  */
>    char *name;
> +  char *demangled_name;
>    unsigned ident;
>    unsigned lineno_checksum;
>    unsigned cfg_checksum;
> @@ -325,6 +327,14 @@ static int flag_gcov_file = 1;
>
>  static int flag_display_progress = 0;
>
> +/* Output *.gcov file in intermediate format used by 'lcov'.  */
> +
> +static int flag_intermediate_format = 0;
> +
> +/* Output demangled function names.  */
> +
> +static int flag_demangled_names = 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.  */
> @@ -388,6 +398,7 @@ static void executed_summary (unsigned, unsigned);
>  static void function_summary (const coverage_t *, const char *);
>  static const char *format_gcov (gcov_type, gcov_type, int);
>  static void accumulate_line_counts (source_t *);
> +static void output_gcov_file(const char *, source_t *);
>  static int output_branch_count (FILE *, int, const arc_t *);
>  static void output_lines (FILE *, const source_t *);
>  static char *make_gcov_file_name (const char *, const char *);
> @@ -461,21 +472,23 @@ print_usage (int error_p)
>    fnotice (file, "Usage: gcov [OPTION]... SOURCE|OBJ...\n\n");
>    fnotice (file, "Print code coverage information.\n\n");
>    fnotice (file, "  -h, --help                      Print this help,
> then exit\n");
> -  fnotice (file, "  -v, --version                   Print version
> number, then exit\n");
>    fnotice (file, "  -a, --all-blocks                Show information
> for every basic block\n");
>    fnotice (file, "  -b, --branch-probabilities      Include branch
> probabilities in output\n");
> -  fnotice (file, "  -c, --branch-counts             Given counts of
> branches taken\n\
> +  fnotice (file, "  -c, --branch-counts             Output counts of
> branches taken\n\
>                                      rather than percentages\n");
> -  fnotice (file, "  -n, --no-output                 Do not create an
> output file\n");
> +  fnotice (file, "  -d, --display-progress          Display progress
> information\n");
> +  fnotice (file, "  -f, --function-summaries        Output summaries
> for each function\n");
> +  fnotice (file, "  -i, --intermediate-format       Output .gcov file
> in intermediate text format\n");
>    fnotice (file, "  -l, --long-file-names           Use long output
> file names for included\n\
>                                      source files\n");
> -  fnotice (file, "  -f, --function-summaries        Output summaries
> for each function\n");
> +  fnotice (file, "  -m, --demangled-names           Output demangled
> function names\n");
> +  fnotice (file, "  -n, --no-output                 Do not create an
> output file\n");
>    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, "  -r, --relative-only             Only show data
> for relative sources\n");
>    fnotice (file, "  -s, --source-prefix DIR         Source prefix to 
> elide\n");
> -  fnotice (file, "  -r, --relative-only             Only show data
> for relative sources\n");
> -  fnotice (file, "  -p, --preserve-paths            Preserve all
> pathname components\n");
>    fnotice (file, "  -u, --unconditional-branches    Show
> unconditional branch counts too\n");
> -  fnotice (file, "  -d, --display-progress          Display progress
> information\n");
> +  fnotice (file, "  -v, --version                   Print version
> number, then exit\n");
>    fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
>     bug_report_url);
>    exit (status);
> @@ -503,9 +516,11 @@ static const struct option options[] =
>    { "all-blocks",           no_argument,       NULL, 'a' },
>    { "branch-probabilities", no_argument,       NULL, 'b' },
>    { "branch-counts",        no_argument,       NULL, 'c' },
> +  { "intermediate-format",  no_argument,       NULL, 'i' },
>    { "no-output",            no_argument,       NULL, 'n' },
>    { "long-file-names",      no_argument,       NULL, 'l' },
>    { "function-summaries",   no_argument,       NULL, 'f' },
> +  { "demangled-names",      no_argument,       NULL, 'm' },
>    { "preserve-paths",       no_argument,       NULL, 'p' },
>    { "relative-only",        no_argument,       NULL, 'r' },
>    { "object-directory",     required_argument, NULL, 'o' },
> @@ -523,7 +538,8 @@ process_args (int argc, char **argv)
>  {
>    int opt;
>
> -  while ((opt = getopt_long (argc, argv, "abcdfhlno:s:pruv", options,
> NULL)) != -1)
> +  while ((opt = getopt_long (argc, argv, "abcdfhilmno:s:pruv",
> options, NULL)) !=
> +         -1)
>      {
>        switch (opt)
>   {
> @@ -545,6 +561,9 @@ process_args (int argc, char **argv)
>   case 'l':
>    flag_long_names = 1;
>    break;
> + case 'm':
> +  flag_demangled_names = 1;
> +  break;
>   case 'n':
>    flag_gcov_file = 0;
>    break;
> @@ -564,6 +583,10 @@ process_args (int argc, char **argv)
>   case 'u':
>    flag_unconditional = 1;
>    break;
> + case 'i':
> +          flag_intermediate_format = 1;
> +          flag_gcov_file = 1;
> +          break;
>          case 'd':
>            flag_display_progress = 1;
>            break;
> @@ -579,6 +602,110 @@ process_args (int argc, char **argv)
>    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_intermediate_filename (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'.
> +
> +The intermediate format contains a single file named 'foo.cc.gcov',
> +with no source code included. A sample output is
> +
> +file:foo.cc
> +function:5,1,_Z3foov
> +function:13,1,main
> +function:19,1,_GLOBAL__sub_I__Z3foov
> +function:19,1,_Z41__static_initialization_and_destruction_0ii
> +lcount:5,1
> +lcount:7,9
> +lcount:9,8
> +lcount:11,1
> +file:/.../iostream
> +lcount:74,1
> +file:/.../basic_ios.h
> +file:/.../ostream
> +file:/.../ios_base.h
> +function:157,0,_ZStorSt12_Ios_IostateS_
> +lcount:157,0
> +file:/.../char_traits.h
> +function:258,0,_ZNSt11char_traitsIcE6lengthEPKc
> +lcount:258,0
> +...
> +
> +The default gcov outputs multiple files: 'foo.cc.gcov',
> +'iostream.gcov', 'ios_base.h.gcov', etc. with source code
> +included. Instead the intermediate format here outputs only a single
> +file 'foo.cc.gcov' similar to the above example. */
> +
> +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, "file:%s\n", src->name);    /* source file name */
> +
> +  for (fn = src->functions; fn; fn = fn->line_next)
> +    {
> +      /* function:<name>,<line_number>,<execution_count> */
> +      fprintf (gcov_file, "function:%d,%s,%s\n", fn->line,
> +               format_gcov (fn->blocks[0].count, 0, -1),
> +               flag_demangled_names ? fn->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, "lcount:%u,%s\n", line_num,
> +                 format_gcov (line->count, 0, -1));
> +      if (flag_branches)
> +        for (arc = line->u.branches; arc; arc = arc->line_next)
> +          {
> +            if (!arc->is_unconditional && !arc->is_call_non_return)
> +              {
> +                const char *branch_type;
> +                /* branch:<line_num>,<branch_coverage_type>
> +                   branch_coverage_type
> +                     : notexec (Branch not executed)
> +                     : taken (Branch executed and taken)
> +                     : nottaken (Branch executed, but not taken)
> +                */
> +                if (arc->src->count)
> +                  branch_type = (arc->count > 0) ? "taken" : "nottaken";
> +                else
> +                  branch_type = "notexec";
> +                fprintf(gcov_file, "branch:%d,%s\n", line_num, branch_type);
> +              }
> +          }
> +    }
> +}
> +
> +
>  /* Process a single input file.  */
>
>  static void
> @@ -655,11 +782,40 @@ process_file (const char *file_name)
>  }
>
>  static void
> +output_gcov_file(const char *file_name, source_t *src)
> +{
> +  char *gcov_file_name = make_gcov_file_name (file_name, src->coverage.name);
> +
> +  if (src->coverage.lines)
> +    {
> +      FILE *gcov_file = fopen (gcov_file_name, "w");
> +      if (gcov_file)
> +        {
> +          fnotice (stdout, "Creating '%s'\n", gcov_file_name);
> +          output_lines (gcov_file, src);
> +          if (ferror (gcov_file))
> +            fnotice (stderr, "Error writing output file '%s'\n",
> gcov_file_name);
> +          fclose (gcov_file);
> +        }
> +      else
> +        fnotice (stderr, "Could not open output file '%s'\n", 
> gcov_file_name);
> +    }
> +  else
> +    {
> +      unlink (gcov_file_name);
> +      fnotice (stdout, "Removing '%s'\n", gcov_file_name);
> +    }
> +  free (gcov_file_name);
> +}
> +
> +static void
>  generate_results (const char *file_name)
>  {
>    unsigned ix;
>    source_t *src;
>    function_t *fn;
> +  FILE *gcov_intermediate_file = NULL;
> +  char *gcov_intermediate_filename = NULL;
>
>    for (ix = n_sources, src = sources; ix--; src++)
>      if (src->num_lines)
> @@ -670,7 +826,7 @@ generate_results (const char *file_name)
>        coverage_t coverage;
>
>        memset (&coverage, 0, sizeof (coverage));
> -      coverage.name = fn->name;
> +      coverage.name = flag_demangled_names ? fn->demangled_name : fn->name;
>        add_line_counts (flag_function_summary ? &coverage : NULL, fn);
>        if (flag_function_summary)
>   {
> @@ -688,7 +844,21 @@ generate_results (const char *file_name)
>        else
>   file_name = canonicalize_name (file_name);
>      }
> -
> +
> +  if (flag_gcov_file && flag_intermediate_format)
> +    {
> +      /* Open the intermediate file.  */
> +      gcov_intermediate_filename =
> +        get_gcov_intermediate_filename (file_name);
> +      gcov_intermediate_file = fopen (gcov_intermediate_filename, "w");
> +      if (!gcov_intermediate_file)
> +        {
> +          fnotice (stderr, "Cannot open intermediate output file %s\n",
> +                   gcov_intermediate_filename);
> +          return;
> +        }
> +    }
> +
>    for (ix = n_sources, src = sources; ix--; src++)
>      {
>        if (flag_relative_only)
> @@ -711,34 +881,21 @@ generate_results (const char *file_name)
>        total_executed += src->coverage.lines_executed;
>        if (flag_gcov_file)
>   {
> -  char *gcov_file_name
> -    = make_gcov_file_name (file_name, src->coverage.name);
> +          if (flag_intermediate_format)
> +            /* Output the intermediate format without requiring source
> +               files.  This outputs a section to a *single* file.  */
> +            output_intermediate_file (gcov_intermediate_file, src);
> +          else
> +            output_gcov_file (file_name, src);
> +          fnotice (stdout, "\n");
> +        }
> +    }
>
> -  if (src->coverage.lines)
> -    {
> -      FILE *gcov_file = fopen (gcov_file_name, "w");
> -
> -      if (gcov_file)
> - {
> -  fnotice (stdout, "Creating '%s'\n", gcov_file_name);
> -  output_lines (gcov_file, src);
> -  if (ferror (gcov_file))
> -    fnotice (stderr, "Error writing output file '%s'\n",
> -     gcov_file_name);
> -  fclose (gcov_file);
> - }
> -      else
> - fnotice (stderr, "Could not open output file '%s'\n",
> - gcov_file_name);
> -    }
> -  else
> -    {
> -      unlink (gcov_file_name);
> -      fnotice (stdout, "Removing '%s'\n", 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_intermediate_file);
> +      XDELETEVEC (gcov_intermediate_filename);
>      }
>
>    if (!file_name)
> @@ -765,6 +922,9 @@ release_function (function_t *fn)
>      }
>    free (fn->blocks);
>    free (fn->counts);
> +  if (flag_demangled_names && fn->demangled_name != fn->name)
> +    free (fn->demangled_name);
> +  free (fn->name);
>  }
>
>  /* Release all memory used.  */
> @@ -1050,6 +1210,12 @@ read_graph_file (void)
>
>    fn = XCNEW (function_t);
>    fn->name = function_name;
> +          if (flag_demangled_names)
> +            {
> +              fn->demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
> +              if (!fn->demangled_name)
> +                fn->demangled_name = fn->name;
> +            }
>    fn->ident = ident;
>    fn->lineno_checksum = lineno_checksum;
>    fn->cfg_checksum = cfg_checksum;
> @@ -2277,7 +2443,8 @@ output_lines (FILE *gcov_file, const source_t *src
>      if (arc->fake)
>        return_count -= arc->count;
>
> -  fprintf (gcov_file, "function %s", fn->name);
> +  fprintf (gcov_file, "function %s", flag_demangled_names ?
> +                   fn->demangled_name : fn->name);
>    fprintf (gcov_file, " called %s",
>     format_gcov (called_count, 0, -1));
>    fprintf (gcov_file, " returned %s",
> Index: testsuite/lib/gcov.exp
> ===================================================================
> --- testsuite/lib/gcov.exp (revision 199273)
> +++ testsuite/lib/gcov.exp (working copy)
> @@ -70,7 +70,62 @@ proc verify-lines { testname testcase file } {
>      return $failed
>  }
>
> +
>  #
> +# verify-intermediate -- check that intermediate file has certain lines
> +#
> +# TESTNAME is the name of the test, including unique flags.
> +# TESTCASE is the name of the test.
> +# FILE is the name of the gcov output file.
> +#
> +# Checks are very loose, they are based on certain tags being 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 { testname testcase file } {
> +    set failed 0
> +    set srcfile 0
> +    set function 0
> +    set lcount 0
> +    set branch 0
> +    set fd [open $file r]
> +    while { [gets $fd line] >= 0 } {
> + if [regexp "^file:" $line] {
> +    incr srcfile
> + }
> + if [regexp "^function:(\[0-9\]+),(\[0-9\]+),.*" $line] {
> +    incr function
> + }
> + if [regexp "^lcount:(\[0-9\]+),(\[0-9\]+)" $line] {
> +    incr lcount
> + }
> + if [regexp "^branch:(\[0-9\]+),(taken|nottaken|notexec)" $line] {
> +    incr branch
> + }
> +    }
> +
> +    # We should see at least one tag of each type
> +    if {$srcfile == 0} {
> + fail "$testname expected 'file:' tag not found"
> + incr failed
> +    }
> +    if {$function == 0} {
> + fail "$testname expected 'function:' tag not found"
> + incr failed
> +    }
> +    if {$lcount == 0} {
> + fail "$testname expected 'lcount:' tag not found"
> + incr failed
> +    }
> +    if {$branch == 0} {
> + fail "$testname expected 'branch:' tag not found"
> + incr failed
> +    }
> +    return $failed
> +}
> +
> +
> +#
>  # verify-branches -- check that branch percentages are as expected
>  #
>  # TESTNAME is the name of the test, including unique flags.
> @@ -248,6 +303,8 @@ proc run-gcov { args } {
>      set gcov_args ""
>      set gcov_verify_calls 0
>      set gcov_verify_branches 0
> +    set gcov_verify_lines 1
> +    set gcov_verify_intermediate 0
>      set xfailed 0
>
>      foreach a $args {
> @@ -255,6 +312,11 @@ proc run-gcov { args } {
>    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
>   } elseif { $gcov_args == "" } {
>      set gcov_args $a
>   } else {
> @@ -295,7 +357,12 @@ proc run-gcov { args } {
>      remote_upload host $testcase.gcov $testcase.gcov
>
>      # Check that line execution counts are as expected.
> -    set lfailed [verify-lines $testname $testcase $testcase.gcov]
> +    if { $gcov_verify_lines } {
> + # Check that line execution counts are as expected.
> + set lfailed [verify-lines $testname $testcase $testcase.gcov]
> +    } else {
> + set lfailed 0
> +    }
>
>      # If requested via the .x file, check that branch and call information
>      # is correct.
> @@ -309,15 +376,21 @@ proc run-gcov { args } {
>      } else {
>   set cfailed 0
>      }
> +    if { $gcov_verify_intermediate } {
> + # Check that intermediate format has the expected format
> + set ifailed [verify-intermediate $testname $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 { $xfailed } {
>   setup_xfail "*-*-*"
>      }
>      if { $tfailed > 0 } {
> - fail "$testname gcov: $lfailed failures in line counts, $bfailed in
> branch percentages, $cfailed in return percentages"
> + fail "$testname gcov: $lfailed failures in line counts, $bfailed in
> branch percentages, $cfailed in return percentages, $ifailed in
> intermediate format"
>      } else {
>   pass "$testname gcov"
>   clean-gcov $testcase

Reply via email to