Sun Studio 12 Update 1:OpenMP API 用户指南

第 6 章 自动确定变量的作用域

在 OpenMP 并行区域中声明变量的作用域属性称为确定作用域。通常,如果将变量的作用域确定为 SHARED,则所有线程共享该变量的一个副本。如果将变量的作用域确定为 PRIVATE,则每个线程各有一份该变量副本。OpenMP 拥有丰富的数据环境。除了 SHAREDPRIVATE 之外,还可以将变量的作用域声明为 FIRSTPRIVATELASTPRIVATEREDUCTIONTHREADPRIVATE

OpenMP 要求用户声明在并行区域中使用的每个变量的作用域。这是一个单调乏味、容易出错的过程,并且公认是使用 OpenMP 将程序并行化的过程中最艰难的部分。

Sun Studio C、C++ 和 Fortran 95 编译器提供了自动确定作用域的功能。这些编译器可以分析并行区域的执行和同步模式,并基于一组作用域确定规则自动确定变量的作用域。

6.1 自动作用域数据范围子句

自动确定数据作用域子句是 Sun 对 OpenMP 规范的扩展。通过使用以下两种子句之一,用户可以指定要自动确定作用域的变量。

6.1.1 __auto 子句

语法:

__auto(list-of-variables)

并行构造中的 __auto 子句可指示编译器自动确定构造中已命名变量的作用域。(请注意 auto 前面的两个下划线)。

__auto 子句可以出现在 PARALLELPARALLEL DO/forPARALLEL SECTIONS 中或 Fortran 95 的 PARALLEL WORKSHARE 指令中。

如果在 __auto 子句中指定了变量,则不能在其他任何数据作用域子句中指定该变量。

6.1.2 default(__auto) 子句

并行构造中的 default(__auto) 子句可指示编译器自动确定构造中引用的所有未在任何数据作用域子句中显式确定作用域的变量的作用域。

default(__auto) 子句可以出现在 PARALLELPARALLEL DO/forPARALLEL SECTIONS 中或 Fortran 95 的 PARALLEL WORKSHARE 指令中。

6.2 作用域规则

在自动确定作用域的情况下,编译器应用以下规则来确定并行区域中变量的作用域。

这些规则并不适用于由 OpenMP 规范隐式确定作用域的变量,如工作共享 DO 循环或 FOR 循环的循环索引变量。

6.2.1 标量变量的作用域规则

6.2.2 数组的作用域规则

6.3 关于自动作用域的通用注释

在自动确定没有隐式作用域的变量的作用域时,编译器将根据上述规则按给定顺序 S1–S3(如果变量为标量)以及上述规则 A1(如果变量为数组)检查变量的使用情况。如果符合某个规则,编译器将按照匹配的规则确定变量的作用域。如果不符合某个规则,编译器将尝试使用下一个规则。如果编译器找不到匹配项,它将放弃确定该变量的作用域的尝试,并将该变量的作用域确定为 SHARED,然后像指定了 IF (.FALSE.)if(0) 子句一样,将绑定并行区域序列化。

作用域的自动确定失败的原因有两个。一个原因是使用的变量不匹配任何规则。第二个原因是源代码对于编译器来说过于复杂,因而无法执行全面的分析。函数调用、复杂的数组下标、内存别名和用户实现的同步都是常见原因。(请参见6.5 当前实现的已知限制。)

6.3.1 Fortran 95 的自动确定作用域规则:

对于 Fortran,如果由 __autodefault(__auto) 子句自动确定某个变量的作用域,并且该变量具有根据 OpenMP 规范预先确定的作用域,则编译器将根据该预先确定的作用域来确定变量的作用域。

对于 Fortran,下列变量具有预先确定的作用域:

6.3.2 C/C++ 的自动确定作用域规则:

对于 C/C++,如果由 __autodefault(__auto) 子句自动确定某个变量的作用域,并且该变量具有根据 OpenMP 规范预先确定的作用域,则编译器将根据该预先确定的作用域来确定变量的作用域。

对于 C/C++,下列变量具有预先确定的作用域:

C 和 C++ 中的自动确定作用域仅适用于基本数据类型: 整型、浮点型和指针。如果用户指定了要自动确定作用域的结构变量或类变量,则编译器会将该变量的作用域确定为 shared,并且封闭并行区域将由单个线程执行。

6.4 检查自动作用域的结果

使用编译器注释可检查自动确定作用域的结果,并确定是否因自动确定作用域失败而导致将并行区域序列化。

使用 -g 调试选项编译时,编译器将生成行内注释。可以使用 er_src 命令查看这个生成的注释,如下所示。(er_src 命令作为 Sun Studio 软件的一部分提供;有关更多信息,请参见 er_src(1) 手册页或 Sun Studio 性能分析器手册。)

使用 -xvpara 选项进行编译是一个良好的开端。如果自动确定作用域失败,将输出警告消息(如下所示)。


示例 6–1 使用 -vpara 进行编译


%cat t.f
      INTEGER X(100), Y(100), I, T
C$OMP PARALLEL DO DEFAULT(__AUTO)
      DO I=1, 100
         T = Y(I)
         CALL FOO(X)
         X(I) = T*T
      END DO
C$OMP END PARALLEL DO
      END
%f95 -xopenmp -xO3 -vpara -c t.f
"t.f", line 2: Warning: parallel region will be executed 
   by a single thread because the autoscoping 
   of following variables failed - x

使用 f95-vparacc-xvpara 进行编译。(CC 中尚未实现此选项。)


示例 6–2 使用编译器注释


%cat t.f
      INTEGER X(100), Y(100), I, T
C$OMP PARALLEL DO DEFAULT(__AUTO)
      DO I=1, 100
         T = Y(I)
         X(I) = T*T
      END DO
C$OMP END PARALLEL DO
      END

%f95 -xopenmp -xO3 -g -c t.f
%er_src t.o
Source file: ./t.f
Object file: ./ot.o
Load Object: ./t.o

     1. INTEGER X(100), Y(100), I, T

Source OpenMP region below has tag R1
Variables autoscoped as SHARED in R1: x, y
Variables autoscoped as PRIVATE in R1: t, i
Private variables in R1: i, t
Shared variables in R1: y, x
     2. C$OMP PARALLEL DO DEFAULT(__AUTO)
       <Function: _$d1A2.MAIN_>
Source loop below has tag L1
L1 parallelized by explicit user directive
L1 parallel loop-body code placed in function _$d1A2.MAIN_ along with 0
inner loops
Copy in M-function of loop below has tag L2
L2 scheduled with steady-state cycle count = 3
L2 unrolled 4 times
L2 has 0 loads, 0 stores, 2 prefetches, 0 FPadds, 0 FPmuls, and 0 FPdivs
per iteration
L2 has 1 int-loads, 1 int-stores, 4 alu-ops, 1 muls, 0 int-divs and 1
shifts per iteration
     3. DO I=1, 100
     4. T = Y(I)
     5. X(I) = T*T
     6. END DO
     7. C$OMP END PARALLEL DO
     8. END

接下来,使用一个更复杂的示例来解释自动作用域规则的应用方式。


示例 6–3 更复杂的示例


 1.      REAL FUNCTION FOO (N, X, Y)
 2.      INTEGER       N, I
 3.      REAL          X(*), Y(*)
 4.      REAL          W, MM, M
 5.
 6.      W = 0.0
 7.
 8. C$OMP PARALLEL DEFAULT(__AUTO)
 9.
10. C$OMP SINGLE
11.       M = 0.0
12. C$OMP END SINGLE
13.
14.       MM = 0.0
15.
16. C$OMP DO
17.       DO I = 1, N
18.          T = X(I)
19.          Y(I) = T
20.          IF (MM .GT. T) THEN
21.             W = W + T
22.             MM = T
23.          END IF
24.       END DO
25. C$OMP END DO
26.
27. C$OMP CRITICAL
28.       IF ( MM .GT. M ) THEN
29.          M = MM
30.       END IF
31. C$OMP END CRITICAL
32.
33. C$OMP END PARALLEL
34.
35.      FOO = W - M
36.
37.      RETURN
38.      END

函数 FOO() 包含一个并行区域,该并行区域包含一个 SINGLE 构造、一个工作共享 DO 构造和一个 CRITICAL 构造。如果我们忽略所有 OpenMP 并行构造,则并行区域中的代码所执行的操作如下:

  1. 将数组 X 中的值复制到数组 Y

  2. 查找 X 中的最大正数值,并将其存储在 M

  3. X 的一些元素的值累加到变量 W 中。

让我们看一下编译器如何使用上述规则来查找并行区域中变量的相应作用域。

在并行区域中使用下列变量:INMMTWMXY。编译器将确定以下内容。

6.5 当前实现的已知限制

以下是当前 Sun Studio Fortran 95 编译器中已知的自动确定作用域限制。