public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: singhai@google.com (Sharad Singhai)
To: reply@codereview.appspotmail.com, gcc-patches@gcc.gnu.org
Subject: [google] Add intermediate text format for gcov (issue4595053)
Date: Tue, 14 Jun 2011 07:13:00 -0000	[thread overview]
Message-ID: <20110614061420.B19BD15C1AC@nabu.mtv.corp.google.com> (raw)

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

             reply	other threads:[~2011-06-14  6:14 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-06-14  7:13 Sharad Singhai [this message]
2011-06-14 10:18 ` Richard Guenther
     [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
2011-10-01 21:35     ` Sharad Singhai (शरद सिंघई)

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=20110614061420.B19BD15C1AC@nabu.mtv.corp.google.com \
    --to=singhai@google.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=reply@codereview.appspotmail.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).