自动作用域可以帮助程序员决定如何确定变量的作用域。但是,对于一些复杂程序,自动作用域可能不会成功,或者无法实现程序员期望的结果。错误确定作用域可能引发许多不引人注意但很严重的问题。例如,将某些变量的作用域错误地确定为 SHARED 可能会导致数据争用;将变量错误地专有化可能会在构造之外为变量使用未定义的值。
Solaris Studio C、C++ 和 Fortran 编译器提供了一个编译时作用域检查功能,编译器可以通过该功能来确定 OpenMP 程序中的变量是否正确确定了作用域。
根据编译器的功能,作用域检查可以发现数据争用、不适当专有化、变量归约等潜在问题以及其他作用域问题。在作用域检查期间,编译器会对程序员指定的数据共享属性、编译器确定的隐式数据共享属性和自动作用域结果进行检查。
要启用作用域检查,应使用 -xvpara 和 -xopenmp 选项在优化级别 -xO3 或更高级别上编译 OpenMP 程序。如果只使用 -xopenmp=noopt 编译该程序,作用域检查将不起作用。如果优化级别低于 -xO3,编译器将发出警告消息,且不执行任何作用域检查。
在作用域检查期间,编译器将检查所有 OpenMP 构造。如果确定有些变量的作用域时引发问题,编译器会发出警告消息,有时还会建议使用正确的数据共享属性子句。
例如:
% 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 |
更复杂的示例:
% 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 |
上述虚构示例显示了作用域检查可以检测到的一些典型作用域错误。
r 被指定为归约变量,其操作为 +,但实际上操作应为 *。
a 的作用域显式确定为 PRIVATE。由于 PRIVATE 变量没有初始值,因此第 11 行中对 a 的引用可能会显示一些乱码。编译器会指出此问题,并建议程序员考虑将 a 的作用域确定为 FIRSTPRIVATE。
变量 i 是循环索引变量。有些情况下,如果在循环后使用循环索引值,程序员可能希望将其指定为 LASTPRIVATE。但在以上示例中不是这样;在循环后根本没有引用 i。编译器会发出警告,并建议程序员将 i 的作用域确定为 PRIVATE。使用 PRIVATE 而不是 LASTPRIVATE 可以提高性能。
程序员不为变量 b 显式指定数据共享属性。根据 OpenMP 3.0 规范第 79 页的第 27-28 行,将 b 的作用域隐式确定为 SHARED。但是,将 b 的作用域确定为 SHARED 将导致数据争用。b 的正确数据共享属性应为 REDUCTION。
如上所述,作用域检查仅适用于优化级别 -xO3 或更高级别。如果只使用 -xopenmp=noopt 来编译程序,作用域检查将不起作用。
在数据争用分析中,只能识别和使用通过 OpenMP 同步指令(如 BARRIER 和 MASTER)指定的同步。不识别用户实现的同步,如忙等待。