public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
From: Harald Anlauf <anlauf@gmx.de>
To: Paul Richard Thomas <paul.richard.thomas@gmail.com>
Cc: Alessandro Fanfarillo <alessandro.fanfarillo@gmail.com>,
	Andrew Benson <abenson@carnegiescience.edu>,
	"fortran@gcc.gnu.org" <fortran@gcc.gnu.org>
Subject: Re: [Patch, fortran] PR37336 (Finalization) - [F03] Finish derived-type finalization
Date: Fri, 11 Feb 2022 22:08:05 +0100	[thread overview]
Message-ID: <7ab973cd-f62e-28be-36e8-4e44252a4a38@gmx.de> (raw)
In-Reply-To: <CAGkQGiJQOFw366Ueh1eepz_XztwOUEw7Ws2GBJc27=OkHb110Q@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5089 bytes --]

Hi Paul,

Am 11.02.22 um 10:08 schrieb Paul Richard Thomas via Fortran:
> Your "stupid questions" are not at all stupid. The finalization of
> 'variable' that occurs in your testcase demonstrates that the finalization
> with my patch is occurring at the wrong time. I now see that NAG is correct
> on this.
>
> Please press on with the questions!

Jerry's suggestion to add lots of prints turned out to be really
enlightening with regard to observable behavior.  I rewrote the
testcase again and placed the interesting stuff into a subroutine.
This way one can distinguish what actually happens during program
start, entering and leaving a subroutine.

I encountered the least surprises (= none) with NAG 7.0 here.
For reference this is the output:

  At start of program : 0

  Enter sub           : 0
  After 1st allocation: 0
  After 2nd allocation: 0
  Checking MyType% ind: 21
  Checking MyType2%ind: 22
  Deallocate MyType   : 0
  # Leave desctructor1: 1 21
  * MyType deallocated: 1
  (kept MyType2 for automatic deallocation on return from sub)
  Leave sub           : 1
  # Leave desctructor1: 2 22

  After sub           : 2

To make it short: the destructor is called only when deallocation
occurs, either explicitly or automatically.


Intel 2021.5.0:

  At start of program :           0

  Enter sub           :           0
  # Leave desctructor1:           1           0
  After 1st allocation:           1
  # Leave desctructor1:           2           0
  After 2nd allocation:           2
  Checking MyType% ind:          21
  Checking MyType2%ind:          22
  Deallocate MyType   :           2
  # Leave desctructor1:           3          21
  * MyType deallocated:           3
  (kept MyType2 for automatic deallocation on return from sub)
  Leave sub           :           3
  # Leave desctructor1:           4          21
  # Leave desctructor1:           5          22
  # Leave desctructor1:           6          22

  After sub           :           6

So after entering the subroutine, the destructor is called twice,
but for unknown reasons element ind, which I had expected to be
either default-initialized to -1, or explicitly to 21 or 22, is 0.
The places where this happens seem to be the assignments of
MyType and MyType2.

Furthermore, variable MyType is finalized on return from sub,
although it is already deallocated, and MyType2 appears to
get finalized twice automatically.

I have no idea how this can get justified...


Crayftn 12.0.2: in order to make the output easier to understand,
I chose to reset final_count twice.  This will become clear soon.

  # Leave desctructor1: 1,  20

  At start of program : 1
  +++ Resetting final_count for Cray Fortran : Version 12.0.2

  # Leave desctructor1: 1,  21
  # Leave desctructor1: 2,  22
  Enter sub           : 2
  +++ Resetting final_count for Cray Fortran : Version 12.0.2
  After 1st allocation: 0
  After 2nd allocation: 0
  Checking MyType% ind: -21
  Checking MyType2%ind: 22
  Deallocate MyType   : 0
  # Leave desctructor1: 1,  -21
  * MyType deallocated: 1
  (kept MyType2 for automatic deallocation on return from sub)
  Leave sub           : 1
  # Leave desctructor1: 2,  22

  After sub           : 2

So it appears that Cray is calling the destructor for each declaration
where a constructor is involved, or the like.  Even if this is a
parameter declaration, like in the main.  Resetting the counter for
the first time.

On entering sub, I see now two finalizations before the first print.
Resetting the counter for the second time.

But then the assignments do not invoke finalization, where Intel did.
So this part appears more like NAG, but...

... something is strange here: component ind is wrong after the
first assignment.  Looks clearly like a really bad bug.

Explicit and automatic deallocation seems fine.


Nvidia 22.2:

  At start of program :            0

  Enter sub           :            0
  After 1st allocation:            0
  After 2nd allocation:            0
  Checking MyType% ind:           21
  Checking MyType2%ind:           22
  Deallocate MyType   :            0
  # Leave desctructor1:            1           21
  * MyType deallocated:            1
  (kept MyType2 for automatic deallocation on return from sub)
  Leave sub           :            1
  # Leave desctructor1:            2   1590094384
  # Leave desctructor1:            3           22

  After sub           :            3

OK, that is really odd.  Although valgrind does not report
invalid accesses, there is something really fishy here.
I have not investigated further.  Nvidia is out for now.


One of the lessons learned is that it might be hard to write a
portable testcase that works for all compilers that rightfully(?)
can claim to implement finalization correctly...  And I have only
scratched the surface so far.

Paul: do you think you can enhance your much more comprehensive
testcase to ease debugging further?

Cheers,
Harald

[-- Attachment #2: finalize_38b.f90 --]
[-- Type: text/x-fortran, Size: 1965 bytes --]

module testmode
  implicit none

  type :: simple
     integer :: ind = -1
  contains
    final :: destructor1
  end type simple

  integer :: final_count = 0

contains

  subroutine destructor1(self)
    type(simple), intent(inout) :: self
    final_count = final_count + 1
    print *, "# Leave desctructor1:", final_count, self% ind
    self% ind = - self% ind
  end subroutine destructor1

end module testmode

program test_final
  use, intrinsic :: iso_fortran_env
  use testmode
  implicit none
  type(simple), parameter :: ThyType_param = simple(20)
  character(80) :: compiler
  compiler = compiler_version ()
  print *
  print *, "At start of program :", final_count
  call reset ()
  print *
  call sub ()
  print *
  print *, "After sub           :", final_count
contains
  subroutine sub ()
    type(simple), parameter   :: ThyType   = simple(21)
    type(simple)              :: ThyType2  = simple(22)
    type(simple), allocatable :: MyType, MyType2

    print *, "Enter sub           :", final_count
    call reset ()

    MyType = ThyType
    print *, "After 1st allocation:", final_count

    MyType2 = ThyType2
    print *, "After 2nd allocation:", final_count

    print *, "Checking MyType% ind:", MyType% ind
    print *, "Checking MyType2%ind:", MyType2% ind
    if (.not. allocated (MyType )) print *, "MyType?"
    if (.not. allocated (MyType2)) print *, "MyType2?"

    print *, "Deallocate MyType   :", final_count
    deallocate (MyType)
    print *, "* MyType deallocated:", final_count

    if (allocated (MyType2)) &
    print *, "(kept MyType2 for automatic deallocation on return from sub)"
    print *, "Leave sub           :", final_count

  end subroutine sub
  !
  subroutine reset ()
    if (final_count == 0) return
    if (compiler(1:4) == "Cray") then
       print *, "+++ Resetting final_count for ", trim (compiler)
       final_count = 0 ! reset for crayftn 12.0.2
    end if
  end subroutine reset
end program test_final

WARNING: multiple messages have this Message-ID
From: Harald Anlauf <anlauf@gmx.de>
To: fortran@gcc.gnu.org
Cc: Alessandro Fanfarillo <alessandro.fanfarillo@gmail.com>,
	Andrew Benson <abenson@carnegiescience.edu>,
	"fortran@gcc.gnu.org" <fortran@gcc.gnu.org>
Subject: Re: [Patch, fortran] PR37336 (Finalization) - [F03] Finish derived-type finalization
Date: Fri, 11 Feb 2022 22:08:05 +0100	[thread overview]
Message-ID: <7ab973cd-f62e-28be-36e8-4e44252a4a38@gmx.de> (raw)
Message-ID: <20220211210805.IDwYmDfKARHKRtA2YRMTOszD8ZRz3vkzg2d723S-eDk@z> (raw)
In-Reply-To: <CAGkQGiJQOFw366Ueh1eepz_XztwOUEw7Ws2GBJc27=OkHb110Q@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 4939 bytes --]

Hi Paul,

Am 11.02.22 um 10:08 schrieb Paul Richard Thomas via Fortran:
> Your "stupid questions" are not at all stupid. The finalization of
> 'variable' that occurs in your testcase demonstrates that the finalization
> with my patch is occurring at the wrong time. I now see that NAG is correct
> on this.
> 
> Please press on with the questions!

Jerry's suggestion to add lots of prints turned out to be really
enlightening with regard to observable behavior.  I rewrote the
testcase again and placed the interesting stuff into a subroutine.
This way one can distinguish what actually happens during program
start, entering and leaving a subroutine.

I encountered the least surprises (= none) with NAG 7.0 here.
For reference this is the output:

  At start of program : 0

  Enter sub           : 0
  After 1st allocation: 0
  After 2nd allocation: 0
  Checking MyType% ind: 21
  Checking MyType2%ind: 22
  Deallocate MyType   : 0
  # Leave desctructor1: 1 21
  * MyType deallocated: 1
  (kept MyType2 for automatic deallocation on return from sub)
  Leave sub           : 1
  # Leave desctructor1: 2 22

  After sub           : 2

To make it short: the destructor is called only when deallocation
occurs, either explicitly or automatically.


Intel 2021.5.0:

  At start of program :           0

  Enter sub           :           0
  # Leave desctructor1:           1           0
  After 1st allocation:           1
  # Leave desctructor1:           2           0
  After 2nd allocation:           2
  Checking MyType% ind:          21
  Checking MyType2%ind:          22
  Deallocate MyType   :           2
  # Leave desctructor1:           3          21
  * MyType deallocated:           3
  (kept MyType2 for automatic deallocation on return from sub)
  Leave sub           :           3
  # Leave desctructor1:           4          21
  # Leave desctructor1:           5          22
  # Leave desctructor1:           6          22

  After sub           :           6

So after entering the subroutine, the destructor is called twice,
but for unknown reasons element ind, which I had expected to be
either default-initialized to -1, or explicitly to 21 or 22, is 0.
The places where this happens seem to be the assignments of
MyType and MyType2.

Furthermore, variable MyType is finalized on return from sub,
although it is already deallocated, and MyType2 appears to
get finalized twice automatically.

I have no idea how this can get justified...


Crayftn 12.0.2: in order to make the output easier to understand,
I chose to reset final_count twice.  This will become clear soon.

  # Leave desctructor1: 1,  20

  At start of program : 1
  +++ Resetting final_count for Cray Fortran : Version 12.0.2

  # Leave desctructor1: 1,  21
  # Leave desctructor1: 2,  22
  Enter sub           : 2
  +++ Resetting final_count for Cray Fortran : Version 12.0.2
  After 1st allocation: 0
  After 2nd allocation: 0
  Checking MyType% ind: -21
  Checking MyType2%ind: 22
  Deallocate MyType   : 0
  # Leave desctructor1: 1,  -21
  * MyType deallocated: 1
  (kept MyType2 for automatic deallocation on return from sub)
  Leave sub           : 1
  # Leave desctructor1: 2,  22

  After sub           : 2

So it appears that Cray is calling the destructor for each declaration
where a constructor is involved, or the like.  Even if this is a
parameter declaration, like in the main.  Resetting the counter for
the first time.

On entering sub, I see now two finalizations before the first print.
Resetting the counter for the second time.

But then the assignments do not invoke finalization, where Intel did.
So this part appears more like NAG, but...

... something is strange here: component ind is wrong after the
first assignment.  Looks clearly like a really bad bug.

Explicit and automatic deallocation seems fine.


Nvidia 22.2:

  At start of program :            0

  Enter sub           :            0
  After 1st allocation:            0
  After 2nd allocation:            0
  Checking MyType% ind:           21
  Checking MyType2%ind:           22
  Deallocate MyType   :            0
  # Leave desctructor1:            1           21
  * MyType deallocated:            1
  (kept MyType2 for automatic deallocation on return from sub)
  Leave sub           :            1
  # Leave desctructor1:            2   1590094384
  # Leave desctructor1:            3           22

  After sub           :            3

OK, that is really odd.  Although valgrind does not report
invalid accesses, there is something really fishy here.
I have not investigated further.  Nvidia is out for now.


One of the lessons learned is that it might be hard to write a
portable testcase that works for all compilers that rightfully(?)
can claim to implement finalization correctly...  And I have only
scratched the surface so far.

Paul: do you think you can enhance your much more comprehensive
testcase to ease debugging further?

Cheers,
Harald

[-- Attachment #2: finalize_38b.f90 --]
[-- Type: text/x-fortran, Size: 1965 bytes --]

module testmode
  implicit none

  type :: simple
     integer :: ind = -1
  contains
    final :: destructor1
  end type simple

  integer :: final_count = 0

contains

  subroutine destructor1(self)
    type(simple), intent(inout) :: self
    final_count = final_count + 1
    print *, "# Leave desctructor1:", final_count, self% ind
    self% ind = - self% ind
  end subroutine destructor1

end module testmode

program test_final
  use, intrinsic :: iso_fortran_env
  use testmode
  implicit none
  type(simple), parameter :: ThyType_param = simple(20)
  character(80) :: compiler
  compiler = compiler_version ()
  print *
  print *, "At start of program :", final_count
  call reset ()
  print *
  call sub ()
  print *
  print *, "After sub           :", final_count
contains
  subroutine sub ()
    type(simple), parameter   :: ThyType   = simple(21)
    type(simple)              :: ThyType2  = simple(22)
    type(simple), allocatable :: MyType, MyType2

    print *, "Enter sub           :", final_count
    call reset ()

    MyType = ThyType
    print *, "After 1st allocation:", final_count

    MyType2 = ThyType2
    print *, "After 2nd allocation:", final_count

    print *, "Checking MyType% ind:", MyType% ind
    print *, "Checking MyType2%ind:", MyType2% ind
    if (.not. allocated (MyType )) print *, "MyType?"
    if (.not. allocated (MyType2)) print *, "MyType2?"

    print *, "Deallocate MyType   :", final_count
    deallocate (MyType)
    print *, "* MyType deallocated:", final_count

    if (allocated (MyType2)) &
    print *, "(kept MyType2 for automatic deallocation on return from sub)"
    print *, "Leave sub           :", final_count

  end subroutine sub
  !
  subroutine reset ()
    if (final_count == 0) return
    if (compiler(1:4) == "Cray") then
       print *, "+++ Resetting final_count for ", trim (compiler)
       final_count = 0 ! reset for crayftn 12.0.2
    end if
  end subroutine reset
end program test_final

  reply	other threads:[~2022-02-11 21:08 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-03 17:14 Paul Richard Thomas
2022-02-07 21:09 ` Harald Anlauf
2022-02-07 21:09   ` Harald Anlauf
2022-02-08 11:22   ` Paul Richard Thomas
2022-02-08 18:29     ` Harald Anlauf
2022-02-08 18:29       ` Harald Anlauf
2022-02-09  2:35       ` Jerry D
2022-02-10 12:25       ` Paul Richard Thomas
2022-02-10 19:49         ` Harald Anlauf
2022-02-10 19:49           ` Harald Anlauf
2022-02-11  2:15           ` Jerry D
2022-02-11  9:08           ` Paul Richard Thomas
2022-02-11 21:08             ` Harald Anlauf [this message]
2022-02-11 21:08               ` Harald Anlauf
2022-02-11 21:59               ` Paul Richard Thomas
2022-02-16 18:49                 ` Paul Richard Thomas
2022-02-17 20:55                   ` Harald Anlauf
2022-02-17 20:55                     ` Harald Anlauf
2022-02-17 21:23                   ` Thomas Koenig
2022-02-18 18:06                     ` Paul Richard Thomas
2023-01-02 13:15                       ` Paul Richard Thomas
     [not found]                         ` <trinity-a4069639-4079-4f60-b928-1fec82384b1e-1672953005015@3c-app-gmx-bap48>
2023-01-05 21:14                           ` Fw: " Harald Anlauf
2023-01-06  3:08                             ` Jerry D
2023-01-06  8:33                               ` Harald Anlauf
2023-01-07 10:57                                 ` Paul Richard Thomas
2023-01-07 15:28                                   ` Thomas Koenig
2023-01-07 18:35                                     ` Paul Richard Thomas
2023-01-08 12:03                                       ` Thomas Koenig
2023-01-08 13:42                                         ` Paul Richard Thomas
2023-01-09 20:42                                   ` Aw: " Harald Anlauf
2023-01-11 20:56                                     ` Harald Anlauf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7ab973cd-f62e-28be-36e8-4e44252a4a38@gmx.de \
    --to=anlauf@gmx.de \
    --cc=abenson@carnegiescience.edu \
    --cc=alessandro.fanfarillo@gmail.com \
    --cc=fortran@gcc.gnu.org \
    --cc=paul.richard.thomas@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).