diff mbox

[5/5] Don't mark live recursively in gt_cleare_cache

Message ID 55A28EC3.4080202@mentor.com
State New
Headers show

Commit Message

Tom de Vries July 12, 2015, 3:58 p.m. UTC
On 12/07/15 17:45, Tom de Vries wrote:
> Hi,
>
> this patch series implements the forbidding of multi-step garbage
> collection liveness dependencies between caches.
>
> The first four patches downgrade 3 caches to non-cache, since they
> introduce multi-step dependencies. This allows us to decouple:
> - establishing a policy for multi-step dependencies in caches, and
> - fixing issues that allow us to use these 3 as caches again.
>
> 1. Downgrade debug_args_for_decl to non-cache
> 2. Add struct tree_decl_map_hasher
> 3. Downgrade debug_expr_for_decl to non-cache
> 4. Downgrade value_expr_for_decl to non-cache
> 5. Don't mark live recursively in gt_cleare_cache
>
> Bootstrapped and reg-tested on x86_64, with ENABLE_CHECKING.
>
> I'll post the patches in response to this email.
>

This patch:
- disables the recursive marking of cache entries during the cache-clear
   phase
- Adds ENABLE_CHECKING code to check that we don't end up with partially
   dead cache entries

OK for trunk?

Thanks,
- Tom

Comments

Richard Biener July 14, 2015, 10:31 a.m. UTC | #1
On Sun, Jul 12, 2015 at 5:58 PM, Tom de Vries <Tom_deVries@mentor.com> wrote:
> On 12/07/15 17:45, Tom de Vries wrote:
>>
>> Hi,
>>
>> this patch series implements the forbidding of multi-step garbage
>> collection liveness dependencies between caches.
>>
>> The first four patches downgrade 3 caches to non-cache, since they
>> introduce multi-step dependencies. This allows us to decouple:
>> - establishing a policy for multi-step dependencies in caches, and
>> - fixing issues that allow us to use these 3 as caches again.
>>
>> 1. Downgrade debug_args_for_decl to non-cache
>> 2. Add struct tree_decl_map_hasher
>> 3. Downgrade debug_expr_for_decl to non-cache
>> 4. Downgrade value_expr_for_decl to non-cache
>> 5. Don't mark live recursively in gt_cleare_cache
>>
>> Bootstrapped and reg-tested on x86_64, with ENABLE_CHECKING.
>>
>> I'll post the patches in response to this email.
>>
>
> This patch:
> - disables the recursive marking of cache entries during the cache-clear
>   phase
> - Adds ENABLE_CHECKING code to check that we don't end up with partially
>   dead cache entries
>
> OK for trunk?

It seems your docs do not match the implementation with regarding to
keep_cache_entry returning -1.  It looks like -1 is a "I do not know" value
which IMHO is bad to have.

I miss documentation of the ggc_marked_nonkey_p function and what it
is supposed to return.  As the function seems to be manually implemented
it also looks error-prone - I suppose gengtype could generate those.

+#ifdef ENABLE_CHECKING
+           gcc_assert (!ggc_marked_p (*iter));
+#endif

gcc_checking_assert ()

+#ifdef ENABLE_CHECKING
+           gcc_assert (H::ggc_marked_nonkey_p (*iter));
+#endif

likewise.

Rather than conditionalizing build of the ggc_marked_nonkey_p
functions can you mark them UNUSED (I suppose you only
avoid defined-but-not-used Werror errors)?  We try to get away
from conditional compilation.

Thanks,
Richard.

> Thanks,
> - Tom
>
diff mbox

Patch

[PATCH 5/5] Don't mark live recursively in gt_cleare_cache

2015-07-10  Tom de Vries  <tom@codesourcery.com>

	PR libgomp/66714
	* hash-table.h (gt_cleare_cache): Mark cache entry non-recursively.
	(gt_cleare_cache) [ENABLE_CHECKING]: Assert non-key components of live
	entry already marked.  Assert dead key component implies dead entry.
	* tree.h (struct tree_decl_map_cache_hasher) [ENABLE_CHECKING]: Add new
	function ggc_marked_nonkey_p.
	* tree.c (struct tree_vec_map_cache_hasher) [ENABLE_CHECKING]: Same.
	* ubsan.c (struct tree_type_map_cache_hasher) [ENABLE_CHECKING]: Same.
	* varasm.c (struct tm_clone_hasher) [ENABLE_CHECKING]: Same.
	* hash-traits.h (struct ggc_cache_remove) [ENABLE_CHECKING]: Same.
	* trans-mem.c (struct tm_wrapper_hasher) [ENABLE_CHECKING]: Same.

	* testsuite/libgomp.c/pr66714.c: New test.
---
 gcc/hash-table.h                      | 64 +++++++++++++++++++++++++++++++++--
 gcc/hash-traits.h                     |  4 +++
 gcc/trans-mem.c                       |  6 ++++
 gcc/tree.c                            |  6 ++++
 gcc/tree.h                            |  6 ++++
 gcc/ubsan.c                           |  6 ++++
 gcc/varasm.c                          |  6 ++++
 libgomp/testsuite/libgomp.c/pr66714.c | 17 ++++++++++
 8 files changed, 113 insertions(+), 2 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.c/pr66714.c

diff --git a/gcc/hash-table.h b/gcc/hash-table.h
index 12e0c96..282ba8a 100644
--- a/gcc/hash-table.h
+++ b/gcc/hash-table.h
@@ -1046,14 +1046,74 @@  gt_cleare_cache (hash_table<H> *h)
   if (!h)
     return;
 
+  /* There are roughly 2 types of cache entries.
+
+     I.
+
+     The simple one, that uses ggc_cache_remove::keep_cache_entry.
+
+       int keep_cache_entry (T &e) { return ggc_marked_p (e) ? -1 : 0; }
+
+     The function returns either live (-1) or dead (0), dependent on whether the
+     entry was marked during the marking phase.
+
+     If the entry is dead, we clear the slot holding the entry.  The slot can be
+     now be reused, and the entry will be freed during the sweeping phase.
+
+     If the entry is live we're done.  The entry itself, and anything reachable
+     from the entry have been marked during the marking phase.
+
+
+     II.
+
+     The complex one, with a non-standard keep_cache_entry.
+
+     Say we have a cache entry E with key field to and non-key field from:
+
+       struct sE {
+	 type1 from;
+	 type2 to;
+       };
+       typedef struct sE *E;
+
+     and a keep_cache_entry function:
+
+       int keep_cache_entry (E &e) { return ggc_marked_p (e->from); }
+
+     The function returns either live (1) or dead (0), dependent on whether the
+     from field of the entry was marked during the marking phase.
+
+     If the from field is dead, we clear the slot holding the entry.  The slot
+     can be now be reused, and the from field will be freed during the sweeping
+     phase.  The to field will be freed during the sweeping phase dependent on
+     whether it was marked live during the marking phase.  Furthermore, we check
+     that the entry was not marked.  If that that check fails, it means that
+     we ended up with a live entry with a dead from field.
+
+     If the from field is live, we mark the entry non-recursively live, since
+     the cache may hold the only reference to the entry.
+     However, we check that anything reachable from the entry has already been
+     marked during the marking phase.  If that that check fails, it means that
+     we ended up with a live entry with a dead to field.  */
+
   for (typename table::iterator iter = h->begin (); iter != h->end (); ++iter)
     if (!table::is_empty (*iter) && !table::is_deleted (*iter))
       {
 	int res = H::keep_cache_entry (*iter);
 	if (res == 0)
-	  h->clear_slot (&*iter);
+	  {
+#ifdef ENABLE_CHECKING
+	    gcc_assert (!ggc_marked_p (*iter));
+#endif
+	    h->clear_slot (&*iter);
+	  }
 	else if (res != -1)
-	  gt_ggc_mx (*iter);
+	  {
+	    ggc_set_mark (*iter);
+#ifdef ENABLE_CHECKING
+	    gcc_assert (H::ggc_marked_nonkey_p (*iter));
+#endif
+	  }
       }
 }
 
diff --git a/gcc/hash-traits.h b/gcc/hash-traits.h
index 450354a..9c0ff65 100644
--- a/gcc/hash-traits.h
+++ b/gcc/hash-traits.h
@@ -241,6 +241,10 @@  struct ggc_cache_remove : ggc_remove<T>
   /* Entries are weakly held because this is for caches.  */
   static void ggc_mx (T &) {}
 
+#ifdef ENABLE_CHECKING
+  static int ggc_marked_nonkey_p (T &) { return 1; }
+#endif
+
   static int
   keep_cache_entry (T &e)
   {
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index c809a2e..70432f3 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -478,6 +478,12 @@  struct tm_wrapper_hasher : ggc_cache_ptr_hash<tree_map>
     return a->base.from == b->base.from;
   }
 
+#ifdef ENABLE_CHECKING
+  static int ggc_marked_nonkey_p (tree_map *&m) {
+    return ggc_marked_p (m->to);
+  }
+#endif
+
   static int
   keep_cache_entry (tree_map *&m)
   {
diff --git a/gcc/tree.c b/gcc/tree.c
index bb4467d..fbcb37d 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -271,6 +271,12 @@  struct tree_vec_map_cache_hasher : ggc_cache_ptr_hash<tree_vec_map>
     return a->base.from == b->base.from;
   }
 
+#ifdef ENABLE_CHECKING
+  static int ggc_marked_nonkey_p (tree_vec_map *&m) {
+    return ggc_marked_p (m->to);
+  }
+#endif
+
   static int
   keep_cache_entry (tree_vec_map *&m)
   {
diff --git a/gcc/tree.h b/gcc/tree.h
index 8d8fb7e..c100c365 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4635,6 +4635,12 @@  struct tree_decl_map_cache_hasher : ggc_cache_ptr_hash<tree_decl_map>
     return tree_decl_map_eq (a, b);
   }
 
+#ifdef ENABLE_CHECKING
+  static int ggc_marked_nonkey_p (tree_decl_map *&m) {
+    return ggc_marked_p (m->to);
+  }
+#endif
+
   static int
   keep_cache_entry (tree_decl_map *&m)
   {
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 19eafab..350ad22 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -95,6 +95,12 @@  struct tree_type_map_cache_hasher : ggc_cache_ptr_hash<tree_type_map>
     return a->type.from == b->type.from;
   }
 
+#ifdef ENABLE_CHECKING
+   static int ggc_marked_nonkey_p (tree_type_map *&m) {
+     return ggc_marked_p (m->decl);
+  }
+#endif
+
   static int
   keep_cache_entry (tree_type_map *&m)
   {
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 3e76032..4e44c43 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -5793,6 +5793,12 @@  struct tm_clone_hasher : ggc_cache_ptr_hash<tree_map>
   static hashval_t hash (tree_map *m) { return tree_map_hash (m); }
   static bool equal (tree_map *a, tree_map *b) { return tree_map_eq (a, b); }
 
+#ifdef ENABLE_CHECKING
+  static int ggc_marked_nonkey_p (tree_map *&m) {
+    return ggc_marked_p (m->to);
+  }
+#endif
+
   static int
   keep_cache_entry (tree_map *&e)
   {
diff --git a/libgomp/testsuite/libgomp.c/pr66714.c b/libgomp/testsuite/libgomp.c/pr66714.c
new file mode 100644
index 0000000..a8c5bbdb
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pr66714.c
@@ -0,0 +1,17 @@ 
+/* { dg-do "compile" } */
+/* { dg-additional-options "--param ggc-min-expand=0" } */
+/* { dg-additional-options "--param ggc-min-heapsize=0" } */
+/* { dg-additional-options "-g" } */
+
+/* Minimized from target-2.c.  */
+
+void
+fn3 (int x)
+{
+  double b[3 * x];
+  int i;
+  #pragma omp target
+    #pragma omp parallel for
+      for (i = 0; i < x; i++)
+	b[i] += 1;
+}
-- 
1.9.1