Debugging optimized programs presents special usability
problems. Optimization can change the sequence of operations, add
or remove code, change variable data locations, and perform other
transformations that make it difficult to associate the generated
code with the original source statements.
For example:
- Data location issues
- With an optimized program, it is not always certain where the
most current value for a variable is located. For example, a value
in memory may not be current if the most current value is being stored
in a register. Most debuggers are incapable of following the removal
of stores to a variable, and to the debugger it appears as though
that variable is never updated, or possibly even never set.
This contrasts with no optimization where all values are flushed back
to memory and debugging can be more effective and usable.
- Instruction scheduling issues
- With an optimized program, the compiler might reorder
instructions. That is, instructions might not be executed in the order
you would expect based on the sequence of lines in the original source
code. Also, the sequence of instructions for a statement might not
be contiguous. As you step through the program with a debugger, the
program may appear as if it is returning to a previously executed
line in the code (interleaving of instructions).
- Consolidating variable values
- Optimizations can result in the removal and consolidation of variables.
For example, if a program has two expressions that assign the same
value to two different variables, the compiler may substitute a single
variable. This can inhibit debug usability because a variable that
a programmer is expecting to see is no longer available in the optimized
program.
There are a couple of different approaches you can take to improve
debug capabilities while also optimizing your program:
- Debug non-optimized code first
- Debug a non-optimized version of your program first, then recompile
it with your desired optimization options. See Debugging in the presence of optimization for some compiler
options that are useful in this approach.
- Use -g level
- Use the -g level suboption
to control the amount of debugging information made available. Increasing
it improves debug capability, but prevents some optimizations.
- Use -qoptdebug
- When compiling with -O3 optimization
level or higher, use the compiler option -qoptdebug to
generate a pseudocode file that more accurately maps to how instructions
and variable values will operate in an optimized program. With this
option, when you load your program into a debugger, you will be debugging
the pseudocode for the optimized program. See Using -qoptdebug to help debug optimized programs for more information.