public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/omp/gcc-12] libgomp: Fix occassional hangs with taskwait nowait depend
@ 2022-07-05  8:10 Tobias Burnus
  0 siblings, 0 replies; only message in thread
From: Tobias Burnus @ 2022-07-05  8:10 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:4d893a716e17e428c93553a9fa3b6349cc776b38

commit 4d893a716e17e428c93553a9fa3b6349cc776b38
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Jul 5 09:19:47 2022 +0200

    libgomp: Fix occassional hangs with taskwait nowait depend
    
    Richi reported occassional hangs with taskwait-depend-nowait-1.*
    tests and I've finally manged to reproduce.  The problem is if
    taskwait depend without nowait is encountered soon after
    taskwait depend nowait and the former depends on the latter and there
    is no other work to do, the taskwait depend without nowait is put
    to sleep, but the empty_task optimization in
    gomp_task_run_post_handle_dependers wouldn't wake it up in that
    case.  gomp_task_run_post_handle_dependers normally does some wakeups
    because it schedules more work (another task), which is not the
    case of empty_task, but we need to do the wakeups that would be done
    upon task completion so that we awake sleeping threads when the
    last child is done.
    So, the taskwait-depend-nowait-1.* testcase is fixed with the
    else if (__builtin_expect (task->parent_depends_on, 0) part of
    the patch.
    The new testcase can hang on another problem, if the empty task
    is the last task of a taskgroup, we need to use atomic store
    like elsewhere to decrease the counter to 0, and wake up taskgroup
    end if needed.
    Yet another spot which can sleep is normal taskwait (without depend),
    but I believe nothing needs to be done for that - in that case we
    await solely until the children's queue has no tasks, tasks still
    waiting for dependencies aren't accounted in that, but the reason
    is that if taskwait should wait for something, there needs to be at least
    one active child doing something (in the children queue), which then
    possibly awakes some of its siblings when the dependencies are met,
    or in the empty task case awakes further dependencies, but in any
    case the child that finished is still handled as active child and
    will awake taskwait at the end if there is nothing further to
    do.
    Last sleeping case are barriers, but that is handled by ++ret and
    awaking the barrier.
    
    2022-05-25  Jakub Jelinek  <jakub@redhat.com>
    
            * task.c (gomp_task_run_post_handle_dependers): If empty_task
            is the last task taskwait depend depends on, wake it up.
            Similarly if it is the last child of a taskgroup, use atomic
            store instead of decrement and awak taskgroup wait if any.
            * testsuite/libgomp.c-c++-common/taskwait-depend-nowait-2.c: New test.
    
    (cherry picked from commit c125f504c43a1d863b040375872b6696a6c2b681)

Diff:
---
 libgomp/ChangeLog.omp                              | 11 +++++
 libgomp/task.c                                     | 22 +++++++++-
 .../taskwait-depend-nowait-2.c                     | 48 ++++++++++++++++++++++
 3 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/libgomp/ChangeLog.omp b/libgomp/ChangeLog.omp
index dd0db03a02d..d20fe4bdf7a 100644
--- a/libgomp/ChangeLog.omp
+++ b/libgomp/ChangeLog.omp
@@ -1,3 +1,14 @@
+2022-07-05  Tobias Burnus  <tobias@codesourcery.com>
+
+	Backport from mainline:
+	2022-05-25  Jakub Jelinek  <jakub@redhat.com>
+
+	* task.c (gomp_task_run_post_handle_dependers): If empty_task
+	is the last task taskwait depend depends on, wake it up.
+	Similarly if it is the last child of a taskgroup, use atomic
+	store instead of decrement and awak taskgroup wait if any.
+	* testsuite/libgomp.c-c++-common/taskwait-depend-nowait-2.c: New test.
+
 2022-07-05  Tobias Burnus  <tobias@codesourcery.com>
 
 	Backport from mainline:
diff --git a/libgomp/task.c b/libgomp/task.c
index 7925e5873c4..30cd046df2a 100644
--- a/libgomp/task.c
+++ b/libgomp/task.c
@@ -1382,10 +1382,30 @@ gomp_task_run_post_handle_dependers (struct gomp_task *child_task,
 	{
 	  if (!parent)
 	    task->parent = NULL;
+	  else if (__builtin_expect (task->parent_depends_on, 0)
+		   && --parent->taskwait->n_depend == 0
+		   && parent->taskwait->in_depend_wait)
+	    {
+	      parent->taskwait->in_depend_wait = false;
+	      gomp_sem_post (&parent->taskwait->taskwait_sem);
+	    }
 	  if (gomp_task_run_post_handle_depend (task, team))
 	    ++ret;
 	  if (taskgroup)
-	    taskgroup->num_children--;
+	    {
+	      if (taskgroup->num_children > 1)
+		--taskgroup->num_children;
+	      else
+		{
+		  __atomic_store_n (&taskgroup->num_children, 0,
+				    MEMMODEL_RELEASE);
+		  if (taskgroup->in_taskgroup_wait)
+		    {
+		      taskgroup->in_taskgroup_wait = false;
+		      gomp_sem_post (&taskgroup->taskgroup_sem);
+		    }
+		}
+	    }
 	  gomp_finish_task (task);
 	  free (task);
 	  continue;
diff --git a/libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-2.c b/libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-2.c
new file mode 100644
index 00000000000..371ddf5639d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-2.c
@@ -0,0 +1,48 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main ()
+{
+  int a[48], b = 1;
+  #pragma omp parallel num_threads (4)
+  {
+    #pragma omp barrier
+    #pragma omp single
+    {
+      int i;
+      for (i = 0; i < 48; ++i)
+	#pragma omp task depend(in: a) shared(a)
+	  a[i] = i;
+      for (i = 0; i < 32; ++i)
+	{
+	  #pragma omp taskwait depend(inout: a) nowait
+	}
+      #pragma omp taskwait
+      for (i = 0; i < 48; ++i)
+	if (a[i] != i)
+	  abort ();
+      for (i = 0; i < 48; ++i)
+	#pragma omp task depend(in: a) shared(a)
+	  a[i] = 2 * i + 1;
+      #pragma omp taskgroup
+      {
+	#pragma omp taskwait depend(inoutset: a) nowait
+	#pragma omp taskgroup
+	{
+	  #pragma omp taskwait depend(inoutset: a) nowait
+	}
+      }
+      for (i = 0; i < 48; ++i)
+	if (a[i] != 2 * i + 1)
+	  abort ();
+      #pragma omp task depend(in: a) shared(a)
+      usleep (5000);
+      #pragma omp taskgroup
+      {
+	#pragma omp taskwait depend(inout: a) nowait
+      }
+    }
+  }
+  return 0;
+}


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

only message in thread, other threads:[~2022-07-05  8:10 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-05  8:10 [gcc/devel/omp/gcc-12] libgomp: Fix occassional hangs with taskwait nowait depend Tobias Burnus

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).