Oracle Solaris Studio 12.2:OpenMP API 用户指南

第 7 章 作用域检查

自动作用域可以帮助程序员决定如何确定变量的作用域。但是,对于一些复杂程序,自动作用域可能不会成功,或者无法实现程序员期望的结果。错误确定作用域可能引发许多不引人注意但很严重的问题。例如,将某些变量的作用域错误地确定为 SHARED 可能会导致数据争用;将变量错误地专有化可能会在构造之外为变量使用未定义的值。

Solaris Studio C、C++ 和 Fortran 编译器提供了一个编译时作用域检查功能,编译器可以通过该功能来确定 OpenMP 程序中的变量是否正确确定了作用域。

根据编译器的功能,作用域检查可以发现数据争用、不适当专有化、变量归约等潜在问题以及其他作用域问题。在作用域检查期间,编译器会对程序员指定的数据共享属性、编译器确定的隐式数据共享属性和自动作用域结果进行检查。

7.1 使用作用域检查功能

要启用作用域检查,应使用 -xvpara-xopenmp 选项在优化级别 -xO3 或更高级别上编译 OpenMP 程序。如果只使用 -xopenmp=noopt 编译该程序,作用域检查将不起作用。如果优化级别低于 -xO3,编译器将发出警告消息,且不执行任何作用域检查。

在作用域检查期间,编译器将检查所有 OpenMP 构造。如果确定有些变量的作用域时引发问题,编译器会发出警告消息,有时还会建议使用正确的数据共享属性子句。

例如:


示例 7–1 作用域检查


% cat t.c

#include <omp.h>
#include <string.h>

int main()
{
  int g[100], b, i;

  memset(g, 0, sizeof(int)*100);

  #pragma omp parallel for shared(b)
  for (i = 0; i < 100; i++)
  {
    b += g[i];
  }

  return 0;
}

%  cc -xopenmp -xO3 -xvpara source1.c
"source1.c", line 10: Warning: inappropriate scoping
         variable 'b' may be scoped inappropriately as 'shared'
         . write at line 13 and write at line 13 may cause data race

"source1.c", line 10: Warning: inappropriate scoping
         variable 'b' may be scoped inappropriately as 'shared'
         . write at line 13 and read at line 13 may cause data race

如果优化级别低于 -xO3,编译器将不进行作用域检查:


%  cc -xopenmp=noopt  -xvpara source1.c
 "source1.c", line 10: Warning: Scope checking under vpara compiler 
option is supported with optimization level -xO3 or higher.
 Compile with a higher optimization level to enable this feature

更复杂的示例:


示例 7–2 source2


% cat source2.c

#include <omp.h>

int main()
{
  int g[100];
  int r=0, a=1, b, i;

  #pragma omp parallel for private(a) lastprivate(i) reduction(+:r)
  for (i = 0; i < 100; i++)
  {
    g[i] = a;
    b = b + g[i];
    r = r * g[i];
  }

  a = b;
  return 0;
}

% cc -xopenmp -xO3 -xvpara source2.c
"source2.c", line 8: Warning: inappropriate scoping
        variable 'r' may be scoped inappropriately as 'reduction'
        . reference at line 13 may not be a reduction of the specified type

"source2.c", line 8: Warning: inappropriate scoping
        variable 'a' may be scoped inappropriately as 'private'
        . read at line 11 may be undefined
        . consider 'firstprivate'

"source2.c", line 8: Warning: inappropriate scoping
        variable 'i' may be scoped inappropriately as 'lastprivate'
        . value defined inside the parallel construct is not used outside
        . consider 'private'

"source2.c", line 8: Warning: inappropriate scoping
        variable 'b' may be scoped inappropriately as 'shared'
        . write at line 12 and write at line 12 may cause data race

"source2.c", line 8: Warning: inappropriate scoping
        variable 'b' may be scoped inappropriately as 'shared'
        . write at line 12 and read at line 12 may cause data race

上述虚构示例显示了作用域检查可以检测到的一些典型作用域错误。

  1. r 被指定为归约变量,其操作为 +,但实际上操作应为 *

  2. a 的作用域显式确定为 PRIVATE。由于 PRIVATE 变量没有初始值,因此第 11 行中对 a 的引用可能会显示一些乱码。编译器会指出此问题,并建议程序员考虑将 a 的作用域确定为 FIRSTPRIVATE

  3. 变量 i 是循环索引变量。有些情况下,如果在循环后使用循环索引值,程序员可能希望将其指定为 LASTPRIVATE。但在以上示例中不是这样;在循环后根本没有引用 i。编译器会发出警告,并建议程序员将 i 的作用域确定为 PRIVATE。使用 PRIVATE 而不是 LASTPRIVATE 可以提高性能。

  4. 程序员不为变量 b 显式指定数据共享属性。根据 OpenMP 3.0 规范第 79 页的第 27-28 行,将 b 的作用域隐式确定为 SHARED。但是,将 b 的作用域确定为 SHARED 将导致数据争用。b 的正确数据共享属性应为 REDUCTION

7.2 限制