Compaq KAP C/OpenMP
for Tru64 UNIX
User Guide


Previous Contents Index


Chapter 5
Assertions and Directives

Assertions enable the programmer to provide KAP with additional information about the program. Although many KAP users run the product without assertions, sometimes assertions can improve the optimization results. Directives control advanced features and transformations on a local basis.

KAP does not guarantee that an assertion will have an effect. KAP notes the information provided by the assertion, and if that information helps, KAP uses it.

A variable used in a pragma needs to be declared before it is used in that pragma; otherwise, KAP detects an error.

To understand the process KAP uses in interpreting assertions, it is necessary to understand assumed dependences. In the following loop where X is an array, n and m are scalars, and nothing is known about the relationship between n and m , there are two types of dependences, as follows:


for (i=0; i<n; i++) 
       X[i] = X[i-1] + X[m]; 

Between X[i] and X[i-1] there is a FORWARD dependence, and the distance is known to be 1. Between X[i] and X[m] , KAP tries to find a relation but cannot, because it does not know the value of m in relation to n . The second dependence is called an ASSUMED dependence, because it is assumed but cannot be proven to exist.

Assertions can be unsafe, because KAP cannot check the correctness of the assertions. If you provide incorrect information, then the KAP generated code may give different results than the original scalar program generates.

Avoid giving a series of similar, redundant assertions, and avoid mixing assertions and hand-coded parallel C pragmas. Either can cause KAP to process some of the pragmas and not others, potentially giving undesired results.

Table 5-1 lists KAP assertions and directives and their durations.

Table 5-1 KAP Assertions and Directives
Name Duration
Assertions  
#pragma _KAP arl(<integer>) Selectable
#pragma _KAP distinct (name, name) Selectable
#pragma _KAP no side effects(name) Program unit
Assertions (Parallel Processing) --- affect automatic detection  
#pragma _KAP concurrent Loop
#pragma _KAP concurrent call Loop
#pragma _KAP serial Loop
Directives (Inlining and IPA)  
#pragma _KAP inline [here|routine|global] [( name[,name..] )] Selectable
#pragma _KAP ipa [here|routine|global] [( name[,name..] )] Selectable
Directives (Parallel Processing)  
#pragma _KAP minconcurrent(<integer>) Program unit

5.1 Assertions

The following sections describe each of the KAP assertions.

5.1.1 #pragma _KAP arl(<integer>)

This is the assertion form of the -addressresolution command switch. You can use it to specify, on a function-by-function basis, the degree of data aliasing in a program. Aliasing is the use of multiple names including pointers to refer to the same memory location. This is often a useful technique, but it complicates data-dependence analysis and can reduce the opportunities for optimization. You can use this pragma to tell KAP how cautious to be about multiple names affecting the same object.

The levels are cumulative --- the assumptions made at one level include the assumptions made at earlier levels. The permitted values are as follows:

See the description of the -addressresolution switch in Chapter 4 for a detailed description of the meaning of each level.

When this pragma appears within a function between the outer { and } of the function definition, it applies only to that function. When this pragma appears elsewhere, it applies to all functions following it in the source file. Placing a pragma within a function overrides (for that function) the global pragma or command-line switch, so different values can be used in different parts of a program. The -addressresolution command switch acts like an assertion at the beginning of the source file, and can be overridden by #pragma _KAP arl assertions later in the file.

See also the #pragma _KAP distinct assertion ( Section 5.1.2) that can be used to specify specific pairs of variables that are not aliased.

5.1.2 #pragma _KAP distinct

This assertion tells KAP that listed objects (variables, arrays, items pointed to with a pointer) do not overlap in memory. The syntax of this pragma is as follows:


#pragma _KAP distinct (expr1, expr2[, expr3,...]) 

Where expr1, expr2,... represent objects. The form is as follows:

id --- a variable
*id --- what the pointer id points to
id[] --- the array whose name is id

For example, if the object pointed to by a pointer p never overlaps with the array a[i] for any i used in the program, this can be asserted with #pragma _KAP distinct (*p, a[]) .

All variables specified in this assertion must have been previously declared.

The range of this assertion is the function where it was written and any succeeding functions. If this assertion is made about local variables or function parameters, it will have no effect outside the immediate function.

5.1.3 #pragma _KAP no side effects ( name [,name...] )

C functions frequently produce more information than just the returned value. Changing values of arguments with pointers or arrays, changing global data, and I/O make a function unsafe to parallelize. The no side effects assertion indicates that all of the functions named can be assumed to be safe to execute concurrently. This means that they perform no I/O and they modify only local variables. If pointers or array names are passed to the routines, it is assumed that the memory locations they represent are not modified. The functions named by the #pragma _KAP no side effects () must have been declared before the assertion.

Warning

The #pragma _KAP no side effects () assertion tells KAP to assume that all external functions are thread-reentrant. This will override KAP default behavior, which is to assume that all external functions are NOT thread-reentrant or thread-safe. If the external functions are not thread-safe, and you use #pragma _KAP no side effects () , your program may not execute correctly. For example, local variables in functions are thread-safe only if they are stored as thread-specific data. See the Tru64 UNIX Guide to the POSIX Threads Library for information on thread-safe functions.

5.2 Parallel Processing Assertions

The following sections describe assertions available in the multiprocessor version of KAP.

5.2.1 #pragma _KAP concurrent

This assertion tells KAP to ignore assumed dependences and to prefer parallel execution of the immediately following loop. KAP continues to honor dependences it finds.

This assertion is in effect only for the loop it precedes. KAP does not generate parallel code if you use the -noconcurrentize command-line switch.

5.2.2 #pragma _KAP concurrent call

The #pragma _KAP concurrent call assertion tells KAP that the function calls in the immediately following loop can execute in parallel. KAP ignores all potential data dependences due to function arguments.

This assertion does not apply to any nested or surrounding loops. Place the concurrent call assertion before each loop with function references that can execute in parallel, as shown in the following example:


main() 
{ 
        double x[800][5000]; 
        int row,col; 
        float time1,time2; 
        csettime_(1000); 
        time1 = ctimec_(); 
#pragma _KAP concurrent call 
        for(row=0; row<800; row++){ 
                for(col=0; col <5000; col++){ 
                   x[row][col]=sin(-(double)(row)) + sin(-(double)(row)); 
                } 
        } 
        time2 = ctimec_(); 
        printf("time: %f\n",time1-time2); 
} 

Using the #pragma _KAP concurrent call assertion and processing with the -unroll=1 and -conc switches causes KAP to generate the following code:


int main(  ) 
 
{ 
    double x[800][5000]; 
    int row; 
    int col; 
    float time1; 
    float time2; 
    int _Kii1; 
    int _Kii2; 
 
    csettime_( 1000 ); 
    time1 = ctimec_(  ); 
 
 
    #pragma omp parallel shared(x) private(_Kii1,_Kii2) 
      { 
 
    #pragma omp for nowait 
        for (_Kii1 = 0;_Kii1<=799;_Kii1++) { 
           for (_Kii2 = 0;_Kii2<=4999;_Kii2++) { 
              x[_Kii1][_Kii2] = sin(-((double)(_Kii1)))+sin(-((double)(_Kii1)) ); 
           } 
        } 
 
      } 
      time2 = ctimec_( ); 
      printf("time:%f\n",time1 - time2 ); 
    } 

KAP does not generate parallel code if you use the -noconcurrentize command-line switch.

5.2.3 #pragma _KAP serial

The #pragma _KAP serial assertion forces the loop immediately following it to be serial, and restricts optimization by forcing all enclosing loops to be serial also. Inner loops and other loops inside the same enclosing loop nest, but not enclosing the serial loop, may be optimized. KAP always honors this assertion.

5.3 Inlining and IPA Directives

The -inline_... and -ipa_... directives control manual inlining and IPA. See Chapter 6 for a more complete description.

The -inline_... and -ipa_... directives let you manually select which functions to inline or interprocedure-analyze at which call sites. If these directives appear with a name list, all occurrences of the named functions will be inlined/analyzed, if possible, in all references within the scope of the directive. If a directive appears without a list of functions, all function references are eligible.

The no forms turn off inlining and IPA of the named functions.

The routine and global scopes can be terminated by the corresponding no directives. Likewise, -noinline directives can be terminated with the positive directive.

Enabled pragmas override the -inline , -ipa , -inline_depth ,
-inline_looplevel , and -ipa_looplevel command-line switches. You can use them in addition to, or in place of, command-line controlled, inlining/IPA.

Note

An -inline or -ipa command-line switch must be specified for the corresponding directive to be enabled. The -inline_manual or -ipa_manual switch will enable the corresponding directive without activating the automatic selection algorithms. See the description of the -..._manual command-line switches in Chapter 4 or Chapter 6 for more information.

5.4 Parallel Processing Directive

The following directive is available in the multiprocessor version of KAP:


#pragma _KAP minconcurrent(<integer>) 

Executing a loop in parallel incurs overhead that varies with different systems. If a loop has little work, the overhead required to set up parallel execution may make the loop execute more slowly than it executes serially. The minconcurrent switch sets the level of work in a loop above which KAP should execute the loop in parallel. The higher the minconcurrent value, the more iterations and/or statements the loop body must have to run in parallel.

Specifying #pragma _KAP minconcurrent(0) tells KAP to parallelize all the following loops in the program unit, regardless of the loop bounds and the work in the loop. The range of values for this directive is 0 to 999999 .


Previous Next Contents Index