diff mbox

[GCOV] shared library awareness

Message ID 5419EC21.6040905@acm.org
State New
Headers show

Commit Message

Nathan Sidwell Sept. 17, 2014, 8:16 p.m. UTC
I've committed this patch, last in my current series.  It teaches the gcov 
machinery about shared objects that are also built with coverage information. 
The basic idea is to chain gcov_root structures together onto a single global 
chain -- checking the GCOV_VERSION number so that only compatible gcov modules 
get chained.

When __gcov_rest or __gcov_dump are called, all compatible modules are cleared 
or dumped.  The existing atexit machinery is used to dump the current module 
only when it is exited/unloaded.

nathan
2014-09-17  Nathan sidwell  <nathan@acm.org>

	* Makefile.in (LIBGCOV_INTERFACE): Add _gcov_dump from ...
	(LIBGCOV_DRIVER): ... here.
	* libgcov-driver.c (gcov_master): New.
	(gcov_exit): Remove from master chain.
	(__gcov_init): Add to master chain if version compatible.  Don't
	clear the version.
	* libgcov_interface (__gcov_flust): Call gcov_dump_int.
	(gcov_reset_int): Clear master chain, if compatible.
	(gcov_dump_int): New internal interface.  Dump master chain, if
	compatible.
	(gcov_dump): Alias for gcov_dump_int.
	* libgcov.h (struct gcov_root): Add next and prev fields.
	(struct gcov_master): New struct.
	(__gcov_master): New.
	(gcov_dump_int): Declare.
diff mbox

Patch

Index: Makefile.in
===================================================================
--- Makefile.in	(revision 215334)
+++ Makefile.in	(working copy)
@@ -858,9 +858,10 @@  LIBGCOV_PROFILER = _gcov_interval_profil
 	_gcov_one_value_profiler _gcov_indirect_call_profiler		\
  	_gcov_average_profiler _gcov_ior_profiler			\
 	_gcov_indirect_call_profiler_v2 _gcov_time_profiler
-LIBGCOV_INTERFACE = _gcov_flush _gcov_fork _gcov_execl _gcov_execlp    \
+LIBGCOV_INTERFACE = _gcov_dump _gcov_flush _gcov_fork			\
+	_gcov_execl _gcov_execlp					\
 	_gcov_execle _gcov_execv _gcov_execvp _gcov_execve _gcov_reset
-LIBGCOV_DRIVER = _gcov _gcov_dump
+LIBGCOV_DRIVER = _gcov
 
 libgcov-merge-objects = $(patsubst %,%$(objext),$(LIBGCOV_MERGE))
 libgcov-profiler-objects = $(patsubst %,%$(objext),$(LIBGCOV_PROFILER))
Index: libgcov-driver.c
===================================================================
--- libgcov-driver.c	(revision 215334)
+++ libgcov-driver.c	(working copy)
@@ -777,13 +777,23 @@  __gcov_dump_one (struct gcov_root *root)
   root->run_counted = 1;
 }
 
-/* Per-program/shared-object gcov state.  */
+/* Per-dynamic-object gcov state.  */
 struct gcov_root __gcov_root;
 
+/* Exactly one of these will be live in the process image.  */
+struct gcov_master __gcov_master = 
+  {GCOV_VERSION, 0};
+
 static void
 gcov_exit (void)
 {
   __gcov_dump_one (&__gcov_root);
+  if (__gcov_root.next)
+    __gcov_root.next->prev = __gcov_root.prev;
+  if (__gcov_root.prev)
+    __gcov_root.prev->next = __gcov_root.next;
+  else
+    __gcov_master.root = __gcov_root.next;
 }
 
 /* Add a new object file onto the bb chain.  Invoked automatically
@@ -797,12 +807,21 @@  __gcov_init (struct gcov_info *info)
   if (gcov_version (info, info->version, 0))
     {
       if (!__gcov_root.list)
-        atexit (gcov_exit);
+	{
+	  /* Add to master list and at exit function.  */
+	  if (gcov_version (NULL, __gcov_master.version, "<master>"))
+	    {
+	      __gcov_root.next = __gcov_master.root;
+	      if (__gcov_master.root)
+		__gcov_master.root->prev = &__gcov_root;
+	      __gcov_master.root = &__gcov_root;
+	    }
+	  atexit (gcov_exit);
+	}
 
       info->next = __gcov_root.list;
       __gcov_root.list = info;
     }
-  info->version = 0;
 }
 #endif /* !IN_GCOV_TOOL */
 #endif /* L_gcov */
Index: libgcov-interface.c
===================================================================
--- libgcov-interface.c	(revision 215334)
+++ libgcov-interface.c	(working copy)
@@ -85,7 +85,7 @@  __gcov_flush (void)
   init_mx_once ();
   __gthread_mutex_lock (&__gcov_flush_mx);
 
-  __gcov_dump_one (&__gcov_root);
+  __gcov_dump_int ();
   __gcov_reset_int ();
 
   __gthread_mutex_unlock (&__gcov_flush_mx);
@@ -132,8 +132,16 @@  gcov_clear (const struct gcov_info *list
 void
 __gcov_reset_int (void)
 {
-  gcov_clear (__gcov_root.list);
-  __gcov_root.dumped = 0;
+  struct gcov_root *root;
+
+  /* If we're compatible with the master, iterate over everything,
+     otherise just do us.  */
+  for (root = __gcov_master.version == GCOV_VERSION
+	 ? __gcov_master.root : &__gcov_root; root; root = root->next)
+    {
+      gcov_clear (root->list);
+      root->dumped = 0;
+    }
 }
 
 ALIAS_void_fn (__gcov_reset_int, __gcov_reset);
@@ -145,11 +153,19 @@  ALIAS_void_fn (__gcov_reset_int, __gcov_
    so far, in order to collect profile in region of interest.  */
 
 void
-__gcov_dump (void)
+__gcov_dump_int (void)
 {
-  __gcov_dump_one (&__gcov_root);
+  struct gcov_root *root;
+
+  /* If we're compatible with the master, iterate over everything,
+     otherise just do us.  */
+  for (root = __gcov_master.version == GCOV_VERSION
+	 ? __gcov_master.root : &__gcov_root; root; root = root->next)
+    __gcov_dump_one (root);
 }
 
+ALIAS_void_fn (__gcov_dump_int, __gcov_dump);
+
 #endif /* L_gcov_dump */
 
 #ifdef L_gcov_fork
@@ -169,8 +185,8 @@  __gcov_fork (void)
 #endif
 
 #ifdef L_gcov_execl
-/* A wrapper for the execl function.  Flushes the accumulated profiling data, so
-   that they are not lost.  */
+/* A wrapper for the execl function.  Flushes the accumulated
+   profiling data, so that they are not lost.  */
 
 int
 __gcov_execl (const char *path, char *arg, ...)
Index: libgcov.h
===================================================================
--- libgcov.h	(revision 215334)
+++ libgcov.h	(working copy)
@@ -212,10 +212,21 @@  struct gcov_root
   struct gcov_info *list;
   unsigned dumped : 1;	/* counts have been dumped.  */
   unsigned run_counted : 1;  /* run has been accounted for.  */
+  struct gcov_root *next;
+  struct gcov_root *prev;
 };
 
 extern struct gcov_root __gcov_root ATTRIBUTE_HIDDEN;
 
+struct gcov_master
+{
+  gcov_unsigned_t version;
+  struct gcov_root *root;
+};
+  
+/* Exactly one of these will be active in the process.  */
+extern struct gcov_master __gcov_master;
+
 /* Dump a set of gcov objects.  */
 extern void __gcov_dump_one (struct gcov_root *) ATTRIBUTE_HIDDEN;
 
@@ -230,8 +241,9 @@  extern void __gcov_flush (void) ATTRIBUT
 extern void __gcov_reset (void);
 extern void __gcov_reset_int (void) ATTRIBUTE_HIDDEN;
 
-/* Function to enable early write of profile information so far.  */
+/* User function to enable early write of profile information so far.  */
 extern void __gcov_dump (void);
+extern void __gcov_dump_int (void) ATTRIBUTE_HIDDEN;
 
 /* The merge function that just sums the counters.  */
 extern void __gcov_merge_add (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;