Software Archive
Read-only legacy content
17060 Discussions

Debug vs Release compilations

Intel_C_Intel
Employee
3,077 Views
I have a program that the release version works on more robust computers but fails on two computers with RAM memory of 48 and 64 MB respectively. However when I compile a debug version to try and locate where the program fails on these two machines, the program runs fine. Is there something in the release version optimizer that I could set or does the debug version do some error trapping that the release version doesn't
0 Kudos
25 Replies
Steven_L_Intel1
Employee
2,567 Views
In Debug configuration, turn the optimization setting up to "Full" (4) and rebuild. See if that fails. If it does, drop the opt level down one and try again. You want the lowest opt setting that it fails with. Then debug.

Have you enabled traceback? What is the failure?

Steve
0 Kudos
Intel_C_Intel
Employee
2,567 Views
This subject has become a recurring theme in this forum. The most likely culprit is that you have failed to initialize a variable that then takes on differing initial values depending upon the compilation configuration - one of which causes the error. Not to beat a dead horse, but the failure of the CVF compiler to initialize uninitialized variables to a consistent value (whatever the value, I prefer zero for reals and integers and false for logicals but the key point is that they should be the same regardless of the compilation options) will continue to cause this problem resulting in having to put print statements into the executable in order to debug the program. I started out programming assembly language on a PDP 11 computer using card punch machines, and I feel like I have stepped back in time almost 30 years when I have to resort to print statements in order to debug a program. I will mention once more the option that Salford and Lahey have put into their compiler that initializes all variables to an "undefined" value and, whenever this value is encountered, the debugger stops on the line that containing the "undefined" variable. This is an incredibly powerful option that catches all sorts of program errors in one fell swoop. The folks at CVF ought to at least think about putting something like this in their compiler. Another suggestion for improving debugging capabilities would be to put in the ability to have two sessions of debuggers running with the abillity to automatically find all variables that contain different values between two versions of a code. Most FORTRAN coding done nowadays is code maintenance and updating of existing codes. This would eliminate the time spent tracking down just where in a new version of an existing code a bug has been introduced. Anyone else out there think these additions would be useful?
0 Kudos
durisinm
Novice
2,567 Views
Doesn't the compiler option /warn:uninitialized warn you when an uninitialized variable is used?

/warn:nouninitialized
Suppresses warning messages for a variable that is used before a value was assigned to it. The default is /warn:uninitialized.

In general, I feel that programmers should be responsible for properly initializing all variables. Who else but the programmer knows what the proper initial values should be?

On the other hand, the previous post brings up a good point. If you inherit a program--especially a large one--written by somebody else, it sure would be handy to have a tool to help you find uninitialized variables. I don't know if /warn:uninitialized does that job or not.

Mike Durisin
0 Kudos
Intel_C_Intel
Employee
2,567 Views
I'm a BIG believer in initializing all variables before using them. It's been ingrained in me as good practice, as most languages I've learned require it, and I've been bitten in the past when I've forgotten to do this.

But I've been thinking about this a bit lately, due to Tom's posts. On the one hand, I don't think I support a compiler switch to initialize variables to some value; it's too arbitrary. For example, I might be a "half full" person and expect that logicals be initialized to .true. instead of .false. The point is, the compiler can't know what's right for my program.

On the other hand, I'm starting to think that the different handling of uninitialized variables in debug vs. release configurations is worth questioning. Why should the default Debug configuration provide a value for uninitialized variables when the programmer doesn't? Why not show that variable as "undefined" (what exactly I mean by that I don't know. Tom has examples of something like this being done in other compilers).

The other mitigating factor is that /warn:uninitialized can be, in essence, disabled in the default Debug configuration (/debug:full) because that configuration lowers the optimization level to zero (/O0) unless an explicit optimization level has also been requested. But sometimes, variables still need to have some flow analysis done in order to issue the "used before defined" message. /O0 is not sufficient in some cases. (it is trivial to create an example to illustrate this)

I think this is an interesting discussion that's worth continuing.

-John
0 Kudos
david_jones
Beginner
2,567 Views
The simple detection of unitialised variables cannot work in general because it doesn't cope with variables passed via common blocks or subroutine arguments etc., although I may be biased here by usually compiling subroutines separately.

Perhaps what is needed is some simple compiler-provided initialisation subroutine or compiler-option which will automatically fill the data area used by a program with a given bit-pattern, with this pattern being inherited by anything not coped with by having a fixed memory allocation. A user could then at least run the same program with different settings of this bit pattern and all other options the same to try to detect any differences in program output arising from what would be areas not initialized properly within a program. I seem to recall that this type of option is provided on some compilers.

David Jones
0 Kudos
Intel_C_Intel
Employee
2,567 Views
Here is a specific example of what I am talking about. My field is hydrodynamic and water quality modeling. Typically, codes like these work on arrays that are dimensioned according to the dimension of the problem (1D, 2D, 3D), but only a portion of the arrays involve elements that are part of the computational domain. For a 2D code where the arrays might be dimension 50x50, there might only be 100 "active" computational cells in the domain where an active computational cell is defined as having a width > 0.

Codes then typically loop only over the active cells rather than the whole array to save computational time. The active cells would then be determined by reading in the widths and determining where in the computational grid subsequent DO loop indices should loop over.

If there is an error in the code in the DO loop indices that extends a computation outside the computational grid (accessing an array element at K+1 when K is at the bottom active cell), then the value at K+1 can be different in the debug version versus the release version and will give different answers (which is what started this thread).

The CVF compiler forces the coder to resort to print statements in the code in order to find this error. What I am talking about in the Lahey and Salford compilers is an option to initialize all variables of the array to an "uninitialized" value (some value that has an exceedingly small chance of occurring as a "correct" value for the variable). Then, during runtime, code is inserted by the compiler to chech to see if any variable has this value.

In the preceeding example, the width at K+1 would have been undefined and during debugging the debugger would stop at the line that contained the variable with the "uninitialized" value. This is a real example in the CE-QUAL-W2 code that has existed for a decade. When computing bottom friction, the code computed the average width at the bottom of a computional cell ([(B(K,I)+B(K+1,I))/2.0]. Everything was fine except at the bottom active cell in the compational grid where B(K+1,I) was originally initialized to zero. The result was the friction computed at the bottom of the grid was half of what it was supposed to be. V2 of the model was used primarily for reservoirs in which bottom friction played a minor role. V3 added the capability to model steeply sloping rivers in which bottom friction was now a major player in the hydrodynamic solution. Salford's compiler found this bug right off the bat (and other bugs similar to this).

Steve and John's comments about forcing the programmer to initialize all variables, as I stated once before, is correct in theory, but in practice is another matter. The logical value to initialize the B array to is zero since this is how cells outside the computational domain are defined. So forcing the user to initialize B to zero does not eliminate bugs associated with incorrect initialization values, since B outside the computational domain is correctly initialized to zero.

I will reiterate my point once more - forcing a programmer to initialize all arrays does always eliminate bugs and in many cases makes them more difficult to find. It also results in problems that a number of CVF users have experienced - codes that cannot be debugged inside the CVF environment forcing the programmer to put in print statements in the code in order to find the bug. All compilers should have a default "initial" value for all variables that does not change depending upon compiler options, thus eliminating this problem. Again, I prefer zero for reals and integers and false for logicals, but it doesn't make any difference what they default to so long as the default value is consistent.

The best solution is what Salford and Lahey have implemented where code checks for "uninitialized" values during run time.

Tom
0 Kudos
Intel_C_Intel
Employee
2,567 Views
How do I force in new paragraph in this forum: My previous reply is virtually unreadable.

Tom
0 Kudos
Intel_C_Intel
Employee
2,567 Views
Also, none of my edits in the reply took effect - the part "forcing a programmer to initialize all arrays does always" should read "forcing a programmer to initialize all arrays does 'not' always......... One final thought about theory and practice - implementing a compiler generated run time check for uninitialized values implies that the best programming practice is to NEVER initialize variables.

Tom
0 Kudos
Intel_C_Intel
Employee
2,567 Views
How do I force in new paragraph in this forum: My previous reply is virtually unreadable.

Tom
0 Kudos
Steven_L_Intel1
Employee
2,567 Views
Just hit enter twice to leave a blank line - that should do it. I'll edit your reply to format it better.

Steve
0 Kudos
Steven_L_Intel1
Employee
2,567 Views
We've tended to concentrate on making programs run fast. We add diagnostics where we can do so at a reasonable cost, but to take the approach that Salford (and later, Lahey) took requires not only extensive development time, but it also dramatically slows down execution.

We could zero-initialize all variables without too much difficulty, but this would just tend to hide programmer errors. Initializing floating values to NaNs could help, but for other types, you need to add run-time tests of an "uninitialized" flag - and also need to pass that information in subroutine calls, creating compatibility problems when the application isn't all Fortran.

We recognize that these features can be valuable, but we do not have unlimited resources and prefer to devote our energies to making correct programs run faster.

Personally, I'm more on John's side in that I don't feel a compiler should try to compensate for poor programming practices. In the end, we look at what most of our customers look for, and that has been performance. CVF is the performance leader and we intend to keep it that way. We ARE looking at adding specific diagnostic features, such as pointer and shape checking, but I doubt you'll ever see us go for full-blown run-time interpretation, the way Salford and Lahey have done. If you find those attributes more important, then by all means buy one of those compilers. If enough people do that, then perhaps our priorities would change, but I don't see that happening in this market. (There's a reason why CVF far outsells all of the competition combined...)

I wish we could do everything people want. But we have to make choices, and we've chosen to emphasize performance. Yes, that means there's less hand-holding than other compilers offer.

Some hints - to help the compiler find uninitialized variables, try compiling with /automatic (Settings.Fortran..Fortran Data..Variables default to AUTOMATIC.) Also, use explicit interfaces, with appropriate INTENT attributes, throuhout your program. This one thing alone will help you locate many coding errors.

Steve
0 Kudos
Intel_C_Intel
Employee
2,567 Views
How do I force in new paragraph in this forum: My previous reply is virtually unreadable.

Tom
0 Kudos
Intel_C_Intel
Employee
2,567 Views
Steve,

I hear you - I have limited resources available so I totally sympathize. But what started this discussion was another in a long list of folks saying that they get errors in the release verson and don't get them in the debug version. The culprit is probably more often than not an unitialized array and it could be solved by the compiler initializing all variables to some consistent value. Again, I like zero, etc. but it makes no difference. Having this option at least allows one to debug a program that a programmer would otherwise have to resort to putting in print statements. For the "purists", the option could always be turned off, even if it made their life easier (which is what computers are supposed to be all about). I don't think this would require a tremendous effort on the compiler writers part. And, by the way, you are correct - CVF runs my model a LOT faster than Salford with release compilation options, so you have been succesful in what your main goal is - to provide fast runtime speeds. I still would like to hear some comment on my other suggestion - be able to run two different versions of a code (mainly during development/enhancement where one is the "correct" version and the other is the one in development) and then list all variables that have values that differ between the two codes. This would be incredibly useful and I don't think would require a lot of effort on CVF's part. Thanks for an interesting discussion.

Tom
0 Kudos
Steven_L_Intel1
Employee
2,567 Views
Actually, not initializing variables is only one of several common mistakes that cause debug/release differences. Others can include argument type mismatches, dummy argument aliasing and rounding differences caused by use of registers for intermediate results.

I don't know how CVF could automatically do something that would show you differences between variables - you could use NAMELIST output to dump the variables and WinDiff the output. CVF wouldn't know which variables are interesting (and with optimization, many local variables aren't independently allocated).

Steve
0 Kudos
durisinm
Novice
2,567 Views
What are the conventions for initializing variables in other languages: Visual C++, Visual Basic, Delphi, for example.

I haven't seen an answer to John's question about why variables are initialized differently in Release and Debug configurations for CVF. Is there a reason for this?

Mike Durisin
0 Kudos
Intel_C_Intel
Employee
2,567 Views
Wow, there's a lot I'd like to comment on in this thread. This is where I really wish that this darn forum supported threaded discussions. [sigh]

Well, since I'm talking about the forum I'll start here


Tom wrote:
Also, none of my edits in the reply took effect - the part "forcing a programmer to initialize all arrays does always" should read "forcing a programmer to initialize all arrays does 'not' always.........


Me too. I used the Edit button to edit one of my replies but my changes were not replected in the posting. I just gave up on it. Has it worked for anyone?

-John
0 Kudos
durisinm
Novice
2,567 Views
I have tried using the Edit button once or twice before, and it didn't work for me, either.
0 Kudos
Steven_L_Intel1
Employee
2,567 Views
Strange - the edit button works for me, but then I'm a moderator. I'll check into it.

Regarding "why variables are initialized differently" - they aren't. They're uninitialized in both configurations. It's just that in Debug configuration the variable tends to live entirely in memory, and that's USUALLY zero (but not guaranteed). In Release, the variable could live on the stack or in a register, and you'll get whatever was there last.

Steve
0 Kudos
Intel_C_Intel
Employee
2,567 Views
Seems like we are starting to get into the realm of philosopy of compilers. Well, here goes.

Regarding Steve's comment that the goal of CVF is to provide fast runtimes for "correct" codes (which, as I stated before, they have succeeded admirably), MY first goal in writing FORTRAN programs that people rely upon to make multimillion dollar decisions is first and foremost to write a "correct" program that gives the "right" answer, hence the importance of a compiler that minimizes the effort to write "correct" programs. Getting the wrong answer more quickly should not be the goal of anyone, which I think everyone would agree with.

If you get different answers from a FORTRAN code depending upon the compiler options, they can't both be the "correct" result. Then it is up to the devleloper to decide which is the "correct" result or if either of them are correct. I will leave my belief that there is no such thing as a "correct" 10,000 line FORTRAN program for another time - one thing I have learned after almost 30 years of programming is that a debugger's job is never done. Hence my viewpoint on the importance first and foremost of a great debugging environment that makes it easier to find bugs that are going to be in a code regardless of how good a programmer one is and how well they follow good programming practices.

A FORTRAN compiler should always give the same answer to a problem (with the exception of how roundoff and precision is handled by different compiler options - I agree this is up to the program developer to find and eliminate problems associated with floating point precision).

As Steve has just stated, the way CVF handles this results in a program that can potentially give different results depending upon the compiler options used. If I develop a source code that is released to the public (which is what I do), then this means I have to try all possible combinations of compiler options to ensure that someone else who compiles the program with potentially different options than I used will not get the "wrong" answer.

You can imagine my dismay when I realized this about CVF given the fact that if I encountered major differences (which I did) in the results, I would have to resort to print statements in the code in order to find out why I got different results. All because of this stubborness to follow a rule handed down from on high that the code developer and only the code developer knows how to properly inititialize variables which I don't dispute in theory, but in practice this seldom is the case that the developer always does this properly. I guess my major point is that if everyone followed all the good programming rules and practices, we would all write bugless codes. Anyone want to hold up a commercial product that shows this is the case? In spite of Steve's best efforts, there are bugs in CVF and there will continue to be bugs found in CVF. What I want is a development environment that makes it easier to find these bugs.

Tom

Tom
0 Kudos
Steven_L_Intel1
Employee
2,439 Views
Unlike with some vendors, our philosophy is that you should expect a correct program to deliver substantially the same results with optimization enabled as without. You should not need to try various combinations to see what differences there are. You SHOULD test the product you're delivering to make sure it provides results you're satisfied with.

If you use explicit interfaces throughout your program, along with IMPLICIT NONE, and specify correct INTENT attributes, you can go a long way towards ensuring correctness. I can recommend /automatic as a debugging tool to reveal additional uninitialized variables, but nothing short of full run-time checking is going to find them all.

We continue to improve compile-time and run-time diagnostics. We're working on shape/pointer checking now. Other improvements will undoubtedly come later. There's just so much a compiler can do for you - you have to do your own testing as well.

Steve
0 Kudos
Reply