public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-7765] [nvptx] Add warp sync at simt exit
@ 2022-03-22 13:40 Tom de Vries
  0 siblings, 0 replies; only message in thread
From: Tom de Vries @ 2022-03-22 13:40 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:a624388b9546b066250be8baa118b7d50c403c25

commit r12-7765-ga624388b9546b066250be8baa118b7d50c403c25
Author: Tom de Vries <tdevries@suse.de>
Date:   Wed Mar 9 10:35:14 2022 +0100

    [nvptx] Add warp sync at simt exit
    
    Consider this code (with N defined to 1024):
    ...
      float v = 0.0;
      #pragma omp target map(tofrom: v)
      #pragma omp parallel for simd
      for (int i = 0 ; i < N; i++)
        {
          #pragma omp atomic update
          v = v + 1.0;
        }
    ...
    
    It hangs when executing on target board unix/-foffload=-misa=sm_75, using
    drivers 470.103.01 and 510.54 on a T400 board (sm_75).
    
    I'm tentatively identifying the problem as a bug in -muniform-simt for
    architectures that support Independent Thread Scheduling (sm_70 and later).
    
    The problem -muniform-simt is trying to address is to make sure that a
    register produced outside an openmp simd region is available when used in any
    lane inside an simd region.
    
    The solution is to, outside an simd region, execute in all warp lanes, thus
    producing consistent values in result registers in each warp thread.
    
    This approach doesn't work when executing in all warp lanes multiplies the
    side effects from 1 to 32 separate side effects, which is the case for atomic
    insns.  So atomic insns are rewritten to execute only in lane 0, and if
    there are any results, those are propagated to the other threads in the warp.
    [ And likewise for system calls malloc, free, vprintf. ]
    
    Now, consider a non-atomic update: ld, add, store.  The store has side
    effects, are those multiplied or not?
    
    Pre-sm_70 we can assume that at the end of an SIMT region, any divergent
    control flow has reconverged, and we have a uniform warp, executing in lock
    step.  So:
    - the load will load the same value into the result register across the warp,
    - the add will write the same value into the result register across the warp,
    - the store will write the same value to the same memory location, 32 times,
      at once, having the result of a single store.
    So, no side-effect multiplication (well, at least that's the observation).
    
    Starting sm_70, the threads in a warp are no longer guaranteed to reconverge
    after divergence.  There's a "Convergence Optimizer" that can can identify
    that it is safe for a warp to reconverge, but that works only as long as the
    code does not contain "synchronizing operations".
    
    Consequently, the ld, add, store sequence can be executed by a non-uniform
    warp, which means the side effects can have multiplied, and the registers are
    no longer guarantueed to be in sync.
    
    The atomic update in the example above is translated using an atom.cas loop,
    which means that we have divergence (because only one thread is allowed to
    succeed at a time) and the "Convergence Optimizer" doesn't reconverge probably
    because the atom.cas counts as a "synchronizing operation".  So, it seems
    plausible that the root cause for the mentioned hang is the problem described
    above.
    
    Fix this by adding an explicit warp sync at simt exit.
    
    Note that we're assuming here that the warp will stay uniform until the next
    SIMT region entry.
    
    Tested on x86_64 with nvptx accelerator.
    
    gcc/ChangeLog:
    
    2022-03-09  Tom de Vries  <tdevries@suse.de>
    
            PR target/104916
            PR target/104783
            * config/nvptx/nvptx.md (define_expand "omp_simt_exit"): Emit warp
            sync (or uniform warp check for mptx < 6.0).
    
    libgomp/ChangeLog:
    
    2022-03-15  Tom de Vries  <tdevries@suse.de>
    
            PR target/104916
            PR target/104783
            * testsuite/libgomp.c/pr104783-2.c: New test.

Diff:
---
 gcc/config/nvptx/nvptx.md                |  4 ++++
 libgomp/testsuite/libgomp.c/pr104783-2.c | 25 +++++++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/gcc/config/nvptx/nvptx.md b/gcc/config/nvptx/nvptx.md
index 1dec7caa0d1..5550ce25513 100644
--- a/gcc/config/nvptx/nvptx.md
+++ b/gcc/config/nvptx/nvptx.md
@@ -1881,6 +1881,10 @@
   ""
 {
   emit_insn (gen_omp_simt_exit (Pmode, operands[0]));
+  if (TARGET_PTX_6_0)
+    emit_insn (gen_nvptx_warpsync ());
+  else
+    emit_insn (gen_nvptx_uniform_warp_check ());
   DONE;
 })
 
diff --git a/libgomp/testsuite/libgomp.c/pr104783-2.c b/libgomp/testsuite/libgomp.c/pr104783-2.c
new file mode 100644
index 00000000000..8750d915d01
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/pr104783-2.c
@@ -0,0 +1,25 @@
+#define N (32 * 32)
+
+#define TYPE float
+#define VAR v
+#define INIT 0.0
+#define UPDATE + 1.0
+#define EXPECTED N
+
+int
+main (void)
+{
+  TYPE VAR = INIT;
+  #pragma omp target map(tofrom: VAR)
+  #pragma omp parallel for simd
+  for (int i = 0 ; i < N; i++)
+    {
+      #pragma omp atomic update
+      VAR = VAR UPDATE;
+    }
+
+  if (VAR != EXPECTED)
+    __builtin_abort ();
+
+  return 0;
+}


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

only message in thread, other threads:[~2022-03-22 13:40 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-22 13:40 [gcc r12-7765] [nvptx] Add warp sync at simt exit Tom de Vries

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