This patch adds functionality to libgcov to enable user applications to
collect profile data only in regions of interest. This is useful, for
example, to collect profile data from a long-running server only
during the time when it is serving requests.

Specifically, the new routines __gcov_reset will clear all profile counters
to zero and __gcov_dump will write out the profile information collected so
far. A global variable is used to prevent writing out the profile a
second time during exit.

Bootstrapped and tested on x86_64-unknown-linux-gnu.  Is this ok for trunk?

Thanks,
Teresa

2012-05-03   Teresa Johnson  <tejohn...@google.com>

        * libgcc/libgcov.c (gcov_clear, __gcov_reset): New functions.
        (__gcov_dump): Ditto.
        (gcov_dump_complete): New global variable.
        (__gcov_flush): Outline functionality now in gcov_clear.
        * gcc/gcov-io.h (__gcov_reset, __gcov_dump): Declare.

Index: libgcc/libgcov.c
===================================================================
--- libgcc/libgcov.c    (revision 187048)
+++ libgcc/libgcov.c    (working copy)
@@ -48,6 +48,8 @@ see the files COPYING3 and COPYING.RUNTIME respect
 #ifdef L_gcov
 void __gcov_init (struct gcov_info *p __attribute__ ((unused))) {}
 void __gcov_flush (void) {}
+void __gcov_reset (void) {}
+void __gcov_dump (void) {}
 #endif
 
 #ifdef L_gcov_merge_add
@@ -91,6 +93,9 @@ static struct gcov_info *gcov_list;
 /* Size of the longest file name. */
 static size_t gcov_max_filename = 0;
 
+/* Flag when the profile has already been dumped via __gcov_dump().  */
+static int gcov_dump_complete = 0;
+
 /* Make sure path component of the given FILENAME exists, create
    missing directories. FILENAME must be writable.
    Returns zero on success, or -1 if an error occurred.  */
@@ -286,6 +291,11 @@ gcov_exit (void)
   char *gi_filename, *gi_filename_up;
   gcov_unsigned_t crc32 = 0;
 
+  /* Prevent the counters from being dumped a second time on exit when the
+     application already wrote out the profile using __gcov_dump().  */
+  if (gcov_dump_complete)
+    return;
+
   memset (&all_prg, 0, sizeof (all_prg));
   /* Find the totals for this execution.  */
   memset (&this_prg, 0, sizeof (this_prg));
@@ -679,6 +689,37 @@ gcov_exit (void)
     }
 }
 
+/* Reset all counters to zero.  */
+
+static void
+gcov_clear (void)
+{
+  const struct gcov_info *gi_ptr;
+
+  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      unsigned f_ix;
+
+      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+       {
+         unsigned t_ix;
+         const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+
+         if (!gfi_ptr || gfi_ptr->key != gi_ptr)
+           continue;
+         const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
+         for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+           {
+             if (!gi_ptr->merge[t_ix])
+               continue;
+             
+             memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
+             ci_ptr++;
+           }
+       }
+    }
+}
+
 /* Add a new object file onto the bb chain.  Invoked automatically
    when running an object file's global ctors.  */
 
@@ -730,38 +771,38 @@ init_mx_once (void)
 void
 __gcov_flush (void)
 {
-  const struct gcov_info *gi_ptr;
-
   init_mx_once ();
   __gthread_mutex_lock (&__gcov_flush_mx);
 
   gcov_exit ();
-  for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-    {
-      unsigned f_ix;
+  gcov_clear ();
 
-      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
-       {
-         unsigned t_ix;
-         const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+  __gthread_mutex_unlock (&__gcov_flush_mx);
+}
 
-         if (!gfi_ptr || gfi_ptr->key != gi_ptr)
-           continue;
-         const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
-         for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
-           {
-             if (!gi_ptr->merge[t_ix])
-               continue;
-             
-             memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
-             ci_ptr++;
-           }
-       }
-    }
+/* Function that can be called from application to reset counters to zero,
+   in order to collect profile in region of interest.  */
 
-  __gthread_mutex_unlock (&__gcov_flush_mx);
+void
+__gcov_reset (void)
+{
+  gcov_clear ();
+  /* Re-enable dumping to support collecting profile in multiple regions
+     of interest.  */
+  gcov_dump_complete = 0;
 }
 
+/* Function that can be called from application to write profile collected
+   so far, in order to collect profile in region of interest.  */
+
+void
+__gcov_dump (void)
+{
+  gcov_exit ();
+  /* Prevent profile from being dumped a second time on application exit.  */
+  gcov_dump_complete = 1;
+}
+
 #endif /* L_gcov */
 
 #ifdef L_gcov_merge_add
Index: gcc/gcov-io.h
===================================================================
--- gcc/gcov-io.h       (revision 187048)
+++ gcc/gcov-io.h       (working copy)
@@ -458,6 +458,12 @@ extern void __gcov_init (struct gcov_info *) ATTRI
 /* Called before fork, to avoid double counting.  */
 extern void __gcov_flush (void) ATTRIBUTE_HIDDEN;
 
+/* Function to reset all counters to 0.  */
+extern void __gcov_reset (void);
+
+/* Function to enable early write of profile information so far.  */
+extern void __gcov_dump (void);
+
 /* The merge function that just sums the counters.  */
 extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
 

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

Reply via email to