Using variables
- Use local variables, preferably automatic variables, as often
as possible.
The compiler can accurately analyze the use of local variables, while it has to make several worst-case assumptions about global variables, which hinders optimizations. For example, if you code a function that uses external variables, and calls several external functions, the compiler assumes that every call to an external function could change the value of every external variable.
- If none of the function calls affect the global variables being
used and you have to read them frequently with function calls interspersed,
copy the global variables to local variables and use these local variables
to help the compiler perform optimizations that otherwise would not
be done.
Using IPA can improve the performance of code written using global variables, because it coalesces global variables. IPA puts global variables into one or more structures and accesses them using offsets from the beginning of the structures. For more information, see Using the IPA option.
- If you need to share variables only between functions within the same compilation unit, use
static variables instead of external variables. Because static variables are visible only in the
current source file, they might not have to be reloaded if a call is made to a function in another
source file.
Organize your source code so references to a given set of externally defined variables occur only in one source file, and then use static variables instead of external variables.
In a file with several related functions and static variables, the compiler can group the variables and functions together to improve locality of reference.
Use a local static variable instead of an external variable or a variable defined outside the scope of a function.
The #pragma isolated_call preprocessor directive can improve the runtime performance of optimized code by allowing the compiler to make fewer assumptions about the references to external and static variables. For more information, see #pragma isolated_call in z/OS XL C/C++ Language Reference.
Coalescing global variables causes variables that are frequently used together to be mapped close together in memory. This strategy improves performance in the same way that changing external variables to static variables does.
- Group external data into structures (all elements of an external
structure use the same base address) or arrays wherever it makes sense
to do so.
Before it can access an external variable, the compiler has to make an extra memory access to obtain the variable’s address. The compiler removes extraneous address loads, but this means that the compiler has to use a register to keep the address.
Using many external variables simultaneously requires many registers, thereby causing spilling of registers to storage. If you group variables into structures then it can use a single variable to keep the base address of the structure and use offsets to access individual items. This reduces register pressure and improves overall performance, especially in programs compiled with the RENT option.
The compiler treats register variables the same way it treats automatic variables that do not have their addresses taken.
- Minimize the use of pointers.
Use of pointers inhibits most memory optimizations such as dead store elimination in C and C++.
You can improve the runtime performance of optimized code by using the z/OS® C #pragma disjoint directive to list identifiers that do not share the same physical storage. A similar mechanism that can be used to improve runtime performance of optimized code includes using the C99 restrict qualifier for pointers feature. The restrict type qualifier indicates for the lifetime of the pointer, and only it or a value directly derived from it will be used to access the object to which it points. For more information, see #pragma disjoint and The restrict type qualifier in z/OS XL C/C++ Language Reference.