本附录介绍关于使用线程分析器的一些提示信息。
关于在收集实验之前编译应用程序的提示:
生成应用程序二进制代码时,使用 -g 编译器选项。这样,线程分析器就可以报告数据争用的行号信息。
生成应用程序二进制代码时,使用低于 -xO3 的优化级别进行编译。编译器转换可能会误报行号信息并使结果难以理解。
线程分析器会插入A.2.3 内存分配 API中所示的内存分配例程。链接到内存分配库的归档版本可能会导致误报数据争用。
关于在收集实验之前校验应用程序以检测数据争用的提示:
如果从编译器收到一条错误消息,指出编译器选项 -xinstrument=datarace 非法,则表明您使用的是不支持线程分析器的旧版 Sun Studio 编译器。可以通过键入命令 cc -Version 检查所使用的编译器的版本。最早支持线程分析器的版本日期为 2006 年 6 月。
如果没有校验二进制代码以进行数据争用检测,collect -r race 命令会发出一条如下所示的警告:
% collect -r races a.out WARNING: Target `a.out' is not instrumented for datarace detection; reported datarace data may be misleading |
通过使用 nm 命令以及查找对 tha 例程的调用,可以确定是否校验了二进制代码以进行数据争用检测。如果显示名称以 __tha_ 开头的例程,则表明已校验二进制代码。示例输出如下所示。
源代码级别校验:
% cc -xopenmp -g -xinstrument=datarace source.c % nm a.out | grep __tha_ [71] | 135408| 0|FUNC |GLOB |0 |UNDEF |__tha_get_stack_id [53] | 135468| 0|FUNC |GLOB |0 |UNDEF |__tha_src_read_w_frame [61] | 135444| 0|FUNC |GLOB |0 |UNDEF |__tha_src_write_w_frame |
二进制代码级别校验:
% cc -xopenmp -g source.c % discover -i datarace -o a.out.i a.out % nm a.out.i | grep __tha_ [88] | 0| 0|NOTY |GLOB |0 |UNDEF |__tha_read_w_pc_frame [49] | 0| 0|NOTY |GLOB |0 |UNDEF |__tha_write_w_pc_frame |
要使用 discover,必须使用编译器优化标志 (-xO1, -xO2, -xO3, -xO4, -xO5) 之一编译输入的二进制代码。编译器必须是不低于 Oracle Solaris Studio 12 Update 1 的发行版。操作系统至少必须为 Oracle Solaris 10 Update 5 或 OpenSolaris 版本 snv_70。否则,可能会收到一条如下所示的警告。
% discover -i datarace -o a.out.i a.out discover (warning): a.out has no annotations. Results may be incomplete. See discover documentation for compiler flag/OS recommendation |
如果使用编译器选项 -xbinopt=prepare 编译了二进制代码,可能也可以在基于 SPARC 的系统中运行的早期 Solaris 版本上使用 discover 工具。有关该编译器选项的信息,请参见 cc(1)、CC(1) 或 f95(1) 手册页。
关于运行校验后的应用程序以检测数据争用和死锁的提示。
确保 Solaris 系统已安装所有必需的修补程序。collect 命令可列出所有缺少的必需修补程序。对于 OpenMP 应用程序,需要安装最新版本的 libmtsk.so。
如果从 collect 收到一条错误消息,指出无法识别 -r race 或 -r deadlock 参数,则表明您使用的是不支持线程分析器的旧版 collect。可以通过键入 collect -Version 命令检查所使用的 collect 的版本。最早支持线程分析器的版本日期为 2006 年 6 月。
校验可能会导致执行时间显著延长(高达 50 倍甚至更多),还会导致内存消耗增加。可以尝试通过使用较小的数据集缩短执行时间。也可以尝试通过增加线程数缩短执行时间。
为检测数据争用,请确保应用程序当前使用的线程不止一个。对于 OpenMP,您可以指定线程数,方法是将环境变量 OMP_NUM_THREADS 设置为所需的线程数并将环境变量 OMP_DYNAMIC 设置为 FALSE。
关于报告数据争用的提示:
线程分析器检测运行时的数据争用。应用程序的运行时行为取决于使用的输入数据集和操作系统调度。请通过使用不同的线程数以及使用不同的输入数据集,在 collect 下运行应用程序。还应使用单个数据集重复进行实验,以最大限度地提高该工具检测到数据争用的可能性。
线程分析器检测从单个进程产生的不同线程之间的数据争用。它不检测不同进程之间的数据争用。
线程分析器不报告数据争用中访问的变量的名称。但是,若要确定变量的名称,可以检查发生两次数据争用访问的源代码行,再找出这些源代码行上写入的变量和读取的变量。
在某些情况下,线程分析器可能会报告实际在程序中并未发生的数据争用。这些数据争用称为误报。使用由用户实现的同步时或在线程之间回收内存时,通常会发生这种情况。例如,如果代码中包含实现自旋锁的手编程序集,线程分析器将无法识别这些同步点。通过在源代码中插入对线程分析器用户 API 的调用,可让线程分析器知道有关用户自定义的同步的情况。有关更多信息,请参见2.5 误报和附录 A。
使用源代码级别校验报告的数据争用与使用二进制代码级别校验报告的数据争用可能不相同。在二进制代码级别校验中,缺省情况下会在打开共享库时校验这些共享库(无论它们是静态链接到程序中的,还是通过 dlopen() 动态打开的)。在源代码级别校验中,仅当使用 -instrument=datarace 编译库的源代码时,才会对库进行校验。