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