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]

[tree-ssa libmudflap] new features


Hi -

The attached patch adds some new features to libmudflap.
It tweaks an internal adaptive algorithm to better suit
an application's run-time access patterns.  There's also
an option to intercept SIGUSR1 and print a runtime status
report while an instrumented program is running.  There
are some minor tweaks too.

PS.  It looks like there will be a talk on mudflap at the
GCC Summit in Ottawa.  If anyone is interested in reviewing
drafts of a paper I'm writing about it, let me know.


- FChE


+2003-03-28  Frank Ch. Eigler  <fche at redhat dot com>
+
+	* configure.in: Check for target gettimeofday, signal, some headers.
+	* mf-impl.h (__mf_opts): Add new "sigusr1_report" field.  Comment
+	out inop multi_threaded field.
+	* mf-runtime.c (options): Handle new "-sigusr1-report" option.
+	(__mf_set_options): Correct handling of "-help".
+	(__mf_sigusr1_respond): New function to manage SIGUSR1 response.
+	(__mf_check, __mf_register, __mf_unregister): Call it.
+	(__mf_insert_new_object, __mf_unregister): Respect HAVE_GETTIMEOFDAY.
+	(__mf_report_leaks): Make callable
+	(__mf_tree_analyze): Traverse in-order.  Accumulate address bit
+	distribution statistics.
+	(__mf_adapt_cache): Rewrite shift guessing logic based on address
+	bit distributions.
+	* config.h.in, configure: Regenerated.
+	* testsuite/libmudflap.c/fail27-frag.c: New test.
+	* testsuite/libmudflap.c/pass36-frag.c: New test.

Index: configure.in
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/configure.in,v
retrieving revision 1.1.2.11
diff -u -r1.1.2.11 configure.in
--- configure.in	11 Mar 2003 22:48:29 -0000	1.1.2.11
+++ configure.in	28 Mar 2003 22:26:37 -0000
@@ -25,11 +25,10 @@
 AC_SUBST(enable_shared)
 AC_SUBST(enable_static)
 
-dnl Should check for this header for the host/target, not the build platform
 AC_CHECK_HEADER(stdint.h, [MF_HAVE_STDINT_H=1], [MF_HAVE_STDINT_H=0])
 AC_SUBST(MF_HAVE_STDINT_H)
-AC_CHECK_HEADERS(stdint.h execinfo.h)
-AC_CHECK_FUNCS(backtrace backtrace_symbols)
+AC_CHECK_HEADERS(stdint.h execinfo.h signal.h)
+AC_CHECK_FUNCS(backtrace backtrace_symbols gettimeofday signal)
 
 if ${CONFIG_SHELL-/bin/sh} ./libtool --tag CC --features |
    grep "enable shared" > /dev/null; then
Index: mf-impl.h
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-impl.h,v
retrieving revision 1.1.2.14
diff -u -r1.1.2.14 mf-impl.h
--- mf-impl.h	10 Mar 2003 22:29:58 -0000	1.1.2.14
+++ mf-impl.h	28 Mar 2003 22:26:37 -0000
@@ -84,6 +84,9 @@
   /* Collect and emit statistics. */
   unsigned collect_stats;
 
+  /* Set up a SIGUSR1 -> __mf_report handler. */
+  unsigned sigusr1_report;
+
   /* Execute internal checking code. */
   unsigned internal_checking;
 
@@ -108,8 +111,8 @@
   /* Emit internal tracing message. */
   unsigned verbose_trace;
 
-  /* Support multiple threads. */
-  unsigned multi_threaded;
+  /* Support multiple threads.  XXX: not yet implemented. */
+  /* unsigned multi_threaded; */
 
   /* Wipe stack/heap objects upon unwind.  */
   unsigned wipe_stack;
Index: mf-runtime.c
===================================================================
RCS file: /cvs/gcc/gcc/libmudflap/Attic/mf-runtime.c,v
retrieving revision 1.1.2.28
diff -u -r1.1.2.28 mf-runtime.c
--- mf-runtime.c	10 Mar 2003 22:29:58 -0000	1.1.2.28
+++ mf-runtime.c	28 Mar 2003 22:26:38 -0000
@@ -16,6 +16,9 @@
 #ifdef HAVE_EXECINFO_H
 #include <execinfo.h>
 #endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 #include <assert.h>
 
 #include <string.h>
@@ -108,7 +111,7 @@
   __mf_opts.abbreviate = 1;
   __mf_opts.check_initialization = 1;
   __mf_opts.verbose_violations = 1;
-  __mf_opts.multi_threaded = 0;
+  /* __mf_opts.multi_threaded = 0; */
   __mf_opts.free_queue_length = 4;
   __mf_opts.persistent_count = 100;
   __mf_opts.crumple_zone = 32;
@@ -169,6 +172,11 @@
     {"collect-stats", 
      "collect statistics on mudflap's operation",
      set_option, 1, &__mf_opts.collect_stats},
+#if HAVE_SIGNAL
+    {"sigusr1-report",
+     "print report upon SIGUSR1",
+     set_option, 1, &__mf_opts.sigusr1_report},
+#endif
     {"internal-checking", 
      "perform more expensive internal checking",
      set_option, 1, &__mf_opts.internal_checking},
@@ -188,9 +196,11 @@
      "abbreviate repetitive listings",
      set_option, 1, &__mf_opts.abbreviate},
     /* XXX: this should be sensitive to gcc --enable-threading= setting */
+    /*
     {"multi-threaded", 
      "support multiple threads",
      set_option, 1, &__mf_opts.multi_threaded},
+    */
     {"wipe-stack",
      "wipe stack objects at unwind",
      set_option, 1, &__mf_opts.wipe_stack},
@@ -242,7 +252,7 @@
 
   fprintf (stderr, 
 	   "This is a GCC \"mudflap\" memory-checked binary.\n"
-	   "Mudflap is Copyright (C) 2002 Free Software Foundation, Inc.\n"
+	   "Mudflap is Copyright (C) 2002-2003 Free Software Foundation, Inc.\n"
 	   "\n"
 	   "The mudflap code can be controlled by an environment variable:\n"
 	   "\n"
@@ -311,8 +321,7 @@
 		strncmp (optstr, "help", 4) == 0)
 	      {
 		/* Caller will print help and exit.  */
-		rc = -1;
-		break;
+		return -1;
 	      }
 	    
 	    if (strncmp (optstr, "no-", 3) == 0)
@@ -376,6 +385,9 @@
 
   TRACE ("mf: set options from `%s'\n", saved_optstr);
 
+  /* Call this unconditionally, in case -sigusr1-report was toggled. */
+  __mf_sigusr1_respond ();
+
   return rc;
 }
 
@@ -435,6 +447,8 @@
 static unsigned long __mf_count_unregister;
 static unsigned long __mf_total_unregister_size;
 static unsigned long __mf_count_violation [__MF_VIOL_WATCH+1];
+static unsigned long __mf_sigusr1_received;
+static unsigned long __mf_sigusr1_handled;
 
 
 /* ------------------------------------------------------------------------ */
@@ -487,7 +501,7 @@
 static void __mf_unlink_object (__mf_object_tree_t *obj);
 static void __mf_describe_object (__mf_object_t *obj);
 static unsigned __mf_watch_or_not (void *ptr, size_t sz, char flag);
-
+static void __mf_sigusr1_respond ();
 
 
 /* ------------------------------------------------------------------------ */
@@ -570,9 +584,12 @@
   uintptr_t ptr_high = CLAMPSZ (ptr, sz);
   struct __mf_cache old_entry = *entry;
 
+  if (UNLIKELY (__mf_opts.sigusr1_report))
+    __mf_sigusr1_respond ();
+
   BEGIN_RECURSION_PROTECT;
-  TRACE ("mf: check ptr=%08lx size=%lu %s location=`%s'\n",
-	 ptr, sz, (type == 0 ? "read" : "write"), location);
+  TRACE ("mf: check ptr=%08lx b=%u size=%lu %s location=`%s'\n",
+	 ptr, entry_idx, sz, (type == 0 ? "read" : "write"), location);
   
   switch (__mf_opts.mudflap_mode)
     {
@@ -816,7 +833,9 @@
   new_obj->data.type = type;
   new_obj->data.name = name;
   new_obj->data.alloc_pc = pc;
+#if HAVE_GETTIMEOFDAY
   gettimeofday (& new_obj->data.alloc_time, NULL);
+#endif
   
   if (__mf_opts.backtrace > 0 && (type == __MF_TYPE_HEAP || type == __MF_TYPE_HEAP_I))
     new_obj->data.alloc_backtrace_size = 
@@ -874,6 +893,10 @@
 				type] += sz;
     }
 
+
+  if (UNLIKELY (__mf_opts.sigusr1_report))
+  __mf_sigusr1_respond ();
+
   switch (__mf_opts.mudflap_mode)
     {
     case mode_nop:
@@ -1050,8 +1073,11 @@
 __mf_unregister (void *ptr, size_t sz)
 {
   DECLARE (void, free, void *ptr);
-  BEGIN_RECURSION_PROTECT;
 
+  if (UNLIKELY (__mf_opts.sigusr1_report))
+  __mf_sigusr1_respond ();
+
+  BEGIN_RECURSION_PROTECT;
   TRACE ("mf: unregister ptr=%08lx size=%lu\n", ptr, sz);
 
   switch (__mf_opts.mudflap_mode)
@@ -1120,8 +1146,10 @@
 	    old_obj->data.deallocated_p = 1;
 	    old_obj->left = old_obj->right = NULL;
 	    old_obj->data.dealloc_pc = (uintptr_t) __builtin_return_address (0);
+#if HAVE_GETTIMEOFDAY
 	    gettimeofday (& old_obj->data.dealloc_time, NULL);
-	    
+#endif
+
 	    if (__mf_opts.backtrace > 0 && old_obj->data.type == __MF_TYPE_HEAP)
 	      old_obj->data.dealloc_backtrace_size = 
 		__mf_backtrace (& old_obj->data.dealloc_backtrace,
@@ -1265,10 +1293,11 @@
 struct tree_stats
 {
   unsigned obj_count;
-  uintptr_t total_size;
+  unsigned long total_size;
   unsigned live_obj_count;
   double total_weight;
   double weighted_size;
+  unsigned long weighted_address_bits [sizeof (uintptr_t) * 8][2];
 };
 
 
@@ -1277,6 +1306,9 @@
 {
   assert (obj != NULL);
 
+  if (obj->left)
+    __mf_tree_analyze (obj->left, s);
+
   /* Exclude never-accessed objects.  */
   if (obj->data.read_count + obj->data.write_count)
     {
@@ -1285,16 +1317,28 @@
 
       if (obj->data.liveness)
 	{
+	  unsigned i;
+	  uintptr_t addr;
+
+	  VERBOSE_TRACE ("mf: analyze low=%08lx live=%u name=`%s'\n",
+			 obj->data.low, obj->data.liveness, obj->data.name);
+
 	  s->live_obj_count ++;
 	  s->total_weight += (double) obj->data.liveness;
 	  s->weighted_size +=
 	    (double) (obj->data.high - obj->data.low + 1) *
 	    (double) obj->data.liveness;
+
+	  addr = obj->data.low;
+	  for (i=0; i<sizeof(uintptr_t) * 8; i++)
+	    {
+	      unsigned bit = addr & 1;
+	      s->weighted_address_bits[i][bit] += obj->data.liveness;
+	      addr = addr >> 1;
+	    }
 	}
     }
 
-  if (obj->left)
-    __mf_tree_analyze (obj->left, s);
   if (obj->right)
     __mf_tree_analyze (obj->right, s);
 }
@@ -1304,13 +1348,11 @@
 __mf_adapt_cache ()
 {
   struct tree_stats s;
-  double avg_weight;
-  uintptr_t avg_size;
-  uintptr_t weighted_avg_size;
   uintptr_t new_mask;
-  uintptr_t shifted;
   unsigned char new_shift;
-  double cache_utilization;
+  float cache_utilization;
+  float max_value;
+  static float smoothed_new_shift = -1.0;
   unsigned i;
 
   memset (&s, 0, sizeof (s));
@@ -1323,10 +1365,25 @@
   if (! (s.obj_count > 0) && (s.live_obj_count > 0) && (s.total_weight > 0.0))
     return;
 
-  avg_weight = s.total_weight / s.live_obj_count;
-  weighted_avg_size = (uintptr_t) (s.weighted_size / s.total_weight);
-  avg_size = (uintptr_t) (s.total_size / s.obj_count);
-  if (avg_size == 0) avg_size = 1;
+  /* Guess a good value for the shift parameter by finding an address bit that is a
+     good discriminant of lively objects.  */
+  max_value = 0.0;
+  for (i=0; i<sizeof (uintptr_t)*8; i++)
+    {
+      float value = (float) s.weighted_address_bits[i][0] * (float) s.weighted_address_bits[i][1];
+      if (max_value < value) max_value = value;
+    }
+  for (i=0; i<sizeof (uintptr_t)*8; i++)
+    {
+      float shoulder_factor = 0.7;  /* Include slightly less popular bits too.  */
+      float value = (float) s.weighted_address_bits[i][0] * (float) s.weighted_address_bits[i][1];
+      if (value >= max_value * shoulder_factor)
+	break;
+    }
+  if (smoothed_new_shift < 0) smoothed_new_shift = __mf_lc_shift;
+ /* Converge toward this slowly to reduce flapping. */  smoothed_new_shift = 0.9*smoothed_new_shift + 0.1*i;
+  new_shift = (unsigned) (smoothed_new_shift + 0.5);
+  assert (new_shift >= 0 && new_shift < sizeof (uintptr_t)*8);
 
   /* Count number of used buckets.  */
   cache_utilization = 0.0;
@@ -1334,37 +1391,14 @@
     if (__mf_lookup_cache[i].low != 0 || __mf_lookup_cache[i].high != 0)
       cache_utilization += 1.0;
   cache_utilization /= (1 + __mf_lc_mask);
-  if (cache_utilization < 0.5)
-    new_mask = __mf_lc_mask >> 1;
-  else if (cache_utilization > 0.7)
-    new_mask = (__mf_lc_mask << 1) | 1;
-  else
-    new_mask = __mf_lc_mask;
-  
-  new_mask |= 0x3ff; /* impose a practical minimum */
+
+  new_mask |= 0x3ff; /* XXX: force a large cache.  */
   new_mask &= (LOOKUP_CACHE_SIZE_MAX - 1);
 
-#if 0 /* giving up on heuristics? */
-  new_mask = __mf_lc_mask;
-#endif
-
-  /* Find a good new shift amount.  Make it big enough that the
-     popular objects take up 1-2 "cache lines".  The 24 in the
-     next line imposes a practical 16MB upper limit on the cache line
-     size.  */
-  for (new_shift=0, shifted=2; /* shifted == 2**(new_shift+1) */
-       new_shift < 24;
-       new_shift++, shifted<<=1)
-    if (shifted > weighted_avg_size)
-      break;
-    
-  VERBOSE_TRACE ("mf: adapt cache %u/%u/%lu/%.0f/%.0f => "
-		 "%.0f/%lu/%lu/%.0f%% => "
-		 "%08lx/%u\n",
-		 s.obj_count, s.live_obj_count, s.total_size,
-		 s.total_weight, s.weighted_size,
-		 avg_weight, weighted_avg_size, avg_size, (cache_utilization*100.0),
-		 new_mask, new_shift);
+  VERBOSE_TRACE ("mf: adapt cache obj=%u/%u sizes=%lu/%.0f/%.0f => "
+		 "util=%u%% m=%08lx s=%u\n",
+		 s.obj_count, s.live_obj_count, s.total_size, s.total_weight, s.weighted_size,
+		 (unsigned)(cache_utilization*100.0), new_mask, new_shift);
 
   /* We should reinitialize cache if its parameters have changed.  */
   if (new_mask != __mf_lc_mask ||
@@ -1684,13 +1718,19 @@
 static unsigned
 __mf_report_leaks (__mf_object_tree_t *node)
 {
-  static unsigned count = 0;  /* Shared amongst recursive calls.  */
-  /* XXX: when to reset?  */
+ /* The counter is amongst recursive calls, so
+    that cumulative numbers are printed below.  */
+  static unsigned count = 0;
 
-  if (node == NULL) return count;
+  if (node == NULL)  /* Reset */
+    {
+      count = 0;
+      return 0;
+    }
 
   /* Inorder traversal. */
-  __mf_report_leaks (node->left);
+  if (node->left)
+    __mf_report_leaks (node->left);
   if (node->data.type == __MF_TYPE_HEAP
       || node->data.type == __MF_TYPE_HEAP_I)
     {
@@ -1698,7 +1738,8 @@
       fprintf (stderr, "Leaked object %u:\n", count);
       __mf_describe_object (& node->data);
     }
-  __mf_report_leaks (node->right);
+  if (node->right)
+    __mf_report_leaks (node->right);
 
   return count;
 }
@@ -1775,6 +1816,7 @@
       /* Free up any remaining alloca()'d blocks.  */
       (void) CALL_WRAP (alloca, 0); /* XXX: doesn't work in shared mode. */
       __mf_describe_object (NULL); /* Reset description epoch.  */
+      __mf_report_leaks (NULL); /* Reset cumulative count.  */
       l = __mf_report_leaks (__mf_object_root);
       fprintf (stderr, "number of leaked objects: %u\n", l);
     }
@@ -1895,7 +1937,9 @@
     unsigned dead_p;
     unsigned num_helpful = 0;
     struct timeval now;
+#if HAVE_GETTIMEOFDAY
     gettimeofday (& now, NULL);
+#endif
 
     violation_number ++;
     fprintf (stderr,
@@ -2098,4 +2142,41 @@
   TRACE (" hits=%u\n", count);
 
   return count;
+}
+
+
+void
+__mf_sigusr1_handler (int num)
+{
+  __mf_sigusr1_received ++;
+}
+
+/* Install or remove SIGUSR1 handler as necessary.
+   Also, respond to a received pending SIGUSR1.  */
+void
+__mf_sigusr1_respond ()
+{
+  static int handler_installed;
+
+#if HAVE_SIGNAL
+  /* Manage handler */
+  if (__mf_opts.sigusr1_report && ! handler_installed)
+    {
+      signal (SIGUSR1, __mf_sigusr1_handler);
+      handler_installed = 1;
+    }
+  else if(! __mf_opts.sigusr1_report && handler_installed)
+    {
+      signal (SIGUSR1, SIG_DFL);
+      handler_installed = 0;
+    }
+#endif
+
+  /* Manage enqueued signals */
+  if (__mf_sigusr1_received > __mf_sigusr1_handled)
+    {
+      __mf_sigusr1_handled ++;
+      __mf_report ();
+      handler_installed = 0; /* We may need to re-enable signal; this might be a SysV library. */
+    }
 }
Index: testsuite/libmudflap.c/fail27-frag.c
===================================================================
RCS file: testsuite/libmudflap.c/fail27-frag.c
diff -N testsuite/libmudflap.c/fail27-frag.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/libmudflap.c/fail27-frag.c	28 Mar 2003 22:26:38 -0000
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+char *foo (unsigned i)
+{
+  char buffer[10];
+  char *k = i ? & buffer[i] : NULL; /* defeat addr-of-local-returned warning */
+  return k;
+}
+
+int main ()
+{
+char *f = foo (5);
+f[0] = 'b';
+
+return 0;
+}
+/* { dg-output "mudflap violation 1.*" } */
+/* { dg-output "Nearby object.*" } */
+/* { dg-output "mudflap object.*buffer.*alloc.*dealloc" } */
+/* { dg-do run { xfail *-*-* } } */
Index: testsuite/libmudflap.c/pass36-frag.c
===================================================================
RCS file: testsuite/libmudflap.c/pass36-frag.c
diff -N testsuite/libmudflap.c/pass36-frag.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/libmudflap.c/pass36-frag.c	28 Mar 2003 22:26:38 -0000
@@ -0,0 +1,14 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+int main ()
+{
+char *k;
+__mf_set_options ("-sigusr1-report -print-leaks");
+k = (char *) malloc (100);
+raise (SIGUSR1);
+return 0;
+}
+/* { dg-output "Leaked object.*name=.malloc region.*objects: 1" } */


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