This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: ggc marking hooks


Hello,

The attached (not very big, about 280 lines) patch is related in
intention to my committed patch (rev 121077 of trunk) on mark_hook-s
GTY in gengtype
http://gcc.gnu.org/ml/gcc-patches/2007-01/msg01534.html

Remember that the former patch add the (currently still not used
AFAIK) ability to have a mark hook routine called when markiong some
specific GGC garbage-collected data.

If we want to use the mark_hook feature we probably want to have some
routines called before marking begins and after it has happenned.  As
Steven Bosscher suggested in
http://gcc.gnu.org/ml/gcc-patches/2007-01/msg01536.html a possible use
could be to ease hunting of some memory leaks. Another possible use
could be to simply count the number of data (of some given
GTY-declared type). Then it would be helpful to have a small routine
which clears the counter before every garbage collection (this is a
pre-marking hook) and another routine (after the marking phase of a
ggc_collect) would check or dimp this counter (this is a post-marking
hook). It is best to have these hooks called inside the various
implementations of ggc_collect. Hence I feel that such hooks are
useful, otherwise it is not very wise to use the (already committed)
GTY mark_hook feature.


Of course, the cost is some small overhead in every (working) call of
ggc_collect. But I expect that the number of such hooks is rather
small (a dozen of quickly running routines) - even if this patch does
not force any artificial bound on the number of hooks. In the current
state of this patch, no hooks get called yet and I cannot measure the
small cost of this overhead (which happens only inside ggc_collect,
which is not called very often). In practice, the overhead is really
those of the hooks called.


So the idea would be that some passes or processing might want to use
mark_hook-s in GTY-s and also register some routines as pre-marking
hooks (run before any marking occur within ggc_collect) and
post-marking hooks (run after every marking is done).  Such code can
register a pre-marking hook by calling

   RK = ggc_add_premarking_hook(PREMARKHOOK, DATA, PRIO);

where the routine PREMARKHOOK is called with the DATA (a pointer) and
has PRIO (an integer) as priority. And you get the rank of the
hook. To remove the hook, just call

   ggc_remove_premarking_hook(RK)
and likewise for psotmarking hooks.

Such hook routines can do anything which is not related to GGC
(obviously, they should not change marked data or the garbage
collected heap); in particular, a hook routine could add or remove
another hook (or itself). The implementation copies into an array the
existing hooks and sorts them before running them.

I also added at the appropriate places (inside ggc_collect) the calls
to run the hooks, to ggc_run_premarking_hooks &
ggc_run_postmarking_hooks

bootstrapped on x86_64 GNU/linux (Debian/Sid/AMD64) with
--enable-languages=c --disable-multilib

Ok for trunk?

Changelog after my sig, and patch attached.

Regards
-- 
Basile STARYNKEVITCH         http://starynkevitch.net/Basile/ 
email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359 
8, rue de la Faïencerie, 92340 Bourg La Reine, France
*** opinions {are only mines, sont seulement les miennes} ***

################################################## gcc/Changelog
2007-01-23  Basile Starynkevitch  <basile@starynkevitch.net>

	* gcc/ggc.h (ggc_hook_routine_t, ggc_add_premarking_hook): Declare.
	(ggc_remove_premarking_hook, ggc_add_postmarking_hook): Declare.
	(ggc_run_premarking_hooks, ggc_run_postmarking_hooks): Declare.
	Add declarations for ggc pre,post marking hooks.

	* gcc/ggc-common.c: Includes vec.h and implements pre,post marking 
	hooks. (add_marking_hook): New internal function.
	(ggc_add_premarking_hook, ggc_add_postmarking_hook: New functions.
	(hookptr_cmp, run_marking_hooks): New internal functions.
	(ggc_run_premarking_hooks, ggc_run_postmarking_hooks): New functions.

	* gcc/ggc-zone.c: (ggc_collect) Add calls ggc_run_premarking_hooks
	& ggc_run_postmarking_hooks

	* gcc/ggc-page.c: (ggc_collect) Add calls ggc_run_premarking_hooks
	& ggc_run_postmarking_hooks

	* gcc/Makefile.in: (ggc-common.o) Depends upon vec.h
Index: gcc/ggc.h
===================================================================
--- gcc/ggc.h	(revision 121077)
+++ gcc/ggc.h	(working copy)
@@ -314,4 +314,35 @@ extern void *ggc_alloc_zone_stat (size_t
 
 #endif
 
+
+
+/***
+ * Garbage collection hooks
+ ***/
+
+/* the signature of hooks; these routines cannot do anything ggc
+   related or change ggc managed data */
+typedef void ggc_hook_routine_t(void*data);
+
+/* add a hook to be run before marking; return a hook rank (which is
+   used for removing the hook); the hooks are run in order of
+   increasing priority - can be called from a hook but effective
+   only on the next call to ggc_collect */
+int ggc_add_premarking_hook(ggc_hook_routine_t*rout, void*data, int prio);
+/* remove such an added hook - can be called from a hook but effective
+   only on the next call to ggc_collect */
+void ggc_remove_premarking_hook(int rank);
+
+/* add a hook to be run after marking; ; return a hook rank (which is
+   used for removing the hook); the hooks are run in order of
+   increasing priority - can be called from a hook but effective
+   only on the next call to ggc_collect */
+int ggc_add_postmarking_hook(ggc_hook_routine_t*rout, void*data, int prio);
+/* remove such an added hook  - can be called from a hook but effective
+   only on the next call to ggc_collect */
+void ggc_remove_postmarking_hook(int rank);
+
+/**** only to be run by ggc implementations ****/
+void ggc_run_premarking_hooks (void);
+void ggc_run_postmarking_hooks (void);
 #endif
Index: gcc/ggc-common.c
===================================================================
--- gcc/ggc-common.c	(revision 121077)
+++ gcc/ggc-common.c	(working copy)
@@ -31,6 +31,7 @@ Software Foundation, 51 Franklin Street,
 #include "params.h"
 #include "hosthooks.h"
 #include "hosthooks-def.h"
+#include "vec.h"
 
 #ifdef HAVE_SYS_RESOURCE_H
 # include <sys/resource.h>
@@ -1021,3 +1022,176 @@ dump_ggc_loc_statistics (bool final ATTR
   fprintf (stderr, "-------------------------------------------------------\n");
 #endif
 }
+
+
+
+/************
+ * garbage collection hook management
+ ************/
+
+struct ggchook_st
+{
+  ggc_hook_routine_t *gh_rout;
+  void *gh_data;
+  int gh_prio;
+  long gh_num;			
+};
+
+typedef struct ggchook_st *ggchook_ptr_t;
+DEF_VEC_P (ggchook_ptr_t);
+DEF_VEC_ALLOC_P (ggchook_ptr_t, heap);
+typedef VEC (ggchook_ptr_t, heap) ggchook_vec_t;
+
+static ggchook_vec_t *premark_hookvec;
+static ggchook_vec_t *postmark_hookvec;
+
+static int
+add_marking_hook (ggchook_vec_t ** pvec,
+		  ggc_hook_routine_t * rout, void *data, int prio)
+{
+  static long cnt;
+  struct ggchook_st *newhook = 0;
+  ggchook_vec_t *vec = *pvec;
+  int rk = -1, i = 0, l = 0;
+  gcc_assert (rout != (ggc_hook_routine_t *) 0);
+  if (!vec)
+    vec = VEC_alloc (ggchook_ptr_t, heap, 40);
+  newhook = xcalloc (sizeof (struct ggchook_st), 1);
+  cnt++;
+  newhook->gh_rout = rout;
+  newhook->gh_data = data;
+  newhook->gh_prio = prio;
+  newhook->gh_num = cnt;
+  l = VEC_length (ggchook_ptr_t, vec);
+  for (i = 0; i < l; i++)
+    {
+      if (!VEC_index (ggchook_ptr_t, vec, i))
+	{
+	  rk = i;
+	  VEC_replace (ggchook_ptr_t, vec, rk, newhook);
+	  break;
+	}
+    };
+  if (rk < 0)
+    {
+      rk = l;
+      VEC_safe_push (ggchook_ptr_t, heap, vec, newhook);
+    };
+  *pvec = vec;
+  return rk;
+}
+
+int
+ggc_add_premarking_hook (ggc_hook_routine_t * rout, void *data, int prio)
+{
+  return add_marking_hook (&premark_hookvec, rout, data, prio);
+}
+
+int
+ggc_add_postmarking_hook (ggc_hook_routine_t * rout, void *data, int prio)
+{
+  return add_marking_hook (&postmark_hookvec, rout, data, prio);
+}
+
+
+static void
+remove_marking_hook (ggchook_vec_t ** pvec, int rank)
+{
+  int i = 0, l = 0;
+  ggchook_ptr_t hook = NULL;
+  ggchook_vec_t *vec = *pvec;
+  if (!vec)
+    return;
+  l = VEC_length (ggchook_ptr_t, vec);
+  if (rank < 0 || rank >= l)
+    return;
+  hook = VEC_replace (ggchook_ptr_t, vec, rank, (struct ggchook_st *) 0);
+  if (hook)
+    {
+      memset (hook, 0, sizeof (*hook));
+      free (hook);
+    };
+  /* if this is the highest non empty rank, truncate the vector */
+  for (i = rank + 1; i < l; i++)
+    if (VEC_index (ggchook_ptr_t, vec, i))
+      return;
+  VEC_truncate (ggchook_ptr_t, vec, rank);
+  *pvec = vec;
+}
+
+void
+ggc_remove_premarking_hook (int rank)
+{
+  remove_marking_hook (&premark_hookvec, rank);
+}
+
+void
+ggc_remove_postmarking_hook (int rank)
+{
+  remove_marking_hook (&postmark_hookvec, rank);
+}
+
+/* we sort the hooks by priority or else by their number */
+static int
+hookptr_cmp (const void *l, const void *r)
+{
+  int c;
+  long d;
+  const struct ggchook_st *hl = *(const struct ggchook_st **) l;
+  const struct ggchook_st *hr = *(const struct ggchook_st **) r;
+  c = hl->gh_prio - hr->gh_prio;
+  if (!c)
+    {
+      d = hl->gh_num - hr->gh_num;
+      if (d > 0L)
+	return 1;
+      else if (d < 0L)
+	return -1;
+      else
+	return 0;
+    }
+  else
+    return c;
+}
+
+/* to run the hooks, we copy them into a calloc-ed array of pointers,
+   sort this array, and run the hooks there; hence adding or removing
+   hooks from other hooks is possible without restriction */
+static void
+run_marking_hooks (ggchook_vec_t * hookvec)
+{
+  struct ggchook_st **hooktab = 0, *hook = 0;
+  int rk = 0, i = 0, l = 0;
+  if (!hookvec)
+    return;
+  l = VEC_length (ggchook_ptr_t, hookvec);
+  /* get the non-empty non-null hooks */
+  hooktab = xcalloc (sizeof (*hooktab), l + 1);
+  for (i = 0; VEC_iterate (ggchook_ptr_t, hookvec, i, hook); i++)
+    {
+      if (!hook || !hook->gh_rout)
+	continue;
+      hooktab[rk++] = hook;
+    }
+  if (rk > 1)
+    qsort (hooktab, rk, sizeof (hook), hookptr_cmp);
+  for (i = 0; i < rk; i++)
+    {
+      hook = hooktab[i];
+      (*hook->gh_rout) (hook->gh_data);
+    }
+  free (hooktab);
+}
+
+void
+ggc_run_premarking_hooks (void)
+{
+  run_marking_hooks (premark_hookvec);
+}
+
+void
+ggc_run_postmarking_hooks (void)
+{
+  run_marking_hooks (postmark_hookvec);
+}
+
Index: gcc/ggc-zone.c
===================================================================
--- gcc/ggc-zone.c	(revision 121077)
+++ gcc/ggc-zone.c	(working copy)
@@ -1883,7 +1883,8 @@ ggc_collect (void)
 	}
     }
 
-  /* Start by possibly collecting the main zone.  */
+  /* Start by running pre-marking hooks and possibly collecting the main zone.  */
+  ggc_run_premarking_hooks ();
   main_zone.was_collected = false;
   marked |= ggc_collect_1 (&main_zone, true);
 
@@ -1925,6 +1926,9 @@ ggc_collect (void)
     }
 #endif
 
+  /* run the postmarking hooks before freeing */
+  ggc_run_postmarking_hooks ();
+
   if (marked)
     zone_free_marks ();
 
Index: gcc/ggc-page.c
===================================================================
--- gcc/ggc-page.c	(revision 121077)
+++ gcc/ggc-page.c	(working copy)
@@ -1903,10 +1903,16 @@ ggc_collect (void)
   G.context_depth_collections = ((unsigned long)1 << (G.context_depth + 1)) - 1;
 
   clear_marks ();
+  /* run the premarking hooks before marking roots*/
+  ggc_run_premarking_hooks ();
   ggc_mark_roots ();
+
 #ifdef GATHER_STATISTICS
   ggc_prune_overhead_list ();
 #endif
+
+  /* run the postmarking hooks before freeing memory */
+  ggc_run_postmarking_hooks ();
   poison_pages ();
   validate_free_objects ();
   sweep_pages ();
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 121077)
+++ gcc/Makefile.in	(working copy)
@@ -1719,7 +1719,7 @@ gtype-desc.o: gtype-desc.c $(CONFIG_H) $
 	$(CGRAPH_H) $(TREE_FLOW_H) reload.h $(CPP_ID_DATA_H)
 
 ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(GGC_H) \
-	$(HASHTAB_H) toplev.h $(PARAMS_H) hosthooks.h $(HOSTHOOKS_DEF_H)
+	$(HASHTAB_H) toplev.h $(PARAMS_H) hosthooks.h $(HOSTHOOKS_DEF_H) vec.h
 
 ggc-page.o: ggc-page.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) \
 	$(FLAGS_H) toplev.h $(GGC_H) $(TIMEVAR_H) $(TM_P_H) $(PARAMS_H) $(TREE_FLOW_H)

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]