public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [google] Add intermediate text format for gcov (issue4595053)
       [not found] <20cf303b397be95f9504a5b0f417@google.com>
@ 2011-06-14 21:29 ` Sharad Singhai (शरद सिंघई)
  2011-06-16  0:43   ` Xinliang David Li
  2011-10-01 13:23   ` Matt Rice
  0 siblings, 2 replies; 6+ messages in thread
From: Sharad Singhai (शरद सिंघई) @ 2011-06-14 21:29 UTC (permalink / raw)
  To: Richard Guenther; +Cc: gcc-patches, reply

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 } } } */

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [google] Add intermediate text format for gcov (issue4595053)
  2011-06-14 21:29 ` [google] Add intermediate text format for gcov (issue4595053) Sharad Singhai (शरद सिंघई)
@ 2011-06-16  0:43   ` Xinliang David Li
  2011-10-01 13:23   ` Matt Rice
  1 sibling, 0 replies; 6+ messages in thread
From: Xinliang David Li @ 2011-06-16  0:43 UTC (permalink / raw)
  To: Sharad Singhai (शरद
	सिंघई)
  Cc: Richard Guenther, GCC Patches, reply

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 } } } */
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [google] Add intermediate text format for gcov (issue4595053)
  2011-06-14 21:29 ` [google] Add intermediate text format for gcov (issue4595053) Sharad Singhai (शरद सिंघई)
  2011-06-16  0:43   ` Xinliang David Li
@ 2011-10-01 13:23   ` Matt Rice
  2011-10-01 21:35     ` Sharad Singhai (शरद सिंघई)
  1 sibling, 1 reply; 6+ messages in thread
From: Matt Rice @ 2011-10-01 13:23 UTC (permalink / raw)
  To: Sharad Singhai (शरद
	सिंघई)
  Cc: gcc-patches, reply

2011/6/14 Sharad Singhai (शरद सिंघई) <singhai@google.com>:
> Sorry, Rietveld didn't send out the updated patch along with my mail.
> Here it is.
>

Hi, I tried this patch out on trunk it applies alright, and appears to
work fine, (haven't run the testsuite though) any plans on submitting
it for inclusion with mainline gcc?

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [google] Add intermediate text format for gcov (issue4595053)
  2011-10-01 13:23   ` Matt Rice
@ 2011-10-01 21:35     ` Sharad Singhai (शरद सिंघई)
  0 siblings, 0 replies; 6+ messages in thread
From: Sharad Singhai (शरद सिंघई) @ 2011-10-01 21:35 UTC (permalink / raw)
  To: Matt Rice; +Cc: gcc-patches, reply

Sorry, I didn't think about the mainline. Since you find it useful, I
will propose it for inclusion in the trunk as well.

Thanks,
Sharad

On Sat, Oct 1, 2011 at 6:23 AM, Matt Rice <ratmice@gmail.com> wrote:
> 2011/6/14 Sharad Singhai (शरद सिंघई) <singhai@google.com>:
>> Sorry, Rietveld didn't send out the updated patch along with my mail.
>> Here it is.
>>
>
> Hi, I tried this patch out on trunk it applies alright, and appears to
> work fine, (haven't run the testsuite though) any plans on submitting
> it for inclusion with mainline gcc?
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [google] Add intermediate text format for gcov (issue4595053)
  2011-06-14  7:13 Sharad Singhai
@ 2011-06-14 10:18 ` Richard Guenther
  0 siblings, 0 replies; 6+ messages in thread
From: Richard Guenther @ 2011-06-14 10:18 UTC (permalink / raw)
  To: Sharad Singhai; +Cc: reply, gcc-patches

On Tue, Jun 14, 2011 at 8:14 AM, Sharad Singhai <singhai@google.com> wrote:
> This patch adds an intermediate gcov text format which does not require
> source code. This format can be used by lcov or other tools.
>
> I have bootstrapped it on x86 and all tests pass. Okay for main?

I think there should be either a specification of the format in gcov.texi
or a reference to a specification if it exists elsewhere.

Richard.

> Thanks,
> Sharad
>
> 2011-06-13   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/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,12 @@
>  @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.
> +
>  @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/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 { -i gcov-7.C } } } */
>
> --
> This patch is available for review at http://codereview.appspot.com/4595053
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [google] Add intermediate text format for gcov (issue4595053)
@ 2011-06-14  7:13 Sharad Singhai
  2011-06-14 10:18 ` Richard Guenther
  0 siblings, 1 reply; 6+ messages in thread
From: Sharad Singhai @ 2011-06-14  7:13 UTC (permalink / raw)
  To: reply, gcc-patches

This patch adds an intermediate gcov text format which does not require
source code. This format can be used by lcov or other tools.

I have bootstrapped it on x86 and all tests pass. Okay for main?

Thanks,
Sharad

2011-06-13   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/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,12 @@
 @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.
+
 @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/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 { -i gcov-7.C } } } */

--
This patch is available for review at http://codereview.appspot.com/4595053

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-10-01 21:35 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20cf303b397be95f9504a5b0f417@google.com>
2011-06-14 21:29 ` [google] Add intermediate text format for gcov (issue4595053) Sharad Singhai (शरद सिंघई)
2011-06-16  0:43   ` Xinliang David Li
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

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).