I tried to implement an easy Matrix multiplication, but I Keep getting the error
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
test_performance. 00000000004708F1 Unknown Unknown Unknown
test_performance. 000000000046F047 Unknown Unknown Unknown
test_performance. 000000000043F544 Unknown Unknown Unknown
test_performance. 000000000043F356 Unknown Unknown Unknown
test_performance. 0000000000423DFF Unknown Unknown Unknown
test_performance. 000000000040384D Unknown Unknown Unknown
libpthread.so.0 00002AD8B44769F0 Unknown Unknown Unknown
test_performance. 00000000004034A8 Unknown Unknown Unknown
test_performance. 0000000000402ECE Unknown Unknown Unknown
libc.so.6 00002AD8B46A6BE5 Unknown Unknown Unknown
test_performance. 0000000000402DD9 Unknown Unknown Unknown
This is my Code:
PROGRAM test_performance
IMPLICIT NONE
INTEGER :: DIM_M, DIM_L, DIM_N, index1, index2,index3,index4
INTEGER, DIMENSION(4,4) :: A,B,C
DIM_L=4
DIM_M=4
DIM_N=4
DO index1=1,DIM_M
DO index2=1,DIM_L
print *, 'here I am!'
A(index1,index2)=index1+index2
END DO
END DO
DO index3=1,DIM_L
DO index4=1,DIM_N
B(index3,index4)=index3+index4
END DO
END DO
print *,'A= ',A
print *,'B= ',B
CALL MATRIXMULTIPLICATION
PRINT *, 'C=', C
END PROGRAM test_performance
SUBROUTINE MATRIXMULTIPLICATION(A,B,C, DIM_M, DIM_L, DIM_N)
INTEGER, INTENT(IN) :: DIM_M, DIM_L, DIM_N
INTEGER, INTENT(IN) :: A(4,4), B(4,4)
INTEGER, INTENT(OUT) :: C(4,4)
INTEGER :: ii=1,jj=1, kk=1
DO ii=1, DIM_M
DO jj=1, DIM_N
DO kk=1, DIM_L
C(ii,jj)=C(ii,jj)+A(ii,ll)*B(ll,jj)
END DO
END DO
END DO
END SUBROUTINE MATRIXMULTIPLICATION
I don't know why I get this error, since the Dimension and all the Indices should just be fine. I tried to find the error by using all possible stuff, but I don't havy any clue anymore what the error could be.
The statement
CALL MATRIXMULTIPLICATION
doesn't include the arguments needed when the routine is called. A poor solution would be to simply replace that statement by
CALL MATRIXMULTIPLICATION(A,B,C, DIM_M, DIM_L, DIM_N)
A better solution would be, however, to make the subroutine's interface explicit. There are a number of ways of doing this, one by putting it into a module and useing the module. For a single subroutine that might be overkill but is definitely the way to go as your programs become larger and more complex.
A simple straightforward and satisfactory for your current purposes solution would be to move the line
END PROGRAM test_performance
to follow the line
END SUBROUTINE MATRIXMULTIPLICATION
and, where the end program line originally was insert the line
contains
If you had written your program along these lines in the first place the compiler would have seen your egregious error and pointed it out to you. As it stands the subroutine is external to the program and the compiler can't match its dummy and actual arguments at compile time; as written that argument matching is the programmer's responsibility, one you've rather fluffed.
Further improvements would be to make your subroutine handle arrays of any size and to not bother passing the array dimensions through the argument list. Fortran arrays carry their size and shape information with them, on the rare occasion a routine needs to know them explicitly it can make enquiries.
Even easier would be to use the matmul intrinsic and to spend your time programming other, perhaps more challenging and more interesting, parts of your code.
Related
I have some legacy Fortran 77 code which I'm trying to at least compile without warnings (without disabling warnings). There are subroutine calls that pass a scalar where subroutine expects an array, since the scalar is used as a size-1 array, this causes no problems. But with the Intel compiler, if I enable interface warnings I get this error:
error #8284: If the actual argument is scalar, the dummy argument shall be scalar unless the actual argument is of type character or is an element of an array that is not assumed shape, pointer, or polymorphic.
In some cases, I've tried to solve this by overloading the subroutine with array and scalar variants, but then I face a problem when the argument passed is an "an element of an array", which is detected as a scalar. Consider the following sample (tested with gfortran):
program a
integer n,dum(3)
interface readn
subroutine readn_s(n,m)
integer m,n
end subroutine
subroutine readn_a(n,m)
integer m,n(*)
end subroutine
end interface
call readn(n,1)
write(6,*) 'n=',n
call readn(dum,3)
write(6,*) 'dum=',dum
call readn(dum(2),2)
write(6,*) 'dum=',dum
end program
subroutine readn_s(n,m)
integer i,m,n
n=2
end subroutine
subroutine readn_a(n,m)
integer i,m,n(*)
do i=1,m
n(i)=1
end do
end subroutine
The readn(dum,3) call correctly uses readn_a, while the second one uses readn_s. The intended behaviour is that both should use readn_a. Indeed, if I replace both calls with readn_a everything is as expected.
Is it possible to have this working properly and use the "array" version of the overloaded routine when the actual argument is an array element? I've found out it works if I call the subroutine with readn(dum(2:),2), but I'm afraid that creates a temporary copy of the array...
Original problem:
file.f90
program a
integer n,dum(3)
call readn_a(n,1)
write(6,*) 'n=',n
call readn_a(dum,3)
write(6,*) 'dum=',dum
dum=3
call readn_a(dum(2),2)
write(6,*) 'dum=',dum
end program
file2.f90
subroutine readn_a(n,m)
integer i,m,n(*)
do i=1,m
n(i)=1
end do
end subroutine
Compile with gfortran -Wall file.f90 file2.f90 or ifort file.f90 file2.f90, all is fine and the output is the intended:
n= 1
dum= 1 1 1
dum= 3 1 1
Compile with ifort -warn all file.f90 file2.f90 and I get the error #8284 above. So that's why I wanted a version of the subroutine that would work with scalars or arrays... but would give the array version with an array element.
In your attempted solution the type-kind-rank generic resolution will delegate all array elements to the scalar version of the subroutine and that will not do the intended work on the part of the array. So "The intended behaviour is that both should use readn_a." is not really possible with the approach you chose.
Well, it is possible when you rewrite the code to pass array sections as you noted yourself. But we are again at the same problem as we were before, you example is simplified. We can be certain there there is no temporary array in the example you have shown, we definitely can't say that about your real code. If you use some 2D subsections starting at some random place, you will have temporary arrays for sure and it might be difficult to make the correct subsection at all.
The original warning should be reasonably easy to avoid in your original legacy code. FORTRAN 77 has no non-contiguous arrays so if you keep your arguments to be integer :: a(*) instead of integer :: a and pass that further. If your original variable is scalar, that is a problem.
The problem is that an integer scalar does not constitute an element sequence:
F2008 12.5.2.11 1 An actual argument represents an element sequence if
it is an array expression, an array element designator, a default
character scalar, or a scalar of type character with the C character
kind (15.2.2). ...
An array element designator a(2) is an element sequence but the scalar n is not.
So it is not allowed for sequence association which is used when an array element is passed:
F2008 12.5.2.11 4 An actual argument that represents an element
sequence and corresponds to a dummy argument that is an array is
sequence associated with the dummy argument if the dummy argument is
an explicit-shape or assumed-size array. ...
Your code is not strictly standard Fortran conforming, but very likely to work as expected if you manage to compile it.
Possible solutions:
You can pass the argument as an array expression, but the argument may not be modified inside the subroutine
call readn_a([n],1)
You can just disable the warnings about interface matching
ifort -warn nointerfaces
You can create separate subroutines which only work for scalars and call it under some different name.
You can also disable argument checking for that dummy argument by an Intel Compiler directive
!DEC$ ATTRIBUTES NO_ARG_CHECK :: dummy-arg-name
Before reporting this as a compiler bug at the Intel forums, I'd like to know if the following is standard conforming. My question is: is the order of logical operations always fixed in Fortran?
! main.f90
interface
subroutine f(x)
logical, intent(in), optional :: x
end subroutine f
end interface
call f(.false.)
call f(.true.)
call f()
end program
! f.f90
subroutine f(x)
logical, intent(in), optional :: x
print*, present(x) .and. x
end subroutine f
gfortran main.f90 f.f90 && ./a.out prints
F
T
F
ifort main.f90 f.f90 && ./a.out prints
F
T
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
a.out 0000000000476D75 Unknown Unknown Unknown
a.out 0000000000474997 Unknown Unknown Unknown
a.out 0000000000444264 Unknown Unknown Unknown
a.out 0000000000444076 Unknown Unknown Unknown
a.out 0000000000425176 Unknown Unknown Unknown
a.out 00000000004027A0 Unknown Unknown Unknown
libpthread.so.0 00007F3560702E80 Unknown Unknown Unknown
a.out 0000000000402633 Unknown Unknown Unknown
a.out 000000000040260F Unknown Unknown Unknown
a.out 00000000004025AE Unknown Unknown Unknown
libc.so.6 00007F3560371710 Unknown Unknown Unknown
a.out 00000000004024A9 Unknown Unknown Unknown
I'm using GCC 5.3.0 and Ifort 16.0.2.
No, the Fortran standards make no guarantee about the ordering in which logical expressions are evaluated. Like mathematical expressions compilers are free to reorder them into orders which would be equivalent in the perfect world of 'real logic' (or 'real mathematics') but which are not equivalent in the imperfect world of computers.
You might enforce an order of evaluation like this:
if (.not. present(x)) then
print*, .false.
else
print*, x
end if
My copy of the draft standard includes the clause
7.1.5.4.2 Evaluation of logical intrinsic operations
Once the interpretation of a logical intrinsic operation is established, the
processor may evaluate any other expression that is logically
equivalent, provided that the integrity of parentheses in any
expression is not violated.
My interpretation of the standard is that the program does not conform because it makes reference to an optional argument which is not present. Refer to section 12.5.2.12 3 (1) which rules against this. Because the order of evaluation of the operands of the .and. operator is undefined x may be referenced when not present.
I'm learning how to use functions in fortran and I came across several cases which made me believe that fortran function pass the argument by const reference. When I say "pass by const reference", I'm saying it in C++ sense. I searched online and didn't find related documents. The code which makes me believe fortran functions pass arguments by const reference is as follows.
program try
implicit none
real sq
real a,b
write(*,*) sq(2)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
sq=x**2
return
end
The output for this is
0.0000000E+00
4.000000
This result supports the idea that fortran functions pass arguments by reference, since sq(2) doesn't work. After this code, I put a new line x=x+1 inside the definition of sq. The code looks like
program try
implicit none
real sq
real a,b
write(*,*) sq(2)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
x=x+1
sq=x**2
return
end
This code does compile, but when I run it, it gives the following error
forrtl: severe (180): SIGBUS, bus error occurred
Image PC Routine Line Source
a.out 00000001000014DB Unknown Unknown Unknown
a.out 000000010000144C Unknown Unknown Unknown
Stack trace terminated abnormally.
I guess I got this error because I can't modify the argument inside the function definition, which makes me believe that the argument is passed by const reference. The compiler I'm using is ifort 12.0.0. I'm running it on Mac OS X 10.6.8. Can anyone tell me whether my guess is true?
Update: According to the comment of #Jean, after modifying sq(2) to sq(2.0). The first example will work, the second one still gives the same error. The modified version of the first example is
program try
implicit none
real sq
real a,b
write(*,*) sq(2.0)
a=2
write(*,*) sq(a)
end program
real function sq(x)
real x
sq=x**2
return
end
The output is
4.000000
4.000000
I don't know why this simple modification will work. Hopefully someone can clarify for me.
As pointed out in the comments, you should use explicit interfaces. Then the compiler is able to check argument types. There are different possibilities to do that. For larger programs use modules, for smaller ones, you can include your procedure in the main program by using the contains keyword.
Here is a slightly modified version of your code:
program try
implicit none
real a,b
write(*,*) sq(2.0)
a=2
write(*,*) sq(a)
contains
real function sq(x)
real, value :: x
x=x+1
sq=x**2
return
end
end program
What's new?
the function is included in the main program with the contains keyword. When doing so, you don't have to declare sq like you did before in your third line. Also, the compiler can now check the argument type. Try to write 2 instead of 2.0 and see what happens.
You are right about the references. In Fortran arguments are passed by reference. If your argument is not a variable but just a number, then you can not change it within the procedure because it is constant. If you want variables to be passed by value, use the value keyword.
When I tried to run a huge Fortran code (the code is compiled using Intel compiler version 13.1.3.192), it gave me error message like this:
...
Info[FDFI_Setup]: HPDF code version number is 1.00246
forrtl: severe (153): allocatable array or pointer is not allocated
Image PC Routine Line Source
arts 0000000002AD96BE Unknown Unknown Unknown
arts 0000000002AD8156 Unknown Unknown Unknown
arts 0000000002A87532 Unknown Unknown Unknown
...
Nonetheless, if I insert a small write statement (which is just to check the code, not to disturb the original purpose of the code) in one of the subroutines as the following (I couldn't put all the codes since they are too huge):
...
endif
call GetInputLine(Unit,line,eof,err)
enddo
if(err) return
! - [elfsummer] 20140815 Checkpoint 23
open(unit = 1, file = '/bin/monitor/log_checkpoint',status='old',position='append')
write(1,*) "BEFORE checking required keys: so far so good!"
close(1)
! check required keys
! for modes = 2,3, P and T are the required keys
if(StrmDat%ModeCI==2.or.StrmDat%ModeCI==3) then
...
then suddenly, the error message shown above disappears and the code can run correctly! I also tried to insert such write statements in other locations in the source code but the above error message still exists.
According to Intel's documentation:
severe (153): Allocatable array or pointer is not allocated
FOR$IOS_INVDEALLOC. A Fortran 90 allocatable array or pointer must already be allocated when you attempt to deallocate it. You must allocate the array or pointer before it can again be deallocated.
Note: This error can be returned by STAT in a DEALLOCATE statement.
However, I couldn't see any relations between the error and the "write statements" I added to the code. There is no such "allocate" command in the location I add the write statements.
So I am quite confused. Does anybody know the reasons? Any help is greatly appreciated!!
With traceback option, I could locate the error source directly:
subroutine StringRead(Str,delimiter,StrArray,ns) ! [private] read strings separated by delimiter
implicit none
character*(*),intent(in) :: Str
character*(*),intent(in) :: delimiter
character*(*),pointer :: StrArray(:)
integer,intent(out) :: ns
! - local variables
character(len=len(Str)) :: tline
integer :: nvalue,nvalue_max
character(len=len(StrArray)),pointer:: sarray(:),sarray_bak(:)
integer :: len_a,len_d,i
! deallocate StrArray
if(associated(StrArray)) deallocate(StrArray)
The error, according to the information the traceback gave me, lies in the last statement shown above. If I comment out this statement, then the "forrtl: severe (153)" error would disappear while new errors being generated... But still, I don't think this statement itself could go wrong...It acts as if it just ignores the if... condition and directly reads the deallocate commend, which seems weird to me.
You could have a bug in which you are illegally writing to memory and damaging the structure that stores the allocation information. Changing the code might cause the memory damage to occur elsewhere and that specific error to disappear. Generally, illegal memory accesses typically occur two ways in Fortran. 1) illegal subscripts, 2) mismatch between actual and dummy arguments, i.e., between variables in call and variables as declared in procedures. You can search for the first type of error by using your compiler's option for run-time subscript checking. You can guard against the second by placing all of your procedures in modules and useing those modules so that the compiler can check for argument consistency.
Sounds like some of the earlier comments give the general explanation. However,
1) Is StrArray(:) an Intent(out)? That is, are you reading the file's lines into StrArray() in the s/r, with the hope of returning that as the file's content? If so, declare it as an (Out), or whatever it should be.
2) Why is StrArray() a Pointer? Does it need to be a Pointer? If all you want is file content, you may be better off using a non-Pointer.
You may still need an Allocatable, or Automatic or something, but non-Pointers are easier in many cases.
3) If you must have StrArray(:) as a Pointer, then its size/shape etc must be created prior to use. If the calling sequence ACTUAL Arg is correctly defined (and if StrArray() is Intent(In) or Intent(InOUT), then that might do it.
By contrast, if it is an (Out), then, as with all Pointer arrays, it must be FIRST Allcoated() in the s/r.
If it is not Allocated somewhere early on, then it is undefined, and so the DeAllocate() fails, since it has nothing to DeAlloc, hence Stat = 153.
4) It is possible that you may wish to use this to read files without first knowing the number of lines to read. In that case, you cannot (at least not easily), Allocate StrArray() in advance, since you don't know the Size. In this case, alternate strategies are required.
One possible solution is a loop that simple reads the first char, or advances somehow, for each line in the file. Have the loop track the "sum" of each line read, until EOF. Then, you will know the size of the file (in terms of num lines), and you then allocate StrArray(SumLines) or something. Something like
SumLines = 0
Do i=1, ?? (or use a While)
... test to see if "line i" exists, or EOF, if so, Exit
SumLines = SumLines + 1
End Do
It may be best to do this in a separate s/r, so that the Size etc are known prior to calling the FileRead bits (i.e. that the file size is set prior to the FileRead s/r call).
However, that still leaves you with the problem of what Character(Len) to use. There are many possible solutions to this. Three of which are:
a) Use max length, like Character(Len = 2048), Intent(Out), or better yet, some compile time constant Parameter, call it MaxLineWidth
This has the obvious limitation to lines that <= MaxLineWidth, and that the memory usage may be excessively large when there many "short lines", etc.
b) Use a single char array, like Character(Len = 1), Intent(Out) :: StrArrayChar(:,:)
This is 2-D, since you need 1 D for the chars in each line, and the 2nd D for the lines.
This is a bit better compared to a) since it gives control over line width.
c) A more general approach might rely on a User Defined Type such as:
Type MyFileType
Character(Len=1), Allocatable :: FileLine(:) ! this give variable length lines, but each "line" must be allocated to the length of the line
End Type MyFileType
Then, create an array of this Type, such as:
Type(MyFileType), Allocatable :: MyFile(:) ! or, instead of Allocatable, can use Automatic etc etc
Then, Allocate MyFile to Size = num lines
... anyway, there are various choices, each with its own suitability for varying circumstances (and I have omitted much "housekeeping" re DeAllocs etc, which you will need to implement).
Incidentally, c) is also one possible prototype for "variable length strings" for many Fortran compilers that don't support such explicitly.
I am using "thrgibbs1f90b" one of BLUPF90 Family of Programs which is based on "fortran" and used for gibbs sampling to estimate the variance component for binary data. In each time I try to run thrgibbs1f90b I get the following error message:
forrtl: severe (157): Program Exception - access violation
Image PC Routine Line Source
thrgibbs1f90b.exe 0000000140021961 Unknown Unknown Unknown
thrgibbs1f90b.exe 000000014000BB5B Unknown Unknown Unknown
thrgibbs1f90b.exe 000000014026B41C Unknown Unknown Unknown
thrgibbs1f90b.exe 000000014024F4E3 Unknown Unknown Unknown
kernel32.dll 0000000076E2652D Unknown Unknown Unknown
ntdll.dll 0000000076F5C521 Unknown Unknown Unknown
Any idea why I have this message?
Thanks!
Two educated guesses
The program has tried to read from or write to an array element which doesn't exist, such as the 26th element of a 25-element array.
There is a mismatch between the dummy arguments specified for a procedure and the actual arguments in a call to the procedure; for example passing a 4-byte real value when an 8-byte value is expected (or vice-versa)
Either of these might lead to an attempt to access a memory location to which the program's process has no rights of access. There are many other possible causes, but in my experience these are the most common errors in Fortran programs which give rise to such error messages.
Both of these are easy to spot, you need to (re-)compile your program with compiler options set to check for these conditions