- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am trying to run a finite element fortran program. I am not using MS Visual Studio but rather I am compiling from the command line. The code compiles and runs fine as both a 32-bit and 64-bit application provided the arrays are small enough that they don't exceed 1GB. When the arrays exceed 1GB I get the following error Error <170> Program exception - stack overflow. I have reviewed several of the posts regarding how to deal with this error when using MS Visual Studio. I am wondering how to deal with it when compiling from the command line? Any help is appreciated.
Compiler: Intel Visual Fortran 11.1
System: Intel Xeon CPU E5520 @ 2.27 GHz
12 GB memory
Link Copied
8 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The linker has a /STACK:, option that you may want to consider using. Secondly, it would be useful to know which array variables are being allocated on the stack. Some of them could be ALLOCATEd instead.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The command line version of stack reservation is invoked by appending
/link /stack:nnnnnnnnn
to your ifort linking command. Set nnnnnnnnn to a reasonable numerical value.
/link /stack:nnnnnnnnn
to your ifort linking command. Set nnnnnnnnn to a reasonable numerical value.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for your help. Setting the stack as you described cleared up the problem. I also tried with success using the option /heap-arrays.
I did look through the online manuals and could not find the /stack option anywhere. Is it hidden away in some obscure place?
Finally, can you direct me to a good reference that clearly describes the strengths and weaknesses of the various ways for passing arrays between subroutines. The finite element code I am using was a Fortran 77 code that I have spent a great deal of time converting to fortran 95. Originally most of the arrays were passed in common blocks or within the subroutine calls. The size of all of these arrays was defined at compile time.
I have altered the code to allocate most of these arrays at runtime and in some cases placed the arrays in parameter modules eliminating the common bocks. However, some arrays are still passed during the subroutine call. For example, an array allocated in the main part of the program might be passed to a subroutine as follows:
program main
implicit none
integer :: maxnn
real(8),allocatable :: a(:)
maxnn=nn
allocate (a(nn))
...
call flow(maxnn,a)
...
...
deallocate(a)
stop
end program
subroutine flow(maxnn,h)
implicit none
integer :: maxnn
real(8) :: h(maxnn)
...
...
return
end
I guess my question is, "Are calls like these the likely source of the problem with the stack overflow?"
I did look through the online manuals and could not find the /stack option anywhere. Is it hidden away in some obscure place?
Finally, can you direct me to a good reference that clearly describes the strengths and weaknesses of the various ways for passing arrays between subroutines. The finite element code I am using was a Fortran 77 code that I have spent a great deal of time converting to fortran 95. Originally most of the arrays were passed in common blocks or within the subroutine calls. The size of all of these arrays was defined at compile time.
I have altered the code to allocate most of these arrays at runtime and in some cases placed the arrays in parameter modules eliminating the common bocks. However, some arrays are still passed during the subroutine call. For example, an array allocated in the main part of the program might be passed to a subroutine as follows:
program main
implicit none
integer :: maxnn
real(8),allocatable :: a(:)
maxnn=nn
allocate (a(nn))
...
call flow(maxnn,a)
...
...
deallocate(a)
stop
end program
subroutine flow(maxnn,h)
implicit none
integer :: maxnn
real(8) :: h(maxnn)
...
...
return
end
I guess my question is, "Are calls like these the likely source of the problem with the stack overflow?"
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The method of passing arguments doesn't affect stack usage. Allocatable arrays do; a good way is to use the heap-arrays option which switches from stack to heap according to the size of allocation.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Its a (Microsoft) linker option. Whether you have the help entry in VS may depend on what bits of Visual Studio etc are installed, but if you are searching the index make sure that the "Intel" filter is not active and then see if a "/STACK linker option" item appears. Apparently the fortran compiler option /Fn is equivalent - I didn't know that until today and would agree that's been well hidden...
I don't think the code you posted would be making excessive use of the stack. The array you are passing in is initally allocated (so the original is not on the stack) and it is contiguous and not an expression (so no temporary is required).
If your actual argument array wasn't continguous - say you were passing a slice along an out-of-order dimension or had subscripted using start:stop:step or a vector - then the compiler would need to create a temporary to provide the array to the flow subroutine in the form that the subroutine expected. Making the dummy argument in the subroutine assumed shape (real(8) :: h(:) - requires an explicit interface too) might help for some of these cases. I like using assumed shape arrays for this reason (and because it saves passing array lengths around everywhere), but opinions on them vary.
If, in your subroutine, you had some automatic variables (not dummy arguments) that had a size that depended on the passed value of maxnn (real :: some_variable(maxnn)) then you are in prime territory for use of the stack, particularly if the procedure is recursive or you are compiling with OpenMP.
The compiler might also create temporary arrays for some array expressions and assignments. In some cases this is because a temporary is required in order to correctly "completely evaluate" the expression before assignment or argument association as per the fortran standard, in other cases it is because the compiler is not smart enough to work out that a temporary is not required. The compiler isn't very bright at times...
The /check:arg_temp_created compiler option might help you track down places where temporaries that might end up on the stack are being created. It may also just annoy you.
In my opinion: in most cases, whether to pass variables to procedures via arguments or via module variables etc is more driven by clarity of the code rather than technical requirements (rules for pure procedures and aliasing prohibitions aside). Arguments offer the benefit that at the site of the call you can see what information the procedure operates with. Module variables etc have the benefit that you don't need to clutter the call up with lots of noise (and maybe the potential for error). I put "ubiquitous" constants (molecular weights etc) in modules, equivocate about things like the big data arrays that may be almost as universal in the context of the program, and then argument everything else. Where argument lists start getting silly in length then there's a clear case for bundling related concepts together in derived types. Procedures that change things behind my back that I wouldn't reasonably expect (ie variables that aren't arguments) particularly irritate me.
I don't think the code you posted would be making excessive use of the stack. The array you are passing in is initally allocated (so the original is not on the stack) and it is contiguous and not an expression (so no temporary is required).
If your actual argument array wasn't continguous - say you were passing a slice along an out-of-order dimension or had subscripted using start:stop:step or a vector - then the compiler would need to create a temporary to provide the array to the flow subroutine in the form that the subroutine expected. Making the dummy argument in the subroutine assumed shape (real(8) :: h(:) - requires an explicit interface too) might help for some of these cases. I like using assumed shape arrays for this reason (and because it saves passing array lengths around everywhere), but opinions on them vary.
If, in your subroutine, you had some automatic variables (not dummy arguments) that had a size that depended on the passed value of maxnn (real :: some_variable(maxnn)) then you are in prime territory for use of the stack, particularly if the procedure is recursive or you are compiling with OpenMP.
The compiler might also create temporary arrays for some array expressions and assignments. In some cases this is because a temporary is required in order to correctly "completely evaluate" the expression before assignment or argument association as per the fortran standard, in other cases it is because the compiler is not smart enough to work out that a temporary is not required. The compiler isn't very bright at times...
The /check:arg_temp_created compiler option might help you track down places where temporaries that might end up on the stack are being created. It may also just annoy you.
In my opinion: in most cases, whether to pass variables to procedures via arguments or via module variables etc is more driven by clarity of the code rather than technical requirements (rules for pure procedures and aliasing prohibitions aside). Arguments offer the benefit that at the site of the call you can see what information the procedure operates with. Module variables etc have the benefit that you don't need to clutter the call up with lots of noise (and maybe the potential for error). I put "ubiquitous" constants (molecular weights etc) in modules, equivocate about things like the big data arrays that may be almost as universal in the context of the program, and then argument everything else. Where argument lists start getting silly in length then there's a clear case for bundling related concepts together in derived types. Procedures that change things behind my back that I wouldn't reasonably expect (ie variables that aren't arguments) particularly irritate me.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting tim18
The method of passing arguments doesn't affect stack usage. Allocatable arrays do; a good way is to use the heap-arrays option which switches from stack to heap according to the size of allocation.
"Allocatable" should be "automatic"? I would have thought allocatables always ended up on the heap... otherwise how does the Intel compiler implement the cases where the allocation needs to remain valid beyond the end of the procedure?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think that Tim and you are describing two sides of the the same coin. Tim's statement, in the context of the previous postings in this thread, means to me: "..when one declares a previously automatic local array as ALLOCATABLE, and adds the necessary ALLOCATE and DEALLOCATE statements, stack usage is decreased."
The /heap-arrays compiler option achieves the same effect but without needing any changes to the source code.
The /heap-arrays compiler option achieves the same effect but without needing any changes to the source code.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for the detailed response. It helps a great deal.
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page