Silverfrost Forums

Welcome to our forums

Strange behaviour in common block initialisation?

27 Apr 2021 1:17 #27635

The following code

      PROGRAM TEST
      INTEGER*2 I2, I2C
      INTEGER*4 I4, I4C
      REAL*4 R4, R4C
      REAL*8 R8, R8C
      Common /COMTES/ R8C,R4C,I4C,I2C
#IF _WIN64
      write(*,*) '64 Bit exe'
#ELSE
      write(*,*) '32 Bit exe'
#ENDIF
      WRITE(*,*) 'I2: ', I2, I2C
      WRITE(*,*) 'I4: ', I4, I4C
      WRITE(*,*) 'R4: ', R4, R4C
      WRITE(*,*) 'R8: ', R8, R8C                 
      END

named test.for is compiled using both the 32 bit and the 64 bit Version of SALFORD ftn95 version 8.70.0.

The resulting executable produces output which consists of 2 columns, the first of which consists of 4 local variables I2, I4, R4 and R8, the second of which consists of 4 common block variables I2C, I4C, R4C and R8C. For the 32 bit version of the executables all variables are initialised to 0. For the 64 bit version of the executable the common block variables are not always initialised to 0. Unfortunately, we cannot reproduce this behaviour, we observed many cases where the common block variables are initialised correctly for the 64 bit version, as well. The mistaken initialisation (to a non zero value) occurs for all types of common variables (i.e. for I2C, I4C, R4C and R8C).

We compiled the 64 bit executable via

ftn95 test  /64 /ALL_WARNINGS/NON_STANDARD/SINGLE_THREADED/OLD_ARRAYS/ALT_KINDS/PERSIST/ZEROISE/UNLIMITED_ERRORS/FIXED_FORMAT/SAVE/NO_WARN73/WIDE_SOURCE /WINDOWS /include ..;..\..\subinc /CFPP /DEFINE CLEARWIN 1  /DEFINE SALFORD64 1     /debug /link

We do not have any explation for this behaviour, we thought all variable should be initialised to 0 because of ftn95 option /SAVE being set.

The version number of both clearwin64.dll and salflibc64.dll loaded by the executable are 23.1.18.7 .

Has anybody observed similar behviour?

We would appreciate any hint ...

Regards Dietmar

27 Apr 2021 8:22 #27642

Allocatable arrays initialized to zero, Paul claimed here. If this is standard then i will not bother zeroizing myself, in my case this takes a lot of time sometimes.

But as to the common blocks, the standard does not guarantee you zeroes initially, so you have to do that manually. /zeroize does not work with /64 anymore

28 Apr 2021 7:34 #27644

Thanks Dan,

but I thought ftn95 option /SAVE would make the common block variables static and hence automatically initialised to zero. And this seems to be true for the 32 bit version.

Regards, Dietmar

28 Apr 2021 8:51 #27645

Regarding unintialised COMMON data, for 32 bits you do appear to get zeros (with or without SAVE) but at the moment I don't know if this is by chance or by design.

For 64 bits you don't get zeros.

One solution is represented here...

      PROGRAM TEST
      INTEGER*2 I2C
      INTEGER*4 I4C
      REAL*4 R4C
      REAL*8 R8C
      COMMON /COMTES/ R8C,R4C,I4C,I2C
      DATA  R8C,R4C,I4C,I2C/4*0/
      PRINT*, R8C,R4C,I4C,I2C
      END

If there is more that one common block then it might be simpler to use BLOCK DATA.

Initialised COMMON data is packed into the executable and you can use a binary reader to see it after creating an executable using this sample...

      program test
      common /acomtes/i4a(1000)
      common /bcomtes/i4b(1000)
      data i4a/1000*-1/
      data i4b/1000*-2/
      print*,i4a(1000),i4b(1000)
      end

Another approach is to look at the assembler code produced by using /EXPLIST.

28 Apr 2021 10:41 #27647

Assuming variables are initialised to zero is not standard conforming and so not portable. I don't know why this approach would be used with new code. I really don't know what the following combination of options would mean ? '/NON_STANDARD/SINGLE_THREADED/OLD_ARRAYS/ALT_KINDS/PERSIST/ZEROISE' I don't think /NON_STANDARD is the same as not standard conforming ? It is a bit different to my /64 /ERROR_NUMBERS /IMPLICIT_NONE /INTL /LOGL, but this is not the point of your post.

28 Apr 2021 12:27 #27649

John

Just for information, /INTL and /LOGL are the defaults.

28 Apr 2021 1:28 #27653

Thanks for your infos, Paul, John,

however, I am confused now about what is a static variable.

ftn95 help for the /SAVE option says:

The following types of variables will automatically be static: Any variable that appears in a SAVE statement. ... Any variable that is initialised, e.g. INTEGER::I = 1 All other variables will be made static if the /SAVE option is used.

In another post (8.20 and /ZEROISE) Paul said:

In the following description, local variables and arrays that are given the SAVE attribute are called static variables.

and

FTN95 presets the value of all static variables to zero.

Now having read this post it is **still **unclear to me if a variable of a common block is static or not. My current opinion: for 32 bit it is static for 64 bit it is not.

John C,

I do not know if it is standard conforming if common block variables are initialised to zero or not. But assumed that Salford's 32 bit version of ftn95 initialises common block variables to zero then I would expect this to be the case for the 64 bit version, as well.

This problem arose from the port of a big 32 bit application to 64 bit and hence the origin of the problem is not related to new code.

Moreover if a compiler guarantees that special variables are initialised to zero (as e.g. is the case using static variables in C code) why should I not rely on that behaviour? I could argue that initialising them twice (by the compiler and explicitly in the code) would be redundant.

Concerning the compile options: some of them are 'historical' some necessary. However, I would not remove any of them for I do not know if this would result in additional diffculties 😉

Regards Dietmar

28 Apr 2021 2:06 #27654

Dietmar

I am not sure that it would help if I tried to explain what SAVE means in Fortran or for FTN95. The main point is that initialised COMMON data appears to be set to zero (possibly by design) for 32 bits but not for 64 bits.

If it turns out that the 32 bit behaviour is by design then there is certainly a case for us to see if we can provide the same behaviour for 64 bits. At the moment I don't know if this would be feasible or how long it would take to implement.

In the meantime you will probably want to explore ways to do the initialising in the code. In addition to my comments above, you could also consider using a local integer array (IARRAY) of suitable size which you EQUIVALENCE to the first item in a common block. You can then use the simple assignment statement 'IARRAY = 0' in order to preset all the data to zero.

29 Apr 2021 3:48 #27658

Dietmar,

Quoted from DietmarSiepmann Moreover if a compiler guarantees that special variables are initialised to zero (as e.g. is the case using static variables in C code) why should I not rely on that behaviour?

The Fortran Standard definitely does not guarantee this and I am not sure if FTN95 does either.

SAVE : static variables are allocated a fixed memory address and do not go out of scope. For large programs, it is helpful to differentiate between 'global static variables' which always exist and 'local dynamic variables' which are typically located on the stack and released when exiting the routine (going out of scope) Some load maps show where static variables are stored for each routine. The concept of dynamic variables (not static) is essential for recursive and multi-threaded approaches.

Initialised variables : your claims of initialised variables differ slightly from static variables. In standard Fortran, initialised variables (via data or declaration) imply SAVE. The programmer codes the initial values. Initialised variables are stored in the .exe and can make the .exe much larger.

ZERO initialisation : This is a slightly different case to initialisation. Having zeroised variables in 32-bit is a FTN95 extension. Having zeroised variables in 64-bit, if provided, would be a FTN95 extension which has the potential to increase the execution time when entering a routine, especially for large dynamic arrays. A related extension in FTN95 is that ALLOCATE variables are initialised to zero. I am not sure if this is both 32-bit and 64-bit. I never assume zeroised! There is an important difference in Fortran between variables in a routine that are SAVED and initialised vs variables that are initialised in an executed statement.

The Fortran Standard implies that a variable that is not explicitly initialised (either declaration or execution statement) does not have an initial value. It is incorrect to assume uninitialized variables are zero, which is a very common error, especially when moving from a compiler (like FTN95 /32) that provides this extension. While there could be an argument that default initialising to zero would eliminate many errors and make Fortran more robust, the standards committee have not chosen this approach. I also find not initialising variables to be an alarming approach that is not robust coding.

I did not learn these differences in my first course in FORTRAN !

I hope I have not made too many mistakes in this description !!

29 Apr 2021 8:24 #27660

Paul, John C,

thanks again for your informations.

The /SAVE option seems to be very complicated and to me it seems that one cannot rely on COMMON BLOCK VARIABLEs to be set to zero if /SAVE is specified for every Fortran compiler.

One of my intent was to express that it would be worthwhile that SALFORD's ftn95 compiler behaves in the same way for 32 bit and 64 bit wherever it is possible.

This would be a big help in the porting process from 32 bit to 64 bit 😃

Regards, Dietmar

29 Apr 2021 11:14 #27662

Understanding the difference between static or dynamic variables is essential for understanding Fortran 90+. It should not be complicated. If you require the use of /SAVE or /ZERO, then you are not writing standard conforming programs and they will be difficult for others to maintain.

Ways of making variables static are via declaration : INTEGER, SAVE :: I or when initialising : INTEGER :: I = 1 or : INTEGER I ; DATA I / 1 / You should understand the difference between the following

  subroutine a1 (res)
   integer :: res, ii = 1    ! ii is static
   ii = ii+1
   res = ii
  end subroutine a1

  subroutine a2 (res)
   integer :: res, ii    ! ii is dynamic
   ii = 1
   ii = ii+1
   res = ii
  end subroutine a2

  subroutine a3 (res)
   integer :: res, ii
   data ii / 1 /    ! ii is static
   ii = ii+1
   res = ii
  end subroutine a3

  subroutine a4 (res)
   integer :: res, ii        ! ii is dynamic
   ii = ii+1                   ! what is the value of ii ?
   res = ii
  end subroutine a4

If a variable, array or derived type are defined in a routine, they remain defined/allocated while they are in scope, either in the routine or a called routine. Typically local or automatic arrays are placed on the stack or ALLOCATE on the heap and remain there until you exit from the routine.

If variables are defined in COMMON or MODULE, they remain defined while the COMMON or MODULE remains in scope, which is typically for the duration of the program.

ALLOCATE local arrays by default remain defined until execution exits the routine or DEALLOCATE is used.

For large memory arrays, this can be important (even in 64-bit) as the performance can be impacted by unnecessary memory wastage.

If you go to multi-threading, as well as SAVE vs dynamic, there is also SHARED vs PRIVATE. The management of these differences is essential for correct outcomes, as well as manageing the initialising of these variables.

Having all variables as /SAVE and assuming /ZERO is both lazy and limits accress to the functionality that these differences provide.

It is worth better understanding these issues, write standard conforming Fortran and don't rely on compile options such as /SAVE or /ZERO

3 May 2021 9:44 #27679

Dietmar

A new version of SLINK64 is now available via the Support 'sticky' post. With this version, uninitialised common block data is preset to zero unless /UNDEF is used on the FTN95 command line.

3 May 2021 11:50 #27681

Paul,

thanks, with this new version the 64 bit vesion of test.exe presets common block data to zero analogously to the 32 bit version 😃

Regards, Dietmar

3 May 2021 3:15 #27682

Paul,

having competeley upgraded to version 8.72 (debuggers, dlls, ftn95, clearwin+, slink64) via the support 'sticky' post I ran into problems with sdbg64 when debugging test.exe. Test.exe has been created via comand

ftn95 test.for /debug /cfpp /link /64

Starting the test.exe without debugger works as expected. Executing command sdbg64 test.EXE comes up with an Error dialog displaying lines

Assert failure: expr = ciu->address File = StackFrame.cpp Line= 385

while the command window in which sdbg64.exe was started displays line CreateFileMapping returned 57CreateFileMapping returned 57

Setting a check mark to executabele sdbg64.exe within the resource manager shows the lines following for the associated modules:

Module name - Version clearwin64.dll - 23.5.3.6 salflibc64.dll - 23.5.3.6 sdbg64.exe - 8.70.0.0

The third line confuses me because I would expect sdbgdll.dll instead of sdbg64.exe. However sdbgdll.dll does not occur in the resource manager listing of associated modules. The sdbgdll.dll of the ftn95 installation is dated as follows:

08.11.2020 17:30 522.752 sdbgdll.dll

Regards, Dietmar

4 May 2021 8:28 #27685

Dietmar

Thank you for the feedback.

At the moment I can't explain this failure. It may be necessary for us to rebuild SDBG64.

mecej4 has reported a failure with the new SLINK64 so we should aim to fix that first and then see if a rebuild of SDBG64 is needed.

10 May 2021 8:57 #27724

Dietmar

At number of changes have now been made to FTN95, SDBG64 and salflibc64.dll which relate to this issue. A new version of SDBG64 is already available and new versions of FTN95 and salflibc64.dll will be provided shortly (hopefully later today).

11 May 2021 10:46 #27734

Paul,

I have downloaded all the new stuff from the Support sticky web site including clrwin.ins.

Now sdbg64 works for test.exe as expected 😃

Thanks and regards, Dietmar

19 May 2021 10:33 #27803

Paul,

I'm afraid I need to correct my last post with respect to the following:

if I start the debugging session via command

sdbg64 test.EXE

and then select

           Help
           About Debugger ...

in the menu bar of sdbg64.exe, then sdbg64.exe does not work any more, sdbg64 does not take any input and I could stop it only via the task manager or by typing CTRL-C in the command window from which sdbg64 was started.

Selecting sdbg64.exe within Windows Resource Manager displays version info

         Modulename --- Version
         clearwin64.dll --- 23.5.10.13
         salflibc64.dll --- 23.5.20.23
         sdb64.exe --- 8.72.0.0

The third entry sdb64.exe confuses me, I would expect dll sdbgdll.dll somewhere in the complete output of the resource manager, but I could not find it. Without debugger executable test.exe worked as expcted (as I described above).

The same happens, If I use the new dlls from newDLLs85.zip

By the way ... does anyone know a way how to make Windows resource manager display its output to a command window?

Regards, Dietmar

19 May 2021 11:02 #27805

Dietmar

It works correctly for me so I think that we can expect this to be resolved in a full release.

19 May 2021 12:14 #27807

Paul,

the menu selection described works if the sdbg64 main window is **not **maximized. In this case a window with titlebar 'Silverfrost Debugger' is displayed showing version info and copyright information. sdbg64 takes input and works as expected. However, if I maximize sdbg64's main window and then select --> Help --> About Debugger in the menu bar, then the 'Silverfrost Debugger' window does not occur at all.

Doing the same for the 32 bit version of test.exe I see the 'Silverfrost Debugger' window as well if the main window of sdbg is maximized!!! And the module names displayed by the resource manager in the first three lines are

salflibc.dll (with version info 23.5.10.13), sdbg.exe (with no version info) and sdbgdll.dll (with no version info).

I am **very **surprised that for the 32 bit case I see sdbgdll.dll within the resource manager, but for the 64 bit case I do **not **(unless my eyes did not notice them - that's why my question concerning the output of the resource manager 😉

Regards, Dietmar

Please login to reply.