Variable strangely takes the value zero after the call of a subroutine - fortran

I have been facing some issues trying to convert a code previously compiled with compaq visual fortran 6.6 to gfortran.
Here is a specific problem I have met with gfortran :
There is a variable called "et" which takes the value 3E+10. Then the program calls a subroutine. "et" doesn't appear in the subroutine, but after coming back to the main program it has now the value 0.
When compliling with compaq visual fortran I didn't have this problem.
The code I am working on is a huge scientific program, so I put below only a small part of it :
c
c calculate load/unload modulus
c
500 t=(s1-s3)/2.
aa=1.00
if(iconeps.ne.1)bb=1.00
if(smean.lt.ap1) smean=ap1
if(xn.gt.0.000001) aa=(smean/atmp)**xn
if(iconeps.eq.1)go to 220
if(xm.gt.0.000001) bb=(smean/atmp)**xm
220 if(t.ge.0.99*sm1) go to 600
et=xku*aa*atmp+tt*tm1
if(iconeps.ne.1)bt=xkb*atmp*bb
go to 900
600 et=(xkl*aa*atmp+tt*tm1)*(1.0-rf*sr)**2
if(iconeps.ne.1)bt=xkb*atmp*bb
900 continue
btmax=17.0*et
btmin=0.33*et
if(iconeps.ne.1)then
tbt=(alf1+alf3*dtt)*dtt*(1.+vide)*tm2
btf=bt+tbt
bt=btf
endif
if(bt.lt.btmin) bt=btmin
if(bt.gt.btmax) bt=btmax
if(iconeps.eq.1)go to 1100
1000 continue
1050 if(mt.eq.mtyp4c)goto 1100
s=0.0
t=0.0
call shap4n(s,t,f,pfs,pft) ! Modification by NHV
call thick4n(s,t,xe,ye,thick)
call bmat4n(xe,ye,f,pfs,pft,b,detj,thick)
c calculate incremental strains
do 1300 i=1,4
temp=0.0
do 1200 j=1,8
1200 temp=temp+b(i,j)*disp(j)
1300 depi(i)=temp
epsv=0.0
do 1400 i=1,2
1400 epsv=epsv+depi(i)
epsv=epsv+depi(4)
ev=vide-(1.+vide)*epsv
if(ev.lt.0.0)ev=vide*.01
1100 continue
call perm(permws,xkw,coef,rw,tvisc,ev,vide,tt,pp)
: "et" keeps the good value until just before calling the subroutine "perm". Just after this subroutine it takes the value zero.
"et" isn't in any common block
This piece of code is part of a subroutine called by several different subroutines. What is even more strange is that when it is called in other parts of the code I doesn't have this problem ("et" keeps its value)
So if someone has ever met this kind of problem or have any idea about it I will be very gratefull

Perhaps you have a memory access error, such as an array bounds violation, or a mismatch between actual and dummy arguments. Are the interfaces of the subroutines explicit, such as being "used" from a module? Also try turning on compiler debugging options ... obviously subscript checking, but others might catch something. An extensive set for gfortran 4.5 or 4.6 is:
-O2 -fimplicit-none -Wall -Wline-truncation -Wcharacter-truncation -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -fwhole-file -fcheck=all -std=f2008 -pedantic -fbacktrace
Subscript checking is included in fcheck=all

I had this problem. In my main program, I was using double precision but the numbers I calculated with in my subroutine were single precision. After I changed them to double it fixed the problem and I got actual values instead of 0.

Related

Reading real*8 variable with value 0 with real*4 results a large number in fortran without warning

Reading real*4 variable with value 0 with real*8 results a large number, sometimes without warning.
I'm not good at Fortran. I was just running a Fortran code I got from someone else, and it made a segmentation fault. While I was debugging it, I found that one of the subroutines is reading a variable with value 0 defined with real*8 as real*4 results a large value.
I tried to reproduce it with simple code, but compiler showed a warning for the argument mismatch. I had to nest codes to reproduce the suppressed warning in simple code, but I'm not sure what's the exact condition for suppressed warning.
Actually, for some reason, I'm suspecting it may be the problem of my compiler, as the code (not the example code, original code) ran fine on the PC of the person who gave me the code.
file hello.f:
implicit none
call sdo()
END
file test.f:
subroutine sdo()
implicit none
real*4 dsecs
dsecs=0
write(0,*) dsecs
call sd(dsecs)
return
end
file test2.f:
subroutine sd(dsecs)
implicit none
real*8 dsecs
write(0,*) dsecs
return
end
compilation and execution:
$ gfortran -o hello hello.f test.f test2.f
$ ./hello
Expected result:
0. 00000000
0. 0000000000000000
Actual results:
0. 00000000
-5.2153889789423361E+223
It is not the problem of the compiler. It is the problem of the code. Your code did issue a warning for me that you were doing something nefarious, as it should. The subroutine that thinks dsecs is 4 bytes long sent 4 bytes. The subroutine that thinks dsecs is 8 bytes long looked at 8 bytes. What's in the other 4 bytes? Who knows. How does it look like when the two get mixed together? Probably not what you want. It's like accidentally getting served a scoopful of half icecream and half garbage: unlikely to taste the way you thought.
This is one of those problems that are very simply solved with that classic joke: "Doctor, doctor, it hurts when I do this!" - "Then... don't do that."
EDIT: Sorry, I cheated. I didn't compile them as separate programs. When I do, I don't get warnings. This is also normal - at compilation step, you didn't specify how foreign subroutines look so it couldn't complain, and at linking step compiler doesn't check any more.

Why xlf and ifort take differently on Array Bounds Read?

I'm trying to port a code from ifort compiler to ibm xlf compiler. It works well under ifort on redhat but give results contain "NaNQ" under xlf on AIX system. It turns out that there is a array bounds reading in the code cost this problem, here is a simplified example:
program main
implicit none
real(8)::a(1,0:10)=0.D0
print *, a(1,-1)
end program main
Using both compiler I can successfully compile it, without any mistake or warning.
On ifort I get result:
0.000000000000000E+000
But on xlf, I get:
0.247032822920623272E-322
However, if I read more beyond the boundary, the xlf won't compile but ifort compile successfully.
program main
implicit none
real(8)::a(1,0:10)=0.D0
print *, a(1,-3:-1)
end program main
On ifort I get:
0.000000000000000E+000 0.000000000000000E+000 0.000000000000000E+000
On xlf it won't compile:
"1.f90", line 5.9: 1516-023 (S) Subscript is out of bounds.
** main === End of Compilation 1 ===
1501-511 Compilation failed for file 1.f90.
Why the ifort and xlf take differently on this cross boundary read? Is there any way to make the compiler to check it strictly and prevent cross boundary read to happen? After all, it took me a long time to catch this bug in our code, since our group have been using this code for more than 15 years without any problems on ifort. Thanks.
Most Fortran compilers have options to check for array bounds errors at runtime. In these examples with constant indices the error can be found at compile time, which some compilers but not others will do without using non-default options. With ifort use -check bounds to request array bounds checking. You can get additional checking with -check all. These options are generally not the default because there is a runtime cost. But the cost of getting a wrong answer can be much higher!! I have found the runtime cost to frequently be surprisingly low and recommend using runtime checks during code development and even in production if the runtime cost is acceptable.

Program crash for array copy with ifort

This program crashes with Illegal instruction: 4 on MacOSX Lion and ifort (IFORT) 12.1.0 20111011
program foo
real, pointer :: a(:,:), b(:,:)
allocate(a(5400, 5400))
allocate(b(5400, 3600))
a=1.0
b(:, 1:3600) = a(:, 1:3600)
print *, a
print *, b
deallocate(a)
deallocate(b)
end program
The same program works with gfortran. I don't see any problem. Any ideas ? Unrolling the copy and performing the explicit loop over the columns works in both compilers.
Note that with allocatable instead of pointer I have no problems.
The behavior is the same if the statement is either inside a module or not.
I confirm the same behavior on ifort (IFORT) 12.1.3 20120130.
Apparently, no problem occurs with Linux and ifort 12.1.5
I tried to increase the stack size with the following linking options
ifort -Wl,-stack_size,0x40000000,-stack_addr,0xf0000000 test.f90
but I still get the same error. Increasing ulimit -s to hard same problem.
Edit 2: I did some more debugging and apparently the problem happens when the array splicing operation
b(:, 1:3600) = a(:, 1:3600)
involves a value suspiciously close to 16 M of data.
I am comparing the opcodes produced, but if there is a way to see an intermediate code form that is more communicative, I'd gladly appreciate it.
Your program is correct (though I would prefer allocatable to pointer if you do not need to be able to repoint it). The problem is that ifort by default places all array temporaries on the stack, no matter how large they are. And it seems to need an array temporary for the copy operation you are doing here. To work around ifort's stupid default behavior, always use the -heap-arrays flag when compiling. I.e.
ifort -o test test.f90 -heap-arrays 1600
The number behind -heap-arrays is the threshold where it should begin using the heap. For sizes below this, the stack is used. I chose a pretty low number here - you can probably safely use higher ones. In theory stack arrays are faster, but the difference is usually totally negligible. I wish intel would fix this behavior. Every other compiler has sensible defaults for this setting.
Use "allocatable" instead of "pointer".
real, allocatable :: a(:,:), b(:,:)
Assigning a floating point number to a pointer looks dubious to me.

Puzzling performance difference between ifort and gfortran

Recently, I read a post on Stack Overflow about finding integers that are perfect squares. As I wanted to play with this, I wrote the following small program:
PROGRAM PERFECT_SQUARE
IMPLICIT NONE
INTEGER*8 :: N, M, NTOT
LOGICAL :: IS_SQUARE
N=Z'D0B03602181'
WRITE(*,*) IS_SQUARE(N)
NTOT=0
DO N=1,1000000000
IF (IS_SQUARE(N)) THEN
NTOT=NTOT+1
END IF
END DO
WRITE(*,*) NTOT ! should find 31622 squares
END PROGRAM
LOGICAL FUNCTION IS_SQUARE(N)
IMPLICIT NONE
INTEGER*8 :: N, M
! check if negative
IF (N.LT.0) THEN
IS_SQUARE=.FALSE.
RETURN
END IF
! check if ending 4 bits belong to (0,1,4,9)
M=IAND(N,15)
IF (.NOT.(M.EQ.0 .OR. M.EQ.1 .OR. M.EQ.4 .OR. M.EQ.9)) THEN
IS_SQUARE=.FALSE.
RETURN
END IF
! try to find the nearest integer to sqrt(n)
M=DINT(SQRT(DBLE(N)))
IF (M**2.NE.N) THEN
IS_SQUARE=.FALSE.
RETURN
END IF
IS_SQUARE=.TRUE.
RETURN
END FUNCTION
When compiling with gfortran -O2, running time is 4.437 seconds, with -O3 it is 2.657 seconds. Then I thought that compiling with ifort -O2 could be faster since it might have a faster SQRT function, but it turned out running time was now 9.026 seconds, and with ifort -O3 the same. I tried to analyze it using Valgrind, and the Intel compiled program indeed uses many more instructions.
My question is why? Is there a way to find out where exactly the difference comes from?
EDITS:
gfortran version 4.6.2 and ifort version 12.0.2
times are obtained from running time ./a.out and is the real/user time (sys was always almost 0)
this is on Linux x86_64, both gfortran and ifort are 64-bit builds
ifort inlines everything, gfortran only at -O3, but the latter assembly code is simpler than that of ifort, which uses xmm registers a lot
fixed line of code, added NTOT=0 before loop, should fix issue with other gfortran versions
When the complex IF statement is removed, gfortran takes about 4 times as much time (10-11 seconds). This is to be expected since the statement approximately throws out about 75% of the numbers, avoiding to do the SQRT on them. On the other hand, ifort only uses slightly more time. My guess is that something goes wrong when ifort tries to optimize the IF statement.
EDIT2:
I tried with ifort version 12.1.2.273 it's much faster, so looks like they fixed that.
What compiler versions are you using?
Interestingly, it looks like a case where there is a performance regression from 11.1 to 12.0 -- e.g. for me, 11.1 (ifort -fast square.f90) takes 3.96s, and 12.0 (same options) took 13.3s.
gfortran (4.6.1) (-O3) is still faster (3.35s).
I have seen this kind of a regression before, although not quite as dramatic.
BTW, replacing the if statement with
is_square = any(m == [0, 1, 4, 9])
if(.not. is_square) return
makes it run twice as fast with ifort 12.0, but slower in gfortran and ifort 11.1.
It looks like part of the problem is that 12.0 is overly aggressive in trying to vectorize things: adding
!DEC$ NOVECTOR
right before the DO loop (without changing anything else in the code) cuts the run time down to 4.0 sec.
Also, as a side benefit: if you have a multi-core CPU, try adding -parallel to the ifort command line :)

Fortran I/O: Specifying large record sizes

I am trying to write an array to file, where I have opened the file this way:
open(unit=20, FILE="output.txt", form='unformatted', access='direct', recl=sizeof(u))
Here, u is an array and sizeof(u) is 2730025920, which is ~2.5GB.
When I run the program, I get an error Fortran runtime error: RECL parameter is non-positive in OPEN statement, which I believe means that the record size is too large.
Is there a way to handle this? One option would be to write the array in more than one write call such that the record size in each write is smaller than 2.5GB. But I am wondering if I can write the entire array in a single call.
Edit:
u has been declared as double precision u(5,0:408,0:408,0:407)
The program was compiled as gfortran -O3 -fopenmp -mcmodel=medium test.f
There is some OpenMP code in this program, but the file I/O is sequential.
gfortran v 4.5.0, OS: Opensuse 11.3 on 64 bit AMD Opteron
Thanks for your help.
You should be able to write big arrays as long as it's memory permitting. It seems like you are getting integer overflow with the sizeof function. sizeof is not Fortran standard and I would not recommend using it (implementations may vary between compilers). Instead, it is a better practice to use the inquire statement to obtain record length. I was able to reproduce your problem with ifort and this solution works for me. You can avoid integer overflow by declaring a higher kind variable:
integer(kind=8) :: reclen
inquire(iolength=reclen)u
open(unit=20,file='output.txt',form='unformatted',&
access='direct',recl=reclen)
EDIT: After some investigation, this seems to be a gfortran problem. Setting a higher kind for integer reclen solves the problem for ifort and pgf90, but not for gfortran - I just tried this with version 4.6.2. Even though reclen has the correct positive value, it seems that recl is 32-bit signed integer internally with gfortran (Thanks #M.S.B. for pointing this out). The Fortran run-time error suggests this, and not that the value is larger than maximum. I doubt it is an OS issue. If possible, try using ifort (free for non-commercial use): Intel Non-Commercial Software Download.