diff mbox series

[9/9,OpenACC] Don't detach for no-op exit data with zero dynamic refcount

Message ID 5309b57f3707783cf65c2b6c5b9b784d8e61b760.1592343757.git.julian@codesourcery.com
State New
Headers show
Series Refcounting and manual deep copy improvements | expand

Commit Message

Julian Brown June 16, 2020, 10:39 p.m. UTC
This patch fixes a set of XFAILs in some recently-added patches by
skipping a detach operation on "no-op" exit data operations for blocks
with zero dynamic refcount.  This takes advantage of the ordering of
detach clauses with respect to associated data-movement clauses: i.e.,
they are grouped together adjacently.

OK?

Julian

ChangeLog

	libgomp/
	* oacc-mem.c (find_group_last): Handle detach operations.
	(goacc_exit_data_internal): Detect detachments that are part of copyout
	operations, and suppress them if dynamic refcount is zero.
	* testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90: Remove XFAILs.
	* testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90: Fix typo.
	* testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90: Remove XFAILs.
	* testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90: Likewise.
	* testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90: Likewise.
	* testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90: Likewise.
	* testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90: Likewise.
	* testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90: Likewise.
---
 libgomp/oacc-mem.c                            | 54 ++++++++++++++++---
 .../mdc-refcount-1-1-1.f90                    |  6 +--
 .../mdc-refcount-1-1-2.F90                    |  2 +-
 .../mdc-refcount-1-2-1.f90                    |  6 +--
 .../mdc-refcount-1-2-2.f90                    |  6 +--
 .../mdc-refcount-1-3-1.f90                    |  6 +--
 .../mdc-refcount-1-3-2.f90                    |  5 +-
 .../mdc-refcount-1-4-1.f90                    |  6 +--
 .../mdc-refcount-1-4-2.f90                    |  5 +-
 9 files changed, 55 insertions(+), 41 deletions(-)

Comments

Thomas Schwinge July 24, 2020, 2:18 p.m. UTC | #1
Hi Julian!

On 2020-06-16T15:39:45-0700, Julian Brown <julian@codesourcery.com> wrote:
> This patch fixes a set of XFAILs

The overall goal of couse is not to resolve XFAILs, but to implement the
expected behavior.  :-)

> in some recently-added patches by
> skipping a detach operation on "no-op" exit data operations for blocks
> with zero dynamic refcount.

So this is one aspect of <https://gcc.gnu.org/PR95203> "OpenACC 2.6 deep
copy: attach/detach API routines: no-op behavior".

> This takes advantage of the ordering of
> detach clauses with respect to associated data-movement clauses: i.e.,
> they are grouped together adjacently.

I'm not convinced that it's sufficient to just special-case these cases.
Instead, per the OpenACC "Data Clause Actions" etc., shouldn't basically
all 'gomp_fatal's that we have on 'attach'/'detach' code paths turn into
no-ops ("no action is taken")?


And I'd then again like to bring forward my idea from another review:

| we may (rather easily?) add a flag variable (ICV;
| initialized from an environment variable) to guard this checking
| behavior?

Here: to *keep* the 'gomp_fatal's.

| I suppose we may now have a few libgomp testcases that
| actually do [check things via expected 'gomp_fatal's],
| which wouldn't work any longer [...].

Such testcases could then 'dg-set-target-env-var "GOMP_ATTACH_FATAL" "1"'
(better name is desirable), and have one variant with and one variant
without that enabled.


Before you start re-working the patch, let's please first get agreement
on what exactly we intend to achieve.


Grüße
 Thomas


>       libgomp/
>       * oacc-mem.c (find_group_last): Handle detach operations.
>       (goacc_exit_data_internal): Detect detachments that are part of copyout
>       operations, and suppress them if dynamic refcount is zero.
>       * testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90: Remove XFAILs.
>       * testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90: Fix typo.
>       * testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90: Remove XFAILs.
>       * testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90: Likewise.
>       * testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90: Likewise.
>       * testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90: Likewise.
>       * testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90: Likewise.
>       * testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90: Likewise.
> ---
>  libgomp/oacc-mem.c                            | 54 ++++++++++++++++---
>  .../mdc-refcount-1-1-1.f90                    |  6 +--
>  .../mdc-refcount-1-1-2.F90                    |  2 +-
>  .../mdc-refcount-1-2-1.f90                    |  6 +--
>  .../mdc-refcount-1-2-2.f90                    |  6 +--
>  .../mdc-refcount-1-3-1.f90                    |  6 +--
>  .../mdc-refcount-1-3-2.f90                    |  5 +-
>  .../mdc-refcount-1-4-1.f90                    |  6 +--
>  .../mdc-refcount-1-4-2.f90                    |  5 +-
>  9 files changed, 55 insertions(+), 41 deletions(-)
>
> diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c
> index 745cb132621..f852652c048 100644
> --- a/libgomp/oacc-mem.c
> +++ b/libgomp/oacc-mem.c
> @@ -987,7 +987,9 @@ find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds)
>      {
>      case GOMP_MAP_TO_PSET:
>        if (pos + 1 < mapnum
> -       && (kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH)
> +       && ((kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH
> +           || (kinds[pos + 1] & 0xff) == GOMP_MAP_DETACH
> +           || (kinds[pos + 1] & 0xff) == GOMP_MAP_FORCE_DETACH))
>       return pos + 1;
>
>        while (pos + 1 < mapnum
> @@ -1010,6 +1012,8 @@ find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds)
>        break;
>
>      case GOMP_MAP_ATTACH:
> +    case GOMP_MAP_DETACH:
> +    case GOMP_MAP_FORCE_DETACH:
>        return pos;
>
>      default:
> @@ -1025,7 +1029,9 @@ find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds)
>        /* We can have a single GOMP_MAP_ATTACH mapping after a to/from
>        mapping.  */
>        if (pos + 1 < mapnum
> -       && (kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH)
> +       && ((kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH
> +           || (kinds[pos + 1] & 0xff) == GOMP_MAP_DETACH
> +           || (kinds[pos + 1] & 0xff) == GOMP_MAP_FORCE_DETACH))
>       return pos + 1;
>
>        /* We can have zero or more GOMP_MAP_POINTER mappings after a to/from
> @@ -1168,15 +1174,43 @@ goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum,
>  {
>    gomp_mutex_lock (&acc_dev->lock);
>
> -  /* Handle "detach" before copyback/deletion of mapped data.  */
> -  for (size_t i = 0; i < mapnum; ++i)
> +  /* Handle "detach" before copyback/deletion of mapped data.  If this isn't a
> +     standalone "detach" clause, take care to skip the "detach" operation if
> +     the dynamic refcount of the data to be detached is zero.  */
> +  for (size_t grp = 0; grp < mapnum; grp++)
>      {
> -      unsigned char kind = kinds[i] & 0xff;
> +      size_t i = grp, group_last = find_group_last (grp, mapnum, sizes, kinds);
> +      unsigned char kind = kinds[grp] & 0xff;
>        bool finalize = false;
> +
>        switch (kind)
>       {
> +     case GOMP_MAP_TO_PSET:
> +     case GOMP_MAP_TOFROM:
> +     case GOMP_MAP_FROM:
> +     case GOMP_MAP_FORCE_FROM:
> +     case GOMP_MAP_RELEASE:
> +     case GOMP_MAP_DELETE:
> +       {
> +         if (i + 1 >= mapnum)
> +           break;
> +         kind = kinds[i + 1] & 0xff;
> +         if (kind != GOMP_MAP_FORCE_DETACH && kind != GOMP_MAP_DETACH)
> +           break;
> +         splay_tree_key n = lookup_host (acc_dev, hostaddrs[i], sizes[i]);
> +         if (n == NULL)
> +           {
> +             gomp_mutex_unlock (&acc_dev->lock);
> +             gomp_fatal ("target data not mapped for detach operation");
> +           }
> +         i++;
> +         if (n->dynamic_refcount == 0)
> +           break;
> +       }
> +       /* Fallthrough.  */
> +
>       case GOMP_MAP_FORCE_DETACH:
> -       finalize = true;
> +       finalize = (kind == GOMP_MAP_FORCE_DETACH);
>         /* Fallthrough.  */
>
>       case GOMP_MAP_DETACH:
> @@ -1197,9 +1231,15 @@ goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum,
>           gomp_detach_pointer (acc_dev, aq, n, hostaddr, finalize, NULL);
>         }
>         break;
> +     case GOMP_MAP_STRUCT:
> +     case GOMP_MAP_POINTER:
> +       /* Ignore.  */
> +       break;
>       default:
> -       ;
> +       gomp_fatal (">>>> goacc_exit_data_internal UNHANDLED kind 0x%.2x",
> +                   kind);
>       }
> +      grp = group_last;
>      }
>
>    for (size_t i = 0; i < mapnum; ++i)
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90
> index 445cbabb8ca..7171affb9f0 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90
> @@ -24,12 +24,8 @@ program main
>    print *, "CheCKpOInT1"
>    ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
>    !$acc exit data delete(var%a) finalize
> -  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
> -  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
> -  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
> -  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
>    print *, "CheCKpOInT2"
> -  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
> +  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
>    if (acc_is_present(var%a)) stop 3
>    if (.not. acc_is_present(var)) stop 4
>
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90
> index 7b206ac2042..2aa46189e9a 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90
> @@ -6,4 +6,4 @@
>  #include "mdc-refcount-1-1-1.f90"
>
>  ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
> -! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" }
> +! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90
> index 8554534b2f2..9a10aa5a781 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90
> @@ -26,12 +26,8 @@ program main
>    print *, "CheCKpOInT1"
>    ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
>    !$acc exit data delete(var%a) finalize
> -  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
> -  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
> -  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
> -  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
>    print *, "CheCKpOInT2"
> -  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
> +  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
>    if (acc_is_present(var%a)) stop 3
>    if (.not. acc_is_present(var)) stop 4
>
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90
> index 8e696cc70e8..f506adf8e91 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90
> @@ -26,12 +26,8 @@ program main
>    print *, "CheCKpOInT1"
>    ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
>    !$acc exit data delete(var%a)
> -  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
> -  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
> -  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
> -  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
>    print *, "CheCKpOInT2"
> -  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
> +  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)"  }
>    if (acc_is_present(var%a)) stop 3
>    if (.not. acc_is_present(var)) stop 4
>
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90
> index 070a6f8e149..450d95d3686 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90
> @@ -27,12 +27,8 @@ program main
>    print *, "CheCKpOInT1"
>    ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
>    !$acc exit data delete(var%a) finalize
> -  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
> -  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
> -  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
> -  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
>    print *, "CheCKpOInT2"
> -  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
> +  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
>    if (acc_is_present(var%a)) stop 3
>    if (.not. acc_is_present(var)) stop 4
>
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90
> index 3c4bbda7f66..35efad4138a 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90
> @@ -27,11 +27,8 @@ program main
>    print *, "CheCKpOInT1"
>    ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
>    !$acc exit data delete(var%a)
> -  !TODO { dg-output "(\n|\r\n|\r)libgomp: attach count underflow(\n|\r\n|\r)$" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
> -  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
> -  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
>    print *, "CheCKpOInT2"
> -  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
> +  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
>    if (acc_is_present(var%a)) stop 3
>    if (.not. acc_is_present(var)) stop 4
>
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90
> index b22e411567f..816562fc055 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90
> @@ -26,12 +26,8 @@ program main
>    print *, "CheCKpOInT1"
>    ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
>    !$acc exit data detach(var%a) finalize
> -  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
> -  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
> -  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
> -  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
>    print *, "CheCKpOInT2"
> -  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
> +  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
>    !$acc exit data delete(var%a)
>    if (acc_is_present(var%a)) stop 3
>    if (.not. acc_is_present(var)) stop 4
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90
> index 476cd5c1bee..b98bfd74924 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90
> @@ -27,11 +27,8 @@ program main
>    print *, "CheCKpOInT1"
>    ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
>    !$acc exit data delete(var%a)
> -  !TODO { dg-output "(\n|\r\n|\r)libgomp: attach count underflow(\n|\r\n|\r)$" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
> -  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
> -  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
>    print *, "CheCKpOInT2"
> -  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
> +  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
>    if (acc_is_present(var%a)) stop 3
>    if (.not. acc_is_present(var)) stop 4
>
> --
> 2.23.0
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Julian Brown July 24, 2020, 10:53 p.m. UTC | #2
On Fri, 24 Jul 2020 16:18:34 +0200
Thomas Schwinge <thomas@codesourcery.com> wrote:

> Hi Julian!
> 
> On 2020-06-16T15:39:45-0700, Julian Brown <julian@codesourcery.com>
> wrote:
> > This patch fixes a set of XFAILs  
> 
> The overall goal of couse is not to resolve XFAILs, but to implement
> the expected behavior.  :-)

Eh, details :-).

> > in some recently-added patches by
> > skipping a detach operation on "no-op" exit data operations for
> > blocks with zero dynamic refcount.  
> 
> So this is one aspect of <https://gcc.gnu.org/PR95203> "OpenACC 2.6
> deep copy: attach/detach API routines: no-op behavior".

Not quite, I don't think -- that's about pointers (or pointed-to blocks)
that are not mapped on the target. With this patch, we have a detach
operation with a block with a zero dynamic refcount, but a non-zero
structured refcount -- i.e. it's still mapped. So I think the patch is
necessary, but not sufficient for the other cases you mention. 

> > This takes advantage of the ordering of
> > detach clauses with respect to associated data-movement clauses:
> > i.e., they are grouped together adjacently.  
> 
> I'm not convinced that it's sufficient to just special-case these
> cases. Instead, per the OpenACC "Data Clause Actions" etc., shouldn't
> basically all 'gomp_fatal's that we have on 'attach'/'detach' code
> paths turn into no-ops ("no action is taken")?
> 
> 
> And I'd then again like to bring forward my idea from another review:
> 
> | we may (rather easily?) add a flag variable (ICV;
> | initialized from an environment variable) to guard this checking
> | behavior?
> 
> Here: to *keep* the 'gomp_fatal's.
> 
> | I suppose we may now have a few libgomp testcases that
> | actually do [check things via expected 'gomp_fatal's],
> | which wouldn't work any longer [...].
> 
> Such testcases could then 'dg-set-target-env-var "GOMP_ATTACH_FATAL"
> "1"' (better name is desirable), and have one variant with and one
> variant without that enabled.
> 
> 
> Before you start re-working the patch, let's please first get
> agreement on what exactly we intend to achieve.

Hm, you are probably right about the no-op behaviour for attach
operations (but slightly ugh in terms of usability), but I don't think
that's really the problem the patch addresses.

As for the user-tweakable checking -- yeah maybe it could work, but I
don't think I'm going to have time to work on that at the moment. Sorry!

HTH,

Julian
diff mbox series

Patch

diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c
index 745cb132621..f852652c048 100644
--- a/libgomp/oacc-mem.c
+++ b/libgomp/oacc-mem.c
@@ -987,7 +987,9 @@  find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds)
     {
     case GOMP_MAP_TO_PSET:
       if (pos + 1 < mapnum
-	  && (kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH)
+	  && ((kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH
+	      || (kinds[pos + 1] & 0xff) == GOMP_MAP_DETACH
+	      || (kinds[pos + 1] & 0xff) == GOMP_MAP_FORCE_DETACH))
 	return pos + 1;
 
       while (pos + 1 < mapnum
@@ -1010,6 +1012,8 @@  find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds)
       break;
 
     case GOMP_MAP_ATTACH:
+    case GOMP_MAP_DETACH:
+    case GOMP_MAP_FORCE_DETACH:
       return pos;
 
     default:
@@ -1025,7 +1029,9 @@  find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds)
       /* We can have a single GOMP_MAP_ATTACH mapping after a to/from
 	 mapping.  */
       if (pos + 1 < mapnum
-	  && (kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH)
+	  && ((kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH
+	      || (kinds[pos + 1] & 0xff) == GOMP_MAP_DETACH
+	      || (kinds[pos + 1] & 0xff) == GOMP_MAP_FORCE_DETACH))
 	return pos + 1;
 
       /* We can have zero or more GOMP_MAP_POINTER mappings after a to/from
@@ -1168,15 +1174,43 @@  goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum,
 {
   gomp_mutex_lock (&acc_dev->lock);
 
-  /* Handle "detach" before copyback/deletion of mapped data.  */
-  for (size_t i = 0; i < mapnum; ++i)
+  /* Handle "detach" before copyback/deletion of mapped data.  If this isn't a
+     standalone "detach" clause, take care to skip the "detach" operation if
+     the dynamic refcount of the data to be detached is zero.  */
+  for (size_t grp = 0; grp < mapnum; grp++)
     {
-      unsigned char kind = kinds[i] & 0xff;
+      size_t i = grp, group_last = find_group_last (grp, mapnum, sizes, kinds);
+      unsigned char kind = kinds[grp] & 0xff;
       bool finalize = false;
+
       switch (kind)
 	{
+	case GOMP_MAP_TO_PSET:
+	case GOMP_MAP_TOFROM:
+	case GOMP_MAP_FROM:
+	case GOMP_MAP_FORCE_FROM:
+	case GOMP_MAP_RELEASE:
+	case GOMP_MAP_DELETE:
+	  {
+	    if (i + 1 >= mapnum)
+	      break;
+	    kind = kinds[i + 1] & 0xff;
+	    if (kind != GOMP_MAP_FORCE_DETACH && kind != GOMP_MAP_DETACH)
+	      break;
+	    splay_tree_key n = lookup_host (acc_dev, hostaddrs[i], sizes[i]);
+	    if (n == NULL)
+	      {
+		gomp_mutex_unlock (&acc_dev->lock);
+		gomp_fatal ("target data not mapped for detach operation");
+	      }
+	    i++;
+	    if (n->dynamic_refcount == 0)
+	      break;
+	  }
+	  /* Fallthrough.  */
+
 	case GOMP_MAP_FORCE_DETACH:
-	  finalize = true;
+	  finalize = (kind == GOMP_MAP_FORCE_DETACH);
 	  /* Fallthrough.  */
 
 	case GOMP_MAP_DETACH:
@@ -1197,9 +1231,15 @@  goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum,
 	    gomp_detach_pointer (acc_dev, aq, n, hostaddr, finalize, NULL);
 	  }
 	  break;
+	case GOMP_MAP_STRUCT:
+	case GOMP_MAP_POINTER:
+	  /* Ignore.  */
+	  break;
 	default:
-	  ;
+	  gomp_fatal (">>>> goacc_exit_data_internal UNHANDLED kind 0x%.2x",
+		      kind);
 	}
+      grp = group_last;
     }
 
   for (size_t i = 0; i < mapnum; ++i)
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90
index 445cbabb8ca..7171affb9f0 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90
@@ -24,12 +24,8 @@  program main
   print *, "CheCKpOInT1"
   ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
   !$acc exit data delete(var%a) finalize
-  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
-  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
-  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
-  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
   print *, "CheCKpOInT2"
-  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
+  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
   if (acc_is_present(var%a)) stop 3
   if (.not. acc_is_present(var)) stop 4
 
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90
index 7b206ac2042..2aa46189e9a 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90
@@ -6,4 +6,4 @@ 
 #include "mdc-refcount-1-1-1.f90"
 
 ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
-! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" }
+! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90
index 8554534b2f2..9a10aa5a781 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90
@@ -26,12 +26,8 @@  program main
   print *, "CheCKpOInT1"
   ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
   !$acc exit data delete(var%a) finalize
-  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
-  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
-  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
-  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
   print *, "CheCKpOInT2"
-  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
+  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
   if (acc_is_present(var%a)) stop 3
   if (.not. acc_is_present(var)) stop 4
 
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90
index 8e696cc70e8..f506adf8e91 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90
@@ -26,12 +26,8 @@  program main
   print *, "CheCKpOInT1"
   ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
   !$acc exit data delete(var%a)
-  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
-  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
-  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
-  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
   print *, "CheCKpOInT2"
-  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
+  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)"  }
   if (acc_is_present(var%a)) stop 3
   if (.not. acc_is_present(var)) stop 4
 
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90
index 070a6f8e149..450d95d3686 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90
@@ -27,12 +27,8 @@  program main
   print *, "CheCKpOInT1"
   ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
   !$acc exit data delete(var%a) finalize
-  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
-  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
-  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
-  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
   print *, "CheCKpOInT2"
-  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
+  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
   if (acc_is_present(var%a)) stop 3
   if (.not. acc_is_present(var)) stop 4
 
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90
index 3c4bbda7f66..35efad4138a 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90
@@ -27,11 +27,8 @@  program main
   print *, "CheCKpOInT1"
   ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
   !$acc exit data delete(var%a)
-  !TODO { dg-output "(\n|\r\n|\r)libgomp: attach count underflow(\n|\r\n|\r)$" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
-  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
-  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
   print *, "CheCKpOInT2"
-  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
+  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
   if (acc_is_present(var%a)) stop 3
   if (.not. acc_is_present(var)) stop 4
 
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90
index b22e411567f..816562fc055 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90
@@ -26,12 +26,8 @@  program main
   print *, "CheCKpOInT1"
   ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
   !$acc exit data detach(var%a) finalize
-  !TODO     goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed.
-  !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
-  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
-  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
   print *, "CheCKpOInT2"
-  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
+  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
   !$acc exit data delete(var%a)
   if (acc_is_present(var%a)) stop 3
   if (.not. acc_is_present(var)) stop 4
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90
index 476cd5c1bee..b98bfd74924 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90
@@ -27,11 +27,8 @@  program main
   print *, "CheCKpOInT1"
   ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" }
   !$acc exit data delete(var%a)
-  !TODO { dg-output "(\n|\r\n|\r)libgomp: attach count underflow(\n|\r\n|\r)$" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing).
-  !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all.
-  !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log.
   print *, "CheCKpOInT2"
-  ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } }
+  ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" }
   if (acc_is_present(var%a)) stop 3
   if (.not. acc_is_present(var)) stop 4