Selecting Appropriate Compiler Options
Compilers tend to have many possible command-line options, or flags. The programmer’s task is to identify the smallest subset of flags that will provide the most appropriate set of optimizations. Usually this falls into a set of three objectives for the build:
n The basic optimization level is the debug level. These are the flags necessary to generate code that can be effectively debugged. This kind of build is useful for debugging logical errors in the code. If the code dies with a null-pointer excep-tion, running the debug version of the code will allow the developer to determine whether that exception is a result of optimization or an intrinsic property of the code. It will also allow the developer to step through the code in the smallest pos-sible steps to see exactly how the application gets into that state. However, this capability usually comes at the cost of the reduced runtime performance.
n An optimized build of an application builds quickly and runs at a reasonable speed. A developer will build and run the application many times over the development cycle, so it is important that the compiler does not take long to compile the appli-cation and that the application executes with reasonable performance. Typically, compilers indicate an optimized compilation with the flag -O. The optimizations performed by this flag typically represent a good trade-off between attaining fast runtime performance and spending large amounts of time compiling.
Higher optimizations levels may also be appropriate. The developer first needs to evaluate whether a more aggressive compilation of the application provides further gains. If a more highly optimized build of the application delivers no further per-formance gains, then it is unnecessary to use higher levels of optimization. The build with the lower level of optimization but identical performance can be deliv-ered as the production version of the application. On the other hand, if higher optimization levels deliver greater performance, a production build of the applica-tion may get better performance at the expense of a longer build cycle. If more aggressive compiler options deliver enhanced performance, it is recommended that these options be investigated to determine exactly which options provide the per formance and whether they are appropriate to the application before being used on the production build.
Most compilers have a set of flags that match this philosophy. A debug build of an application is performed with either no optimization flags or a low optimization level flag, together with the flags that generate debug information. As the optimization level is increased, the compiler will examine the code, testing for an increasing range optimiza-tion opportunities. The more opportunities that the compiler checks for, the longer it takes to complete the compilation. Most compilers provide a flag, often -O, that selects a level of optimization that will deliver a good proportion of the maximum possible per-formance, without taking an unreasonable amount of compile time. Most compilers also provide a macro-flag, such as -fast, that enables a selection of more advanced optimiza-tions. These additional optimizations may result in the highest performance but at the cost of a further increase in compile time.
There are two general optimizations worth exploring in some detail: cross-file opti-mization and profile feedback.