public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-11] OpenACC reference count consistency checking
@ 2021-05-13 16:08 Kwok Yeung
  0 siblings, 0 replies; only message in thread
From: Kwok Yeung @ 2021-05-13 16:08 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:88122b84af068fe1db5ba014527cb6f9d5693293

commit 88122b84af068fe1db5ba014527cb6f9d5693293
Author: Julian Brown <julian@codesourcery.com>
Date:   Fri Nov 30 02:40:49 2018 -0800

    OpenACC reference count consistency checking
    
    2018-11-28  Julian Brown  <julian@codesourcery.com>
                Tobias Burnus  <tobias@codesourcery.com>
    
            libgomp/
            * libgomp.h (RC_CHECKING): New macro, disabled by default, guarding all
            hunks in this patch.
            (target_mem_desc): Add forward declaration.
            (async_tgt_use): New struct.
            (target_mem_desc): Add refcount_chk, mark fields.
            (acc_dispatch_t): Add tgt_uses, au_lock fields.
            (dump_tgt, gomp_rc_check): Add prototypes.
            * oacc-async (goacc_async_unmap_tgt): Add refcount self-check code.
            (goacc_async_copyout_unmap_vars): Likewise.
            (goacc_remove_var_async): Likewise.
            * oacc-parallel.c (GOACC_parallel_keyed_internal): Add refcount
            self-check code.
            (GOACC_data_start, GOACC_data_end, GOACC_enter_exit_data): Likewise.
            * target.c (stdio.h): Include.
            (dump_tgt, rc_check_clear, rc_check_count, rc_check_verify)
            (gomp_rc_check): New functions to consistency-check reference counts.
            (gomp_target_init): Initialise self-check-related device fields.

Diff:
---
 libgomp/ChangeLog.omp   |  20 ++++++
 libgomp/libgomp.h       |  18 +++++
 libgomp/oacc-parallel.c |  34 +++++++++
 libgomp/target.c        | 182 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 254 insertions(+)

diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp
new file mode 100644
index 00000000000..568ad9ccac6
--- /dev/null
+++ b/libgomp/ChangeLog.omp
@@ -0,0 +1,20 @@
+2018-11-28  Julian Brown  <julian@codesourcery.com>
+	    Tobias Burnus  <tobias@codesourcery.com>
+
+	* libgomp.h (RC_CHECKING): New macro, disabled by default, guarding all
+	hunks in this patch.
+	(target_mem_desc): Add forward declaration.
+	(async_tgt_use): New struct.
+	(target_mem_desc): Add refcount_chk, mark fields.
+	(acc_dispatch_t): Add tgt_uses, au_lock fields.
+	(dump_tgt, gomp_rc_check): Add prototypes.
+	* oacc-async (goacc_async_unmap_tgt): Add refcount self-check code.
+	(goacc_async_copyout_unmap_vars): Likewise.
+	(goacc_remove_var_async): Likewise.
+	* oacc-parallel.c (GOACC_parallel_keyed_internal): Add refcount
+	self-check code.
+	(GOACC_data_start, GOACC_data_end, GOACC_enter_exit_data): Likewise.
+	* target.c (stdio.h): Include.
+	(dump_tgt, rc_check_clear, rc_check_count, rc_check_verify)
+	(gomp_rc_check): New functions to consistency-check reference counts.
+	(gomp_target_init): Initialise self-check-related device fields.
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index ef1bb4907b6..c1a8ee264cb 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -988,9 +988,17 @@ struct target_var_desc {
   uintptr_t length;
 };
 
+/* Uncomment to enable reference-count consistency checking (for development
+   use only).  */
+//#define RC_CHECKING 1
+
 struct target_mem_desc {
   /* Reference count.  */
   uintptr_t refcount;
+#ifdef RC_CHECKING
+  uintptr_t refcount_chk;
+  bool mark;
+#endif
   /* All the splay nodes allocated together.  */
   splay_tree_node array;
   /* Start of the target region.  */
@@ -1046,6 +1054,10 @@ struct splay_tree_key_s {
   uintptr_t refcount;
   /* Dynamic reference count.  */
   uintptr_t dynamic_refcount;
+#ifdef RC_CHECKING
+  /* The recalculated reference count, for verification.  */
+  uintptr_t refcount_chk;
+#endif
   struct splay_tree_aux *aux;
 };
 
@@ -1201,6 +1213,12 @@ extern void gomp_detach_pointer (struct gomp_device_descr *,
 				 struct goacc_asyncqueue *, splay_tree_key,
 				 uintptr_t, bool, struct gomp_coalesce_buf *);
 
+#ifdef RC_CHECKING
+extern void dump_tgt (const char *, struct target_mem_desc *);
+extern void gomp_rc_check (struct gomp_device_descr *,
+			   struct target_mem_desc *);
+#endif
+
 extern struct target_mem_desc *gomp_map_vars (struct gomp_device_descr *,
 					      size_t, void **, void **,
 					      size_t *, void *, bool,
diff --git a/libgomp/oacc-parallel.c b/libgomp/oacc-parallel.c
index cf1baf6291d..4f48b052239 100644
--- a/libgomp/oacc-parallel.c
+++ b/libgomp/oacc-parallel.c
@@ -292,6 +292,16 @@ GOACC_parallel_keyed (int flags_m, void (*fn) (void *),
 
   tgt = gomp_map_vars_async (acc_dev, aq, mapnum, hostaddrs, NULL, sizes, kinds,
 			     true, GOMP_MAP_VARS_OPENACC);
+
+#ifdef RC_CHECKING
+  gomp_mutex_lock (&acc_dev->lock);
+  assert (tgt);
+  dump_tgt (__FUNCTION__, tgt);
+  tgt->prev = thr->mapped_data;
+  gomp_rc_check (acc_dev, tgt);
+  gomp_mutex_unlock (&acc_dev->lock);
+#endif
+
   if (profiling_p)
     {
       prof_info.event_type = acc_ev_enter_data_end;
@@ -347,6 +357,12 @@ GOACC_parallel_keyed (int flags_m, void (*fn) (void *),
       thr->prof_info = NULL;
       thr->api_info = NULL;
     }
+
+#ifdef RC_CHECKING
+  gomp_mutex_lock (&acc_dev->lock);
+  gomp_rc_check (acc_dev, thr->mapped_data);
+  gomp_mutex_unlock (&acc_dev->lock);
+#endif
 }
 
 /* Legacy entry point (GCC 5).  Only provide host fallback execution.  */
@@ -461,6 +477,12 @@ GOACC_data_start (int flags_m, size_t mapnum,
       tgt->prev = thr->mapped_data;
       thr->mapped_data = tgt;
 
+#ifdef RC_CHECKING
+      gomp_mutex_lock (&acc_dev->lock);
+      gomp_rc_check (acc_dev, thr->mapped_data);
+      gomp_mutex_unlock (&acc_dev->lock);
+#endif
+
       goto out_prof;
     }
 
@@ -545,6 +567,12 @@ GOACC_data_end (void)
   gomp_unmap_vars (tgt, true);
   gomp_debug (0, "  %s: mappings restored\n", __FUNCTION__);
 
+#ifdef RC_CHECKING
+  gomp_mutex_lock (&thr->dev->lock);
+  gomp_rc_check (thr->dev, thr->mapped_data);
+  gomp_mutex_unlock (&thr->dev->lock);
+#endif
+
   if (profiling_p)
     {
       prof_info.event_type = acc_ev_exit_data_end;
@@ -710,6 +738,12 @@ GOACC_update (int flags_m, size_t mapnum,
       thr->prof_info = NULL;
       thr->api_info = NULL;
     }
+
+#ifdef RC_CHECKING
+  gomp_mutex_lock (&acc_dev->lock);
+  gomp_rc_check (acc_dev, thr->mapped_data);
+  gomp_mutex_unlock (&acc_dev->lock);
+#endif
 }
 
 
diff --git a/libgomp/target.c b/libgomp/target.c
index 4a4e1f80745..9b952f79b7c 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -38,6 +38,9 @@
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
+#ifdef RC_CHECKING
+#include <stdio.h>
+#endif
 
 #ifdef PLUGIN_SUPPORT
 #include <dlfcn.h>
@@ -360,6 +363,185 @@ gomp_free_device_memory (struct gomp_device_descr *devicep, void *devptr)
     }
 }
 
+#ifdef RC_CHECKING
+void
+dump_tgt (const char *where, struct target_mem_desc *tgt)
+{
+  if (!getenv ("GOMP_DEBUG_TGT"))
+    return;
+
+  fprintf (stderr, "%s: %s: tgt=%p\n", __FUNCTION__, where, (void*) tgt);
+  fprintf (stderr, "refcount=%d\n", (int) tgt->refcount);
+  fprintf (stderr, "tgt_start=%p\n", (void*) tgt->tgt_start);
+  fprintf (stderr, "tgt_end=%p\n", (void*) tgt->tgt_end);
+  fprintf (stderr, "to_free=%p\n", tgt->to_free);
+  fprintf (stderr, "list_count=%d\n", (int) tgt->list_count);
+  for (int i = 0; i < tgt->list_count; i++)
+    {
+      fprintf (stderr, "list item %d:\n", i);
+      fprintf (stderr, "  key: %p\n", (void*) tgt->list[i].key);
+      if (tgt->list[i].key)
+	{
+	  fprintf (stderr, "  key.host_start=%p\n",
+		   (void*) tgt->list[i].key->host_start);
+	  fprintf (stderr, "  key.host_end=%p\n",
+		   (void*) tgt->list[i].key->host_end);
+	  fprintf (stderr, "  key.tgt=%p\n", (void*) tgt->list[i].key->tgt);
+	  fprintf (stderr, "  key.offset=%d\n",
+		   (int) tgt->list[i].key->tgt_offset);
+	  fprintf (stderr, "  key.refcount=%d\n",
+		   (int) tgt->list[i].key->refcount);
+	  if (tgt->list[i].key->refcount == REFCOUNT_LINK)
+	    fprintf (stderr, "  key.aux.link_key=%p\n",
+		     (void*) tgt->list[i].key->aux->link_key);
+	  else
+	    {
+	      fprintf (stderr, "  key.virtual_refcount=%d\n",
+		       (int) tgt->list[i].key->virtual_refcount);
+	      fprintf (stderr, "  key.aux.attach_count=%p\n",
+		       (void*) tgt->list[i].key->aux->attach_count);
+	    }
+	}
+    }
+  fprintf (stderr, "\n");
+}
+
+static void
+rc_check_clear (splay_tree_node node)
+{
+  splay_tree_key k = &node->key;
+
+  k->refcount_chk = 0;
+  k->tgt->refcount_chk = 0;
+  k->tgt->mark = false;
+
+  if (node->left)
+    rc_check_clear (node->left);
+  if (node->right)
+    rc_check_clear (node->right);
+}
+
+static void
+rc_check_count (splay_tree_node node)
+{
+  splay_tree_key k = &node->key;
+  struct target_mem_desc *t;
+
+  /* Add virtual reference counts ("acc enter data", etc.) for this key.  */
+  k->refcount_chk += k->virtual_refcount;
+
+  t = k->tgt;
+  t->refcount_chk++;
+
+  if (!t->mark)
+    {
+      for (int i = 0; i < t->list_count; i++)
+	if (t->list[i].key)
+	  t->list[i].key->refcount_chk++;
+
+      t->mark = true;
+    }
+
+  if (node->left)
+    rc_check_count (node->left);
+  if (node->right)
+    rc_check_count (node->right);
+}
+
+static bool
+rc_check_verify (splay_tree_node node, bool noisy, bool errors)
+{
+  splay_tree_key k = &node->key;
+  struct target_mem_desc *t;
+
+  if (k->refcount != REFCOUNT_INFINITY)
+    {
+      if (noisy)
+	fprintf (stderr, "key %p (%p..+%d): rc=%d/%d, virt_rc=%d\n", k,
+		 (void *) k->host_start, (int) (k->host_end - k->host_start),
+		 (int) k->refcount, (int) k->refcount_chk,
+		 (int) k->virtual_refcount);
+
+      if (k->refcount != k->refcount_chk)
+	{
+	  if (noisy)
+	    fprintf (stderr, "  -- key refcount mismatch!\n");
+	  errors = true;
+	}
+
+      t = k->tgt;
+
+      if (noisy)
+	fprintf (stderr, "tgt %p: rc=%d/%d\n", t, (int) t->refcount,
+		 (int) t->refcount_chk);
+
+      if (t->refcount != t->refcount_chk)
+	{
+	  if (noisy)
+	    fprintf (stderr,
+		     "  -- target memory descriptor refcount mismatch!\n");
+	  errors = true;
+	}
+    }
+
+  if (node->left)
+    errors |= rc_check_verify (node->left, noisy, errors);
+  if (node->right)
+    errors |= rc_check_verify (node->right, noisy, errors);
+
+  return errors;
+}
+
+/* Call with device locked.  */
+
+attribute_hidden void
+gomp_rc_check (struct gomp_device_descr *devicep, struct target_mem_desc *tgt)
+{
+  splay_tree sp = &devicep->mem_map;
+
+  bool noisy = getenv ("GOMP_DEBUG_TGT") != 0;
+
+  if (noisy)
+    fprintf (stderr, "\n*** GOMP_RC_CHECK ***\n\n");
+
+  if (sp->root)
+    {
+      rc_check_clear (sp->root);
+
+      for (struct target_mem_desc *t = tgt; t; t = t->prev)
+	{
+	  t->refcount_chk = 0;
+	  t->mark = false;
+	}
+
+      /* Add references for interconnected splay-tree keys.  */
+      rc_check_count (sp->root);
+
+      /* Add references for the tgt for a currently-executing kernel and/or
+	 any enclosing data directives.  */
+      for (struct target_mem_desc *t = tgt; t; t = t->prev)
+	{
+	  t->refcount_chk++;
+
+	  if (!t->mark)
+	    {
+	      for (int i = 0; i < t->list_count; i++)
+		if (t->list[i].key)
+		  t->list[i].key->refcount_chk++;
+
+	      t->mark = true;
+	    }
+	}
+
+      if (rc_check_verify (sp->root, noisy, false))
+	{
+	  gomp_mutex_unlock (&devicep->lock);
+	  gomp_fatal ("refcount checking failure");
+	}
+    }
+}
+#endif
+
 /* Handle the case where gomp_map_lookup, splay_tree_lookup or
    gomp_map_0len_lookup found oldn for newn.
    Helper function of gomp_map_vars.  */


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-05-13 16:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-13 16:08 [gcc/devel/omp/gcc-11] OpenACC reference count consistency checking Kwok Yeung

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).