A program might compile and link successfully, yet produce unexpected results during execution. The compiler does not diagnose programming errors that do not violate the syntax of the language. This section describes some common errors, how to detect them, and how to correct them.
Uninitialized variables
An object of automatic storage duration is not implicitly initialized and its initial value is therefore indeterminate. If an auto variable is used before it is set, it may or may not produce the same results every time the program is run. The -qinfo=gen compiler option displays the location of auto variables that are used before being set. The -qinitauto option instructs the compiler to initialize all automatic variables to the specified value. This option reduces the run-time performance of the application and is recommended for debugging only.
Run-time checking
The -qcheck option inserts run-time checking code into the executable. The suboptions specify checking for null pointers, indexing outside of array bounds, and division by zero. Like -qinitauto, -qcheck degrades application performance and is recommended for debugging purposes only.
ANSI aliasing
Type-based aliasing, also referred to as ANSI aliasing, restricts the lvalues that can be safely used to access a data object. When compiling under a language level that enforces conformance to the language standards, the C and C++ compilers enforce type-based aliasing during optimization. The ANSI aliasing rule states that a pointer can only be dereferenced to an object of the same type or a compatible type. The exceptions are that sign and type qualifiers are not subject to type-based aliasing and that a character pointer can point to any type. The common coding practice of casting a pointer to an incompatible type and then dereferencing it violates this rule.
Turning off ANSI aliasing by setting -qalias=noansi may correct program behavior, but doing so reduces the opportunities for the compiler to optimize the application and thereby degrades run-time performance. The recommended solution is to change the program to conform to the type-based aliasing rule.
#pragma option_override
Sometimes an error appears only when optimization is used. It can be worthwhile, especially for complex applications, to turn off optimization for a function known to contain a programming error, while allowing the rest of the program to be optimized. The #pragma option_override directive allows you to specify alternate optimization options for specific functions.
The #pragma option_override directive can also be used to determine the function is causing the problem. The discovery is made by selectively turning off optimization for each function within the directive until the problem disappears.
Several proven techniques are available to achieve parallel execution of a program and more rapid job completion than running on a single processor. These techniques include:
The portability requirements for the application are definitely a factor in selecting the best technique to use. The choice is also highly dependent on the application, the programmer's skills and preferences, and the characteristics of the target machine. The two principal ways of accomplishing parallelization on AIX is by using hand-coded POSIX threads (pthreads) and OpenMP directives.
The parallel programming facilities of the AIX operating system are based on the concept of threads. Parallel programming exploits the advantages of multiprocessor systems, while maintaining a full binary compatibility with existing uniprocessor systems. This means that a multithreaded program that works on a uniprocessor system can take advantage of a multiprocessor system without recompiling.
Pthreads offer great flexibility for making effective use of multiple processors because they provide the maximal amount of control of the parallelization process. The trade-off is a considerable increase in code complexity. In many cases, the simpler approach of using OpenMP directives, SMP-enabled libraries, or the automatic SMP capabilities of compilers is preferable. The explicit use of threads does not necessarily lead to better performance. Debugging multithreaded applications is awkward at best. However, in some programs, it is the only viable approach.
The following lists some pros and cons of the different techniques.
Automatic parallelization by the compiler
SMP-enabled libraries
OpenMP directives
Hybrid approach (subset or mixture of OpenMP and pthreads, or UNIX fork() and exec() parallelization, platform-specific constructs)
pthreads
OpenMP directives are a set of commands that instruct the compiler how a particular loop should be parallelized. The existence of the directives in the source removes the need for the compiler to perform any parallel analysis on the parallel code. The use of OpenMP directives requires the presence of the pthread libraries to provide the necessary infrastructure for parallelization.
The OpenMP directives address three important issues of parallelizing an application. First, clauses and directives are available for scoping variables. Frequently, variables should not be shared; that is, each processor should have its own copy of the variable. Second, work sharing directives specify how the work contained in a parallel region of code should be distributed across the SMP processors. Finally, there are directives for synchronization between the processors.
The compiler supports the OpenMP Version 2.0 specification.
Related References