要启用作用域检查,请使用 -xvpara 和 -xopenmp 选项编译 OpenMP 程序。优化级别应为 -xO3 或更高。如果只使用 -xopenmp=noopt 来编译程序,作用域检查将不起作用。如果优化级别低于 -xO3,编译器将发出警告消息,且不执行任何作用域检查。
在作用域检查期间,编译器将检查所有 OpenMP 构造。如果某些变量的作用域会引发问题,编译器将发出警告消息,有时还会建议使用正确的数据共享属性子句。例如,编译器检测到下列情形时会发出警告消息:
循环是使用 OpenMP 指令并行化的,而这些指令中的不同循环迭代之间存在数据依赖性
例如,指定了要在并行区域中共享的变量但访问并行区域中的该变量可能会导致数据争用,或者指定了要在并行区域中专用的变量但分配给并行区域中该变量的值在并行区域后使用,这样 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
以下示例说明了如何报告潜在的作用域错误。
示例 25 作用域错误示例% 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 是循环索引变量。有些情况下,如果在 parallel for 循环后使用循环索引值,程序员可能希望将其指定为 LASTPRIVATE。但在上述示例中,在循环后根本没有引用 i。编译器会发出警告,并建议将 i 的作用域确定为 private。使用 private 而不是 lastprivate 可以提高性能。
未显式指定变量 b 的任何数据共享属性。根据 OpenMP 规范,b 的作用域将隐式确定为 shared。但是,将 b 的作用域确定为 shared 将导致数据争用。b 的正确数据共享属性应为 reduction。