性能分析的第一个阶段是数据收集。本章介绍了进行数据收集的要求、数据的存储位置、如何收集数据以及如何管理数据收集。有关数据本身的更多信息,请参见第 2 章,性能数据。
本章包含以下主题。
几乎可以为使用任何选项编译的程序收集和分析数据,但有些选项会影响能够在性能分析器中收集或查看的内容。以下几个小节介绍了在编译和链接程序时应考虑的问题。
要查看带注释的“源代码”和“反汇编”分析中的源代码以及“行”分析中的源代码行,就必须使用 -g 编译器选项(对于 C++ 来说为用于启用前端内联的 -g0)编译感兴趣的源文件,以生成调试符号信息。调试符号信息的格式可以是 DWARF2 或 stabs,由 -xdebugformat=(dwarf|stabs) 指定。缺省的调试格式是 dwarf。
要使用允许使用数据空间分析的调试信息准备编译对象(当前仅适用于 SPARC® 处理器),请通过指定 -xhwcprof -xdebugformat=dwarf 和任何级别的优化来进行编译。(目前,这种功能在未经过优化的情况下无法使用。)要查看“数据对象”分析中的程序数据对象,也要添加 -g(对于 C++ 来说为 -g0)以获取全部符号信息。
用 DWARF 格式的调试符号生成的可执行文件和库会自动包括每个要素目标文件调试符号的副本。如果用 stabs 格式的调试符号生成的可执行文件和库与 -xs 选项(该选项将 stabs 符号保留在各个目标文件及可执行文件中)相链接,那么所生成的可执行文件和库中也会包括每个要素目标文件的调试符号。当您需要移动或删除目标文件时,包括这些信息尤为重要。使用可执行文件和库本身中的所有调试符号,可以更容易地将实验和与程序相关的文件移至新位置。
编译程序时,必须使用 -dn 和 -Bstatic 编译器选项打开动态链接。如果试图收集完全静态链接的程序的数据,则收集器会列显一条错误消息并且不收集数据。出现此错误的原因在于,当您运行收集器时,该收集器库也会像其他库一样动态装入。
请不要静态链接任何系统库。如果您执行了静态链接,则可能无法收集任何种类的跟踪数据。另外,请不要链接到收集器库 libcollector.so。
如果使用在某一级别打开的优化来编译程序,编译器就可以重新安排执行顺序,这样就无须严格按照程序中行的顺序来执行程序。性能分析器可以分析在优化后的代码中收集的实验,但它在反汇编级别所显示的数据通常很难与初始源代码行相关联。此外,如果编译器执行尾部调用优化,则调用序列可能与预期的序列不同。有关更多信息,请参见尾部调用优化。
对于大多数程序来说,您不必为数据收集和分析做任何特殊的准备。如果程序执行下列任一操作,则应当阅读下面的一个或多个小节:
安装信号处理程序
显式动态装入系统库
动态编译函数
创建要分析的后续进程
使用异步 I/O 库
直接使用分析计时器或硬件计数器 API
调用 setuid(2) 或执行 setuid 文件
此外,如果要控制程序中的数据收集,还应当阅读相关小节。
malloc、valloc 和 alloca (C/C++)
new (C++)
堆栈局部变量 (Fortran)
MALLOC 和 MALLOC64 (Fortran)
必须小心确保程序不依赖于动态分配的内存的初始内容,除非内存分配方法明确地说明要设置初始值:例如,比较 malloc(3C) 手册页中对 calloc 和 malloc 的描述。
偶尔,使用动态分配的内存的程序似乎可以单独地正常运行,但是启用性能数据收集之后就会失败。症状可能包括意外的浮点行为、段故障或特定于应用程序的错误消息。
如果应用程序单独运行时未初始化的内存偶然设置为良性值,但应用程序与性能数据收集工具一起运行时未初始化的内存被设置为其他值,则会出现这种行为。发生这种情况时,问题不出在性能工具上。依赖于动态分配的内存内容的任何应用程序都具有潜在的错误:除非明确说明使用其他方法,否则操作系统将为动态分配的内存随机提供任意内容。即使目前操作系统会始终将动态分配的内存设置为某个值,但是将来在使用操作系统的后续修订版或将程序移植到其他操作系统时,这些潜在的错误会引起意外的行为。
下列工具可以帮助您找到这些潜在的错误:
f95 -xcheck=init_local
有关更多信息,请参见《Fortran 用户指南》或 f95(1) 手册页
lint 实用程序
有关更多信息,请参见《C 用户指南》或 lint(1) 手册页
dbx 下的运行时检查
有关更多信息,请参见《使用 dbx 调试程序》手册或 dbx(1) 手册页。
Rational Purify
收集器插入各种系统库的函数,以收集跟踪数据并确保数据收集的完整性。下面的列表描述了收集器插入库函数调用的情况。
收集同步等待跟踪数据。收集器插入 Solaris 线程库 libthread.so(在 Solaris 9 OS 上)和 Solaris C 库 libc.so(在 Solaris 10 OS 上)中的函数。
收集堆跟踪数据。收集器插入函数 malloc、realloc、memalign 和 free。这些函数的版本可以在 C 标准库 libc.so 和其他库(如 libmalloc.so 和 libmtmalloc.so)中找到。
确保时钟数据的完整性。收集器插入 setitimer 并阻止程序使用分析计时器。
确保硬件计数器数据的完整性。收集器插入硬件计数器库 libcpc.so 中的函数并阻止程序使用计数器。程序对该库中函数的调用的返回值是 -1。
针对后续进程启用数据收集。收集器插入函数 fork(2)、fork1(2)、vfork(2)、fork(3F)、system(3C)、system(3F)、sh(3F)、popen(3C) 和 exec(2) 及其变体。对 vfork 的调用已在内部被替换为对 fork1 的调用。这些插入仅适用于 collect 命令。
保证由收集器处理 SIGPROF 和 SIGEMT 信号。收集器插入 sigaction 以确保其信号处理程序是这些信号的主信号处理程序。
在某些情况下,插入不会成功:
将程序与任何包含被插入的函数的库进行静态链接。
将 dbx 附加到运行中的未预装入收集器库的应用程序。
动态装入其中一个库并通过只在该库中搜索来解析符号。
收集器插入失败可能会导致性能数据丢失或无效。
收集器使用以下两个信号来收集分析数据:SIGPROF(所有实验)和 SIGEMT(仅限硬件计数器实验)。收集器为其中的每个信号安装一个信号处理程序。该信号处理程序截获并处理它自己的信号,但是会将其他信号传递到所安装的其他信号处理程序。如果程序为这些信号安装其自己的信号处理程序,则收集器会将其信号处理程序作为主处理程序重新安装,以保证性能数据的完整性。
collect 命令还可以将用户指定的信号用于暂停和恢复数据收集以及记录样本。尽管在安装用户处理程序时向实验中写入警告,但这些信号不受收集器保护。确保收集器对指定信号的使用与应用程序对相同信号的使用之间没有冲突是您的责任。
由收集器安装的信号处理程序会设置一个确保系统调用不被信号传送中断的标志。如果程序的信号处理程序将该标志设置为允许中断系统调用,则设置该标志可以更改程序的行为。在异步 I/O 库 libaio.so 中就有一个行为更改的重要示例,它将 SIGPROF 用于异步取消操作,并且中断系统调用。如果已安装收集器库 libcollector.so,则取消信号总是来得太迟,以至于无法取消异步 I/O 操作。
如果在未预装入收集器库和启用性能数据收集的情况下将 dbx 附加到进程,并且程序随后安装其自身的信号处理程序,则收集器不再重新安装其自身的信号处理程序。在这种情况下,程序的信号处理程序必须确保 SIGPROF 和 SIGEMT 信号被传递,以便性能数据不丢失。如果程序的信号处理程序中断系统调用,那么程序行为和分析行为都将与预装入收集器库时不同。
由于动态装入器实施了一定的限制,因此将难以使用 setuid(2) 和收集性能数据。如果您的程序调用 setuid或执行 setuid 文件,则收集器可能无法写入实验文件,原因是它缺少新用户 ID 的必需权限。
此问题可以通过以下方法来解决:确保 umask 的设置可将写入权限授予进程在运行时所使用的任何 UID 或 GID。针对实验,这些 ID 必须具有写入权限。
如果要控制程序中的数据收集,收集器共享库 libcollector.so 包含了一些可以使用的 API 函数。这些函数是用 C 编写的,还提供了一个 Fortran 接口。C 接口和 Fortran 接口都是在由库所提供的头文件中定义的。
API 函数定义如下所示。
void collector_sample(char *name); void collector_pause(void); void collector_resume(void); void collector_thread_pause(unsigned int t); void collector_thread_resume(unsigned int t); void collector_terminate_expt(void); |
CollectorAPI 类为 JavaTM 程序提供了类似的功能,Java 接口中对其进行了介绍。
可通过两种方法来访问 C 和 C++ 接口:
第一种方法是包括 collectorAPI.h 并使用 -lcollectorAPI(包含用于检查底层 libcollector.so API 函数是否存在的真正的函数)进行链接。
这种方法要求与 API 库相链接,可在所有情况下使用。如果没有活动的实验,API 调用将被忽略。
第二种方法是包括 libcollector.h(包含用于检查基础 libcollector.so API 函数是否存在的宏)。
当用于主可执行文件以及数据收集功能随程序一起启动时,该方法有效。当 dbx 用于附加到进程或者从进程针对其执行 dlopen 的共享库中使用时,该方法不总是有效。提供第二种方法的目的仅在于实现向后兼容,建议不要将它用于任何其他目的。
请勿使用 -lcollector 链接任何语言的程序,否则,收集器可能会出现不可预知的行为。
Fortran API libfcollector.h 文件定义了库的 Fortran 接口。要使用该库,必须使用 -lcollectorAPI 链接应用程序。(还提供了该库的替代名称 -lfcollector,目的在于实现向后兼容性。)除动态函数、线程暂停和恢复调用等功能外,Fortran API 提供了与 C 和 C++ API 相同的功能。
要使用 Fortran 的 API 函数,请插入下面的语句:
include "libfcollector.h" |
请勿使用 -lcollector 链接任何语言的程序,否则,收集器可能会出现不可预知的行为。
使用以下语句导入 CollectorAPI 类并访问 Java API。但是请注意,必须使用指向 / installation_directory/lib/collector.jar 的类路径来调用应用程序,其中 installation-directory 是 Sun Studio 软件的安装目录。
import com.sun.forte.st.collector.CollectorAPI; |
Java CollectorAPI 方法的定义如下所示:
CollectorAPI.sample(String name) CollectorAPI.pause() CollectorAPI.resume() CollectorAPI.threadPause(Thread thread) CollectorAPI.threadResume(Thread thread) CollectorAPI.terminate() |
除动态函数 API 之外,Java API 包含与 C 和 C++ API 相同的函数。
C 头文件 libcollector.h 包含一些宏,这些宏的作用是如果当时未在收集数据,则跳过对真正的 API 函数的调用。在这种情况下,不动态装入函数。但是,由于在某些情况下这些宏不能很好地运行,所以使用这些宏会有风险。使用 collectorAPI.h 较为安全,因为它不使用宏,而是直接引用函数。
如果正在收集性能数据,则 Fortran API 子例程会调用 C API 函数,否则这些子例程将返回。检查的开销很低,不会对程序性能产生太大的影响。
如本章稍后所述,要收集性能数据就必须使用收集器运行您的程序。插入对 API 函数的调用不会启用数据收集功能。
如果要在多线程程序中使用 API 函数,应当确保它们只由一个线程调用。除 collector_thread_pause() 和 collector_thread_resume() 之外,API 函数执行适用于进程(而不是单独的线程)的操作。如果每个线程都调用 API 函数,则记录的数据可能会与预期不同。例如,如果一个线程在其他线程到达程序中的同一点之前调用了 collector_pause() 或 collector_terminate_expt(),则会针对所有线程暂停或终止收集,从而丢失那些正在执行 API 调用之前代码的线程的数据。要在单独的线程级别控制数据收集,请使用 collector_thread_pause() 和 collector_thread_resume() 函数。可通过两种方法来使用这些函数:一种是使用一个主线程为所有线程(包括其自身)执行调用;另一种是让每个线程只执行它自己的调用。其他任何用法都可能产生不可预知的结果。
对 API 函数的描述如下所示。
C 和 C++:collector_sample(char *name)
Fortran: collector_sample(string name)
Java:CollectorAPI.sample(String name)
记录样本包并用指定的名称或字符串标记该样本。该标签显示在性能分析器的“事件”选项卡中。Fortran 参数 string 的类型为 character。
样本点包含进程(而不是单独的线程)的数据。在多线程应用程序中,如果在 collector_sample() API 函数记录样本时发生另一个调用,则该函数可确保只写入一个样本。所记录的样本数可能会少于发出该调用的线程数。
性能分析器不对由不同机制记录的样本进行区分。如果只想查看 API 调用所记录的样本,则应当在记录性能数据时关闭所有其他抽样模式。
C、C++ 和 Fortran:collector_pause()
Java:CollectorAPI.pause()
停止将特定于事件的数据写入实验。实验将保持打开状态,并将继续写入全局数据。如果没有活动的实验或者已经停止记录数据,则该调用将被忽略。该函数停止写入所有特定于事件的数据,即使它是由 collector_thread_resume() 函数针对特定线程启用的也是如此。
C、C++ 和 Fortran:collector_resume()
Java:CollectorAPI.resume()
在调用 collector_pause() 之后恢复将特定于事件的数据写入实验。如果没用活动的实验或数据记录功能处于活动状态,则该调用将被忽略。
仅限 C 和 C++:collector_thread_pause(unsigned int t)
Java:CollectorAPI.threadPause(Thread t)
停止将特定于事件的数据从参数列表中所指定的线程写入实验。对于 C/C++ 程序,参数 t 是 POSIX 线程标识符;对于 Java 程序,该参数是 Java 线程。如果实验已经终止、没有活动的实验或已经关闭对该线程数据的写入功能,则该调用将被忽略。即使全局启用了数据写入功能,该函数也会停止写入指定线程的数据。缺省情况下,对单独线程的数据记录功能处于打开状态。
仅限 C 和 C++:collector_thread_resume(unsigned int t)
Java:CollectorAPI.threadResume(Thread t)
恢复将参数列表中指定线程的特定于事件的数据写入实验。对于 C/C++ 程序,参数 t 是 POSIX 线程标识符;对于 Java 程序,该参数是 Java 线程。如果实验已经终止、没有活动的实验或对该线程数据的写入功能已经打开,则该调用将被忽略。只有在全局启用了数据写入功能,而且还针对该线程启用了数据写入功能时,才可以将数据写入实验中。
C、C++ 和 Fortran:collector_terminate_expt()
Java:CollectorAPI.terminate
如果 C 或 C++ 程序向程序的数据空间动态编译函数,而且您希望在性能分析器中查看动态函数或模块的数据,那么,您必须向收集器提供信息。该信息由对收集器 API 函数的调用传递。API 函数的定义如下所示。
void collector_func_load(char *name, char *alias, char *sourcename, void *vaddr, int size, int lntsize, Lineno *lntable); void collector_func_unload(void *vaddr); |
您不必将这些 API 函数用于由 Java HotSpotTM 虚拟机编译的 Java 方法,该虚拟机使用的是另一个接口。Java 接口提供已编译到收集器的方法的名称。您可以查看 Java 编译方法的函数数据和带注释的反汇编列表,但不能查看带注释的源代码列表。
将有关动态编译的函数的信息传递到收集器,以便在实验中进行记录。下表对参数列表进行了描述。
表 3–1 collector_func_load() 的参数列表
参数 |
定义 |
---|---|
name |
性能工具所使用的动态编译函数的名称。该名称不必是函数的实际名称。虽然该名称不应包含嵌入的空格或引号字符,但无须遵循通常的函数命名约定。 |
alias |
用于描述函数的任意字符串。它可以是 NULL。它不经过任何方式的解释,可以包含嵌入的空格。它显示在分析器的“摘要”选项卡中。它可用于指示函数的内容或动态构造函数的原因。 |
sourcename |
构造函数时所在源文件的路径。它可以是 NULL。该源文件用于带注释的源代码列表。 |
vaddr |
函数的装入地址。 |
size |
以字节为单位的函数大小。 |
lntsize |
对行号表中条目数量的计数。如果未提供行号信息,则计数应为零。 |
lntable |
包含 lntsize 条目的表,其中每个条目都是一对整数。第一个整数是偏移量,第二个整数是行号。在一个条目的偏移量和下一个条目中所给出的偏移量之间的所有指令都归属于在第一个条目中提供的行号。偏移量必须按数字升序列出,但行号的顺序可以是任意的。如果 lntable 为 NULL,则没有可用的函数源代码列表,不过反汇编列表是可用的。 |
通知收集器位于地址 vaddr 的动态函数已卸载。
本节描述了数据收集的限制,这些限制是由硬件、操作系统、程序的运行方式或收集器本身造成的。
对同时收集不同类型的数据来说,没有任何限制:您可以在收集某种数据类型的同时收集任何其他数据类型。
用于分析的分析间隔最小值和时钟精度取决于特定的操作环境。最大值设置为 1 秒。分析间隔值将向下舍入到最接近的时钟精度的整数倍。可以通过键入不带参数的 collect 命令来查找最小值和最大值以及时钟精度。
基于时钟的分析记录当 SIGPROF 信号传递到目标时的数据。这将导致在处理该信号和展开调用栈时产生扩大。调用栈越深,信号越频繁,扩大越显著。在一定程度上,基于时钟的分析表现出一些失真,这是由程序中那些执行最深栈部分的显著扩大而导致的。
请尽可能不要将缺省值设置为一个精确的毫秒数,而是将其设置为稍大于或稍小于某个精确数(例如,10.007 毫秒或 0.997 毫秒),以免与系统时钟关联,从而避免数据失真。在 SPARC 平台上,可以按照同样的方式来设置定制值(在 Linux 平台上不能设置定制值)。
只有在已预装入收集器库 libcollector.so 的情况下,才可以从已在运行的程序中收集任何种类的跟踪数据。有关更多信息,请参见从正在运行的程序中收集跟踪数据。
跟踪数据使运行与被跟踪事件的数量成比例地扩大。如果完成了基于时钟的分析,则跟踪事件所引起的扩大将导致时钟数据失真。
硬件计数器溢出分析存在多种限制:
只能在具有硬件计数器且支持溢出分析的处理器上收集硬件计数器溢出数据。在其他系统中,硬件计数器溢出分析功能处于禁用状态。UltraSPARC® III 处理器系列之前的 UltraSPARC 处理器不支持硬件计数器溢出分析。
在 cpustat(1) 运行过程中无法收集系统的硬件计数器溢出数据,原因是 cpustat 控制了这些计数器,不允许用户进程使用它们。如果 cpustat 是在数据收集过程中启动的,则硬件计数器溢出分析将终止,而且会在实验中记录一条错误。
如果正在执行硬件计数器溢出分析, 则无法将自己代码中的硬件计数器与 libcpc(3) API 同时使用。如果调用不是来自收集器,则收集器将插入 libcpc 库函数并返回一个返回值 -1。您应当对程序进行适当编码,使其在无法访问硬件计数器时能够正常工作。如果未进行这样的编码,或者如果根调用了同样使用计数器的系统范围的工具,程序将在硬件计数器分析过程中失败。
如果您试图通过向进程附加 dbx 来在使用硬件计数器库的运行的程序上收集硬件计数器数据,则实验可能会被破坏。
要查看所有可用计数器的列表,请运行不带参数的 collect 命令。
硬件计数器溢出分析功能记录当 SIGEMT 传递到目标时的数据。这将导致在处理该信号和展开调用栈时产生扩大。与基于时钟的分析不同的是,对于某些硬件计数器,程序的不同部分可能会比其他部分更快速地生成事件并显示在该部分代码中的扩大。程序中快速生成这类事件的任何部分都可能会显著失真。类似地,某些事件可能会在一个线程中与其他线程不成比例地生成。
如果要在收集器所跟踪的所有后续进程中收集数据,就必须使用带有下列选项之一的 collect 命令:
-F all 选项导致收集器跟踪所有后续进程(包括那些因调用 system、popen 和 sh 而产生的进程)。
-F '=regexp' 选项允许在其名称或沿袭与指定的正则表达式相匹配的所有后续进程上收集数据。
有关 -F 选项的更多信息,请参 实验控制选项。
应当使用版本不低于 1.5.0_03 的 Java 2 Platform, Standard Edition (J2SE)。缺省情况下,collect 命令使用 Sun Studio 安装程序安装 J2SE 的路径(如果有)。可以通过设置 JDK_HOME 环境变量或 JAVA_PATH 环境变量来覆盖此缺省路径。收集器会验证它在这些环境变量中找到的 java 版本是否为 ELF 可执行文件,如果不是,则列显一条错误消息,指出所使用的环境变量以及已尝试使用的全路径名。
必须使用 collect 命令来收集数据,而不能使用 dbx collector 子命令或 IDE 的数据收集功能。
如果应用程序所创建的后续进程运行 JVM 软件,则不能对这些应用程序进行分析。
如果要使用 64 位 JVM 软件,则必须使用 -j on 标志并将 64 位 JVM 软件指定为目标。请不要使用 java -d64 在 64 位 JVM 软件中收集数据,否则收集不到任何数据。
Java 分析功能使用的 Java 虚拟机工具接口 (Java Virtual Machine Tool Interface, JVMTI) 可能会导致运行的失真和扩大。
对于基于时钟的分析和硬件计数器溢出分析,数据收集进程会对 JVM 软件进行各种调用,并使用信号处理程序处理分析事件。这些例程的开销和将实验写入磁盘的代价将扩大 Java 程序的运行时。这种扩大通常小于 10%。
对于同步跟踪,数据收集功能使用其他 JVMTI 事件,这将导致扩大(与应用程序中监视争用数量成比例)。
在应用程序的一次执行过程中所收集的数据称作实验。实验由存储在一个目录下的一组文件组成。实验的名称即目录的名称。
除记录实验数据以外,收集器还为程序所使用的装入对象创建自己的归档文件。这些归档文件包含装入对象中每个目标文件和函数的地址、大小和名称以及装入对象的地址和上次修改的时间戳。
缺省情况下,实验存储在当前目录中。如果该目录位于网络文件系统上,则存储数据所需的时间比在本地文件系统中长,而且可能会导致性能数据失真。如有可能,应始终尝试在本地文件系统中记录实验。可以在运行收集器时指定存储位置。
新实验的缺省名称为 test.1.er。后缀 .er 是必需的:如果您赋予的名称不具有该后缀,则系统会显示一条错误消息而且不接受该名称。
如果您选择使用格式为 experiment.n.er 的名称(其中,n 是正整数),则收集器会将后续实验名称中的 n 自动递增 1,例如,mytest.1.er 的后面是 mytest.2.er、mytest.3.er 等。如果实验已经存在,收集器也会递增 n,直到找到未使用的实验名称才停止递增 n。如果实验名称不含 n 且实验存在,则收集器会列显一条错误消息。
实验可按组收集。组在实验组文件中定义,缺省情况下该文件存储在当前目录中。实验组文件是纯文本文件,它具有特殊的标题行,并在随后的每一行中显示实验名称。实验组文件的缺省名称为 test.erg。如果名称不以 .erg 结尾,则系统会显示一条错误并且不接受该名称。创建实验组后,您使用该组名运行的所有实验都会添加到该组中。
可以通过创建首行为
#analyzer experiment group |
的纯文本文件并将实验名称添加到后续行来手动创建实验组文件。文件的名称必须以 .erg 结尾。
还可以通过使用带有 -g 参数的 collect 命令来创建实验组。
缺省实验名称与从 MPI 程序中收集的实验名称不同,MPI 程序会为每个 MPI 进程创建一个实验。缺省实验名称为 test.m.er,其中 m 是进程的 MPI 等级。如果指定了实验组 group.erg,则缺省实验名称为 group.m.er。如果指定了实验名称,则该名称会覆盖缺省值。有关更多信息,请参见从 MPI 程序收集数据。
后续进程的实验是沿袭命名的,如下所示。要形成后续进程的实验名称,可将下划线、代码字母和数字添加到其创建者实验名称的主干中。代码字母 f 表示派生,x 表示执行,c 表示组合。数字是派生或执行的索引(无论是否成功)。例如,如果创始进程的实验名称为 test.1.er,则在第三次调用 fork 时为子进程创建的实验为 test.1.er/_f3.er。如果子进程成功调用 exec,则新后续进程的实验名称为 test.1.er/_f3_x1.er。
如果要将实验移到其他计算机以便对其进行分析,则应了解分析对在其中记录实验的操作环境的依赖性。
归档文件包含计算函数级度量和显示时间线所必需的全部信息。但是,如果要查看带注释的源代码或带注释的反汇编代码,则必须能够访问与记录实验时所用装入对象或源文件相同的版本。
性能分析器在下列位置依次搜索源代码、对象和可执行文件,并在找到具有正确基本名称的文件时停止:
实验的归档目录。
当前的工作目录。
记录在可执行文件或编译对象中的绝对路径名。
可以从分析器 GUI 或通过使用 setpath 和 addpath 指令来更改搜索顺序或添加其他搜索目录。
为了确保能够看到程序的正确的带注释源代码和带注释反汇编代码,可以在移动或复制实验之前将源代码、目标文件和可执行文件复制到该实验中。如果您不想复制目标文件,则可以使用 -xs 来链接程序,以确保源代码行和文件位置上的信息插入可执行文件中。可以通过使用 collect 命令的 -A 选项或 dbx collector archive 命令将装入对象自动复制到实验中。
本节就如何对记录实验所需的磁盘空间量进行估计提供了一些指导。实验的大小直接取决于数据包的大小、记录数据包的速率、程序使用的 LWP 的数量和程序的执行时间。
数据包中包含特定于事件的数据和取决于程序结构(调用栈)的数据。取决于数据类型的数据量约为 50 到 100 个字节。调用栈数据由每个调用的返回地址组成,每个地址包含 4 个字节(在 64 位可执行文件中为 8 个字节)。记录了实验中的每个 LWP 的数据包。请注意,对于 Java 程序,有两个相关的调用栈:Java 调用栈和机器调用栈,因此将导致向磁盘中写入更多的数据。
记录分析数据包的速率由时钟数据的分析间隔和硬件计数器数据的溢出值来控制。但是,对于这些参数的选择也会因数据收集的开销而影响数据质量和程序性能的失真。这些参数的值越小,提供的统计信息越好,但开销也会越大。为了在获得较好统计信息和尽可能降低开销之间实现折衷,我们已经为分析间隔和溢出值精心选择了缺省值。值越小,数据越多。
对于一个具有 10 毫秒分析间隔和较小调用栈的基于时钟的分析实验,包的大小为 100 个字节,对于每个 LWP,记录数据的速率为 10 千字节/ 秒。对于溢出值为 1000000 以及在 750 MHz 处理器上收集有关 CPU 循环和执行指令数据的硬件计数器溢出分析实验,包的大小为 100 个字节,对于每个 LWP,记录数据的速率为 150 千字节/ 秒。调用栈深度为数百个调用的应用程序可以很轻松地以十倍的速率记录数据。
在估计实验大小时,还应当考虑归档文件所占用的磁盘空间,它通常是所要求的总磁盘空间的一小部分(请参见上一节)。如果您无法确定所需空间的大小,请尝试运行实验一小会儿。通过该测试,可以得到与数据收集时间无关的归档文件大小,然后对分析文件的大小进行放大以获得全长实验的估计大小。
除了分配磁盘空间之外,收集器还在内存中分配缓冲区,以便在将分析数据写入磁盘之前对其进行存储。目前无法指定这些缓冲区的大小。如果收集器用完了内存,请尝试减少所收集的数据量。
如果存储实验所需的估计空间大于可用空间,请考虑收集部分运行(而不是全部运行)的数据。要收集部分运行的数据,可以使用 collect 命令或 dbx collector 子命令,也可以在程序中插入对收集器 API 的调用。还可以对由 collect 命令或 dbx collector 子命令所收集的分析和跟踪数据总量进行限制。
性能分析器无法读取大于 2 GB 的性能数据。
可以通过多种方法在独立性能分析器或 IDE 的分析器窗口中收集性能数据:
在命令行上使用 collect 命令(请参见使用 collect 命令收集数据和 collect(1) 手册页)。collect 命令行工具的数据收集开销比 dbx 的开销小,因此该方法比其他方法要好。
使用性能分析器的“性能工具收集”对话框(请参见性能分析器联机帮助中的“使用性能工具收集器收集性能数据”)。
使用调试器中的“收集器”对话框(请参见性能分析器联机帮助中的“使用调试器收集性能数据”)。
在 dbx 命令行上使用 collector 命令(请参见使用 dbx collector 子命令收集数据以及 IDE 中“调试”联机帮助中的“collector 命令”)。
只有“性能工具收集”对话框和 collect 命令提供下列数据收集功能:
收集 Java 程序中的数据。如果尝试使用 IDE 调试器中的“收集器”对话框或者 dbx 中的 collector 命令收集 Java 程序中的数据,则收集的是 JVM 软件(而不是 Java 程序)的信息。
自动收集后续进程中的数据。
要从命令行使用 collect 命令运行收集器,请键入以下内容。
% collect collect-options program program-arguments |
其中,collect-options 是 collect 命令选项,program 是要收集其数据的程序的名称,program-arguments 是该程序的参数。
如果未提供 collect-options,则缺省情况下会打开分析间隔大约为 10 毫秒的基于时钟的分析。
要获取可用于分析的选项列表和所有硬件计数器的名称列表,请键入不带参数的 collect 命令。
% collect |
有关对硬件计数器列表的描述,请参见硬件计数器溢出分析数据。另请参见硬件计数器溢出分析的限制。
这些选项控制所收集数据的类型。有关对数据类型的介绍,请参见收集器收集何种数据。
如果未指定数据收集选项,则缺省值为 -p on,这会启用缺省分析间隔大约为 10 毫秒的基于时钟的分析。该缺省值由 -h 选项关闭,而不是由任何其他数据收集选项关闭。
如果您明确禁用了基于时钟的分析,而且未启用跟踪或硬件计数器溢出分析,则 collect 命令会列显一条警告消息,并且只收集全局数据。
off-关闭基于时钟的分析。
on-打开缺省分析间隔大约为 10 毫秒的基于时钟的分析。
lo[w]-打开分析间隔大约为 100 毫秒(低精度)的基于时钟的分析。
hi[gh]-打开分析间隔大约为 1 毫秒(高精度)的基于时钟的分析。有关启用高精度分析的信息,请参见基于时钟的分析的限制。
[+]value-打开基于时钟的分析并将其分析间隔设置为 value。value 的缺省单位为毫秒。可以将 value 指定为整数或浮点数。可以选择在数值后加后缀 m 来选择毫秒单位或者加 u 来选择微秒单位。该值应当是时钟精度的倍数。如果该值较大但不是精度的倍数,则会向下舍入。如果较小,则会列显一条警告消息并将其设置为时钟精度。
在 SPARC 平台上,可以像对硬件计数器分析那样在任何值前面添加 + 符号来启用基于时钟的数据空间分析。
collect 命令的缺省操作是收集基于时钟的分析数据。
收集硬件计数器溢出分析数据。计数器定义的数量与处理器有关。如果安装了 perfctr 修补程序(可以从 http://user.it.uu.se/~mikpe/linux/perfctr/2.6/perfctr-2.6.15.tar.gz 下载),则该选项当前在运行 Linux 操作系统的系统上是可用的。
计数器定义可以采用下列形式之一,具体取决于处理器是否支持硬件计数器的属性。
[+]counter_name[/register_number][,interval]
[+]counter_name[~ attribute_1=value_1]...[~attribute_n=value_n][/register_number][,interval]
特定于处理器的 counter_name 可以为下列名称之一:
周知的(有别名的)计数器名称
由 cputrack(1) 使用的原始(内部)名称。如果计数器可以使用任一事件寄存器,则可以通过向内部名称附加 /0 或 /1 来指定将要使用的事件寄存器。
如果指定了多个计数器,则它们必须使用不同的寄存器。如果它们未使用不同的寄存器,则 collect 命令会列显一条错误消息并退出。某些计数器可在任一寄存器上计数。
要获取可用计数器的列表,请在终端窗口中键入不带参数的 collect。硬件计数器列表一节提供了对计数器列表的介绍。
如果硬件计数器对其计数的事件与内存访问有关,则可以在计数器名称前添加 + 符号,以针对引起计数器溢出的指令打开对其真实程序计数器地址 (PC) 的搜索。这种回溯功能适用于 SPARC 处理器,并且仅适用于类型为 load、store 或 load-store 的计数器。如果搜索成功,则所引用的虚拟 PC、物理 PC 和有效地址将存储在事件数据包中。
在某些处理器上,可以将多个属性选项与一个硬件计数器关联。如果某个处理器支持多个属性选项,则运行不带参数的 collect 命令会列出计数器定义(包括属性名)。可以使用十进制或十六进制格式来指定属性值。
间隔(溢出值)是事件计数的数量,在达到该数量时,硬件计数器将溢出并且将记录溢出事件。间隔可以设置为下列值之一:
on 或空字符串-缺省溢出值,可以通过键入不带参数的 collect 来确定。
hi[gh]-所选计数器的高精度值,大约比缺省溢出值短十倍。之所以还支持缩写 h,是为了与以前的软件发行版兼容。
lo[w]-所选计数器的低精度值,大约比缺省溢出值长十倍。
interval-特定的溢出值,必须是正整数,可以采用十进制格式,也可以采用十六进制格式。
缺省值是为每个计数器预定义的正常阈值,它出现在计数器列表中。另请参见硬件计数器溢出分析的限制。
如果在使用 -h 选项时未明确指定 -p 选项,则基于时钟的分析功能将处于关闭状态。要同时收集硬件计数器数据和基于时钟的数据,必须同时指定 -h 选项和 -p 选项。
all-启用具有零阈值的同步等待跟踪。该选项强制记录所有同步事件。
calibrate-启用同步等待跟踪并在运行时通过校准来设置阈值。(与 on 等效。)
off-禁用同步等待跟踪。
on-启用具有缺省阈值的同步等待跟踪,这将在运行时通过校准来设置缺省阈值。(与 calibrate 等效。)
不记录 Java 监视器的同步等待跟踪数据。
on-打开对堆分配和堆释放请求的跟踪。
off-关闭堆跟踪。
缺省情况下,堆跟踪功能处于关闭状态。对于 Java 程序,不支持堆跟踪;如果指定堆跟踪,将被视为错误。
on-打开对 MPI 调用的跟踪。
off-关闭对 MPI 调用的跟踪。
缺省情况下,MPI 跟踪功能处于关闭状态。
有关其调用被跟踪的 MPI 函数以及从跟踪数据中所计算的度量的更多信息,请参见MPI 跟踪数据。
缺省情况下,启用间隔为 1 秒的定期抽样功能。
记录计数数据(仅用于 SPARC 处理器)。
此功能要求您安装 Binary Interface Tool (BIT),它是 Sun Studio 12(可从 http://cooltools.sunsource.net/ 获取)中一个很不错的附加工具。BIT 是用来度量 SPARC 二进制代码的性能或测试套件适用范围的工具。
option 的允许值包括:
on-打开对函数和指令计数数据的收集。如果可执行文件及其静态链接的任何共享对象是使用 -xbinopt=prepare 标志编译的,则会记录这些可执行文件和共享对象的数据。虽然是静态链接但是未使用 -xbinopt=prepare 标志编译的任何其他共享对象将不包含在数据中。同样,动态打开的任何共享对象将不包含在数据中。可以在性能分析器的“指令-频率”选项卡中或使用 er_print ifreq 命令查看数据。
static-在目标可执行文件中的每个指令以及所有静态链接的共享对象都刚好执行一次的情况下,将生成一个实验。和 -c on 选项一样,-c static 选项也要求使用 -xbinopt=prepare 标志编译可执行文件和共享对象。
为线程分析器收集数据争用检测或死锁检测数据。允许的值包括:
on-打开线程分析器的数据争用检测数据
off-关闭线程分析器数据
all-打开所有线程分析器数据
race-打开线程分析器的数据争用检测数据
deadlock-收集死锁和潜在死锁数据
dtN-打开特定的线程分析器数据类型,这些数据类型由 dt* 参数指定。
有关 collect -r 命令和线程分析器的更多信息,请参见《Sun Studio 12:线程分析器用户指南》和 tha.1 手册页。
控制是否应当记录后续进程的数据。option 的允许值包括:
on-仅针对由函数 fork(及其变体)和 exec(及其变体)创建的后续进程记录实验。
all-针对所有后续进程记录实验。
off-不针对后续进程记录实验。
=regexp-针对其名称或沿袭与指定的正则表达式匹配的所有后续进程记录实验。
如果您指定 -F on 选项,收集器将跟踪通过调用函数 fork(2)、fork1(2)、fork(3F)、vfork(2) 和 exec(2) 及其变体而创建的进程。对 vfork 的调用已在内部被替换为对 fork1 的调用。
如果您指定 -F all 选项,收集器将跟踪所有后续进程,其中包括那些通过调用 system(3C)、system(3F)、sh(3F) 和 popen(3C) 以及类似函数而创建的后续进程以及与它们相关的后续进程。
如果您指定 -F '= regexp' 选项,收集器将跟踪其名称或沿袭与指定的正则表达式相匹配的所有后续进程。有关正则表达式的信息,请参见 regexp(5) 手册页。
当您在后续进程上收集数据时,收集器会针对创始实验中的每个后续进程打开一个新实验。这些新实验是通过向实验后缀添加一个下划线、一个字母和一个数字来命名的,如下所示:
字母可以是 "f"(表示派生)、"x"(表示执行)或 "c"(表示任何其他后续进程)。
数字是派生或执行(无论是否成功)或其他调用的索引。
例如,如果初始进程的实验名称是 test.1.er,则由它的第三个派生创建的子进程的实验是 test.1.er/_f3.er。如果该子进程针对新映像执行 exec 操作,则相应的实验名称为 test.1.er/_f3_x1.er。如果该子进程使用 popen 调用创建另一个进程,则实验名称为 test.1.er/_f3_x1_c1.er。
分析器和 er_print 实用程序在读取创始实验后会自动读取后续进程的实验,但不会选择将后续进程的实验用于数据显示。
要从命令行中选择要显示的数据,请明确指定 er_print 或 analyzer 的路径名。所指定的路径必须包含创始实验的名称以及创始目录中后续实验的名称。
例如,要查看 test.1.er 实验的第三个派生的数据,需要指定以下内容:
er_print test.1.er/_f3.er
analyzer test.1.er/_f3.er
或者,可以使用感兴趣的后续实验的显式名称来准备实验组文件。
要在分析器中检查后续进程,请装入创始实验并从“视图”菜单中选择“过滤数据”。此时将显示一个实验列表,其中只有创始实验处于选中状态。取消选中初始实验并选中感兴趣的后续实验。
如果在后续进程正在被跟踪时创始进程退出,则可能会继续从后续进程中收集数据。创始实验目录会相应地继续变大。
当目标程序是 JVM 时,启用 Java 分析。option 的允许值包括:
on-识别由 Java HotSpot 虚拟机编译的方法并尝试记录 Java 调用栈。
off-不尝试识别由 Java HotSpot 虚拟机编译的方法。
path-记录安装在指定 path 中的 JVM 的分析数据。
如果要收集 .class 文件或 .jar 文件中的数据,则不需要 -j 选项,但前提是 java 可执行文件的路径在 JDK_HOME 环境变量或 JAVA_PATH 环境变量中。随后可以在 collect 命令行上将目标 program 指定为具有或不具有扩展名的 .class 文件或 .jar 文件。
如果无法在 JDK_HOME 或 JAVA_PATH 环境变量中定义java 的路径,或者要禁用对 Java HotSpot 虚拟机所编译的方法的识别,则可以使用 -j 选项。如果使用该选项,则在 collect 命令行上指定的 program 必须是版本不低于 1.5_03 的 Java 虚拟机。collect 命令验证 program 是否为 JVM 以及是否为 ELF 可执行文件;如果不是,collect 命令会列显一条错误消息。
如果要使用 64 位 JVM 收集数据,则不能将 java 的 -d64 选项用于 32 位 JVM,否则将收集不到任何数据;相反,您必须在 collect 命令的 program 参数中或本节提供的两个环境变量之一中指定 64 位 JVM 的路径。
指定要传递到用于分析的 JVM 的单个参数。如果您指定了 -J 选项但未指定 Java 分析,则会生成一个错误并且不运行实验。该参数作为单个参数传递到 JVM。如果需要多个参数,请不要使用 -J 选项,而是明确指定 JVM 的路径,使用 -j on,并在 collect 命令行上在 JVM 路径的后面添加 JVM 的参数。
可以通过全信号名、不带开始的几个字母 SIG 的信号名或信号编号来指定信号。请不要使用程序所使用的信号或会终止执行的信号。建议的信号为 SIGUSR1 和 SIGUSR2。可通过 kill 命令将信号传递到进程。
如果同时使用 -l 和 -y 选项,则必须针对每个选项使用不同的信号。
如果您使用该选项而程序具有其自己的信号处理程序,则应当确保使用 -l 指定的信号会传递到收集器的信号处理程序,而不是被截获或忽略。
有关信号的更多信息,请参见 signal(3HEAD) 手册页。
指定数据收集的时间范围。
可以将 duration 指定为单个数字(可以选择添加 m 或 s 后缀)以指示实验在该时间(单位为分钟或秒)终止。缺省情况下,持续时间以秒为单位。也可以将 duration 指定为用连字符分隔的两个这样的数字,这会导致数据收集暂停,直到经过第一个时间之后才开始收集数据。当到达第二个时间时,数据收集终止。如果第二个数字为零,则在初次暂停之后收集数据,直到该程序运行结束。即使该实验已经终止,也允许目标进程运行至结束。
在从 exec 系统调用退出时使目标进程停止,以便允许调试器附加到目标进程。如果将 dbx 附加到目标进程,请使用 dbx 命令 ignore PROF 和 ignore EMT 来确保收集信号传递到 collect 命令。
控制对包含名为 signal 的信号的数据的记录。无论何时将信号传递到进程,它都在暂停状态(在此期间不记录任何数据)和记录状态(在此期间记录数据)之间切换。无论切换状态如何,都将始终记录样本点。
可以通过全信号名、不带开始的几个字母 SIG 的信号名或信号编号来指定信号。请不要使用程序所使用的信号或会终止执行的信号。建议的信号为 SIGUSR1 和 SIGUSR2。可通过 kill(1) 命令将信号传递到进程。
如果同时使用 -l 和 -y 选项,则必须针对每个选项使用不同的信号。
使用 -y 选项时,如果已提供可选的 r 参数,则收集器将在记录状态下启动,否则将在暂停状态下启动。如果未使用 -y 选项,则收集器将在记录状态下启动。
如果您使用该选项而程序具有其自己的信号处理程序,则应当确保使用 -y 指定的信号会传递到收集器的信号处理程序,而不是被截获或忽略。
有关信号的更多信息,请参见 signal(3HEAD) 手册页。
使用 experiment_name 作为要记录的实验的名称。experiment_name 字符串必须以字符串 ".er" 结尾;否则 collect 实用程序会列显一条错误消息并退出。
将实验置于 directory-name 目录中。此选项仅适用于个别实验,而不适用于实验组。如果该目录不存在,则 collect 实用程序会列显一则错误消息并退出。如果使用 -g 选项指定了某个组,则该组文件也将写入 directory-name 中。
使实验成为实验组 group-name 的一部分。如果 group-name 不以 .erg 结尾,则 collect 实用程序会列显一条错误消息并退出。如果该组存在,则会将实验添加到该组中。如果 group-name 不是绝对路径并且使用 -d 指定了一个目录,则实验组将被置于 directory-name 目录中,否则,将被置于当前目录中。
控制是否应将目标进程所使用的装入对象归档或复制到已记录的实验中。option 的允许值包括:
off-不将装入对象归档到实验中。
on-将装入对象归档到实验中。
copy-将装入对象复制和归档到实验中。
如果您希望将实验从记录的位置复制到另一台计算机,或者从另一台计算机读取实验,请指定 -A copy。使用该选项不会将任何源文件或目标文件复制到实验中。您应当确保在要将实验复制到的计算机上可以访问这些文件。
将所记录的分析数据量限制在 size 兆字节。该限制适用于基于时钟的分析数据量、硬件计数器溢出分析数据量和同步等待跟踪数据量之和,但不适用于样本点。该限制只是近似值,可以被超出。
当达到该限制时,不再记录分析数据,但实验会一直保持打开状态,直到目标进程终止。如果启用了定期抽样,则会继续写入样本点。
记录的数据量的缺省限制为 2000 MB。选择该限制的原因是性能分析器无法处理所含数据量大于 2 GB 的实验。要去掉该限制,请将 size 设置为 unlimited 或 none。
将 collect 本身的所有输出附加到名称 file,但是不重定向所产生的目标的输出。如果该文件设置为 /dev/null,则禁止 collect 的所有输出(包括任何错误消息)。
将注释放在实验的 notes 文件中。最多可以提供十个 -C 选项。该 notes 文件的内容会置于实验标题的前面。
不运行目标,但列显在运行目标时要生成的实验的详细信息。此选项是模拟运行选项。
在终端窗口中显示性能分析器自述文件的文本版本。如果未找到自述文件,则列显一条警告。不再检查任何参数,也不执行进一步的处理。
列显 collect 命令的当前版本。不再检查任何参数,也不执行进一步的处理。
列显 collect 命令的当前版本和正在运行的实验的详细信息。
可以将 -P pid 选项与 collect 实用程序一起使用来连接具有指定 PID 的进程并从该进程收集数据。collect 命令的其他选项被转换为 dbx 脚本,系统会调用该脚本来收集数据。只能收集基于时钟的分析数据(-p 选项)和硬件计数器溢出分析数据(-h 选项)。不支持跟踪数据。
如果在使用 -h 选项时未明确指定 -p 选项,则基于时钟的分析将处于关闭状态。要同时收集硬件计数器数据和基于时钟的数据,必须同时指定 -h 选项和 -p 选项。
确定程序的进程 ID (process ID, PID)。
如果从命令行启动程序并将其放置在后台中,则其 PID 将由 shell 列显到标准输出中;否则,您可以通过键入以下内容来确定程序的 PID。
% ps -ef | grep program-name |
使用 collect 命令启用对该进程的数据收集功能并设置任何可选参数。
% collect -P pid collect-options |
数据收集选项中对收集器选项进行了说明。有关基于时钟的分析的信息,请参见-p option。有关硬件时钟分析的信息,请参见-h option。
本节介绍如何从 dbx 运行收集器,然后介绍可以与 dbx 中的 collector 命令一起使用的每个子命令。
% dbx program |
使用 collector 命令启用数据收集,选择数据类型并设置任何可选参数。
(dbx) collector subcommand |
要获取可用 collector 子命令的列表,请键入:
(dbx) help collector |
必须针对每个子命令都使用一个 collector 命令。
设置要使用的任何 dbx选项并运行该程序。
如果提供的子命令不正确,则会列显一条警告消息并忽略该子命令。下面是 collector 子命令的完整列表。
下列子命令控制收集器所收集的数据的类型。如果实验处于活动状态,则这些子命令将被忽略并显示一条警告。
控制对基于时钟的分析数据的收集。option 的允许值包括:
on-启用缺省分析间隔为 10 毫秒的基于时钟的分析。
off-禁用基于时钟的分析。
timer interval-设置分析间隔。interval 的允许值包括:
on-使用大约为 10 毫秒的缺省分析间隔。
lo[w]-使用大约为 100 毫秒的低精度分析间隔。
hi[gh]-使用大约为 1 毫秒的高精度分析间隔。有关启用高精度分析的信息,请参见基于时钟的分析的限制。
value-将分析间隔设置为 value。value 的缺省单位是毫秒。可以将 value 指定为整数或浮点数。可以选择在数值后添加后缀 m 来选择毫秒单位,也可以添加 u 来选择微秒单位。该值应当是时钟精度的倍数。如果该值大于时钟精度但不是其倍数,则向下舍入。如果该值小于时钟精度,则将其设置为时钟精度。在以上两种情况下均列显警告消息。
缺省设置大约为 10 毫秒。
缺省情况下收集器收集基于时钟的分析数据,除非使用 hwprofile 子命令打开对硬件计数器溢出分析数据的收集。
控制对硬件计数器溢出分析数据的收集。如果您尝试在不支持硬件计数器溢出分析的系统中启用它,则 dbx 会返回一条警告消息,而且该命令将被忽略。option 的允许值包括:
on-打开硬件计数器溢出分析。缺省操作是收集具有正常溢出值的 cycles 计数器的数据。
off-关闭硬件计数器溢出分析。
list-返回可用计数器的列表。有关对该列表的描述,请参见硬件计数器列表。如果系统不支持硬件计数器溢出分析,则 dbx 会返回一条警告消息。
counter counter_definition... [, counter_definition]-计数器定义可以采用下列形式之一,具体取决于处理器是否支持硬件计数器的属性。
[+] counter_name[/ register_number][,interval ]
[+]counter_name[~ attribute_1=value_1]...[~attribute_n =value_n][/ register_number][,interval ]
选择硬件计数器 name,并将其溢出值设置为 interval;也可以选择其他硬件计数器名称并将其溢出值设置为指定的间隔。溢出值可以为下列值之一:
on 或空字符串-缺省溢出值,可以通过键入不带参数的 collect 来确定。
hi[gh]-所选计数器的高精度值,大约比缺省溢出值短十倍。之所以还支持缩写 h,是为了与以前的软件发行版兼容。
lo[w]-所选计数器的低精度值,大约比缺省溢出值长十倍。
interval-特定的溢出值,必须是正整数,可以采用十进制格式,也可以采用十六进制格式。
如果指定了多个计数器,则它们必须使用不同的寄存器。否则,将列显一条警告消息,而且该命令将被忽略。
如果硬件计数器对其计数的事件与内存访问有关,则可以在计数器名称前放置 + 符号,以便对导致计数器溢出的指令的真实 PC 进行搜索。如果搜索成功,则 PC 和所引用的有效地址将被存储在事件数据包中。
缺省情况下,收集器不收集硬件计数器溢出分析数据。如果硬件计数器溢出分析处于启用状态,而且尚未提供 profile 命令,则基于时钟的分析将处于关闭状态。
另请参见硬件计数器溢出分析的限制。
on-启用堆跟踪。
off-禁用堆跟踪。
缺省情况下,收集器不收集堆跟踪数据。
控制对 MPI 跟踪数据的收集。option 的允许值包括:
on-启用对 MPI 调用的跟踪。
off-禁用对 MPI 调用的跟踪。
缺省情况下,收集器不收集 MPI 跟踪数据。
为线程分析器收集数据争用检测或死锁检测数据。允许的值包括:
on-打开线程分析器的数据争用检测数据
off-关闭线程分析器数据
all-打开所有线程分析器数据
race-打开线程分析器的数据争用检测数据
deadlock-收集死锁和潜在死锁数据
dtN-打开特定的线程分析器数据类型,这些数据类型由 dt* 参数指定。
有关线程分析器的更多信息,请参见《Sun Studio 12:线程分析器用户指南》和 tha.1 手册页。
缺省情况下,启用抽样间隔 value 为 1 秒的定期抽样。
控制当 dbx 停止目标进程时对样本的记录。关键字的含义如下所示:
on-在 dbx 每次停止目标进程时记录样本。
off-在 dbx 停止目标进程时不记录样本。
缺省情况下,在 dbx 停止目标进程时记录样本。
禁用数据收集功能。如果进程正在运行而且正在收集数据,该子命令将终止实验并禁用数据收集功能。如果进程正在运行而且数据收集功能处于禁用状态,则该子命令将被忽略并显示一条警告。如果没有任何进程在运行,则该子命令将针对后续运行禁用数据收集功能。
启用数据收集功能。如果进程正在运行,但数据收集功能处于禁用状态,则该子命令将启用数据收集功能并启动新的实验。如果进程正在运行,而且数据收集功能处于启用状态,则该子命令将被忽略并显示一条警告。如果没有任何进程在运行,则该子命令将针对后续运行启用数据收集功能。
您可以在任何进程执行期间根据需要启用和禁用数据收集功能任意次数。每次启用数据收集功能时,都会创建一个新实验。
暂停数据收集,但使实验保持打开状态。收集器暂停时不记录样本点。在暂停之前会生成一个样本,在恢复之后会立即生成另一个样本。如果已暂停数据收集功能,则该子命令将被忽略。
在发出 pause 之后恢复数据收集。如果正在收集数据,则该子命令将被忽略。
记录具有标签 name 的样本包。该标签显示在性能分析器的“事件”标签中。
下列子命令定义实验的存储选项。如果实验处于活动状态,则这些子命令将被忽略并显示一条警告。
on-对装入对象进行正常归档
off-不对装入对象进行归档
copy-除正常归档之外,还将装入对象复制到实验中
如果打算将实验移到另一台计算机上,或者从另一台计算机上读取实验,则应当启用对装入对象的复制。如果实验处于活动状态,则该命令将被忽略并显示一条警告。该命令不会将源文件或目标文件复制到实验中。
将所记录的分析数据量限制在 value 兆字节。该限制适用于基于时钟的分析数据量、硬件计数器溢出分析数据量和同步等待跟踪数据量之和,但不适用于样本点。该限制只是近似值,可以被超出。
当达到该限制时,不再记录分析数据,但实验会一直保持打开状态,而且会继续记录样本点。
记录的数据量的缺省限制为 2000 MB。选择该限制的原因是性能分析器无法处理所含数据量大于 2 GB 的实验。要去掉该限制,请将 value 设置为 unlimited 或 none。
控制实验的存储位置。如果实验处于活动状态,则该命令将被忽略并显示一条警告。option 的允许值包括:
directory directory-name-设置用来存储实验和实验组的目录。如果该目录不存在,则该子命令将被忽略并显示一条警告。
experiment experiment-name-设置实验的名称。如果实验名称不以 .er 结尾,则该子命令将被忽略并显示一条警告。有关实验名称以及收集器如何对其进行处理的更多信息,请参见数据的存储位置。
group group-name-设置实验组的名称。如果实验组名称不以 .erg 结尾,则该子命令将被忽略并显示一条警告。如果该组已经存在,则将实验添加到该组中。如果目录名是用 store directory 子命令设置的,而且组名不是绝对路径,则组名以目录名为前缀。
显示每个收集器控件的当前设置。
使用收集器可以从正在运行的进程中收集数据。如果进程已受 dbx 的控制,则可以暂停该进程并使用前几节中所描述的方法来启用数据收集。
如果进程不受 dbx 的控制,则可以使用 collect –P pid 命令从正在运行的进程中收集数据,如使用 collect 实用程序从正在运行的进程中收集数据中所述。您还可以向其附加 dbx,收集性能数据,然后从该进程分离并使进程继续运行。如果要为选定的后续进程收集性能数据,则必须将 dbx 附加到每个进程。
确定程序的进程 ID (process ID, PID)。
如果从命令行启动程序并将其放置在后台中,则其 PID 将由 shell 列显到标准输出中;否则,您可以通过键入以下内容来确定程序的 PID。
% ps -ef | grep program-name |
附加到该进程。
从 dbx 键入以下内容。
(dbx) attach program-name pid |
如果 dbx 尚未运行,请键入以下内容。
% dbx program-name pid |
附加到正在运行的进程会使该进程暂停。
有关附加到进程的更多信息,请参见《Sun Studio 12:使用 dbx 调试程序》。
启动数据收集功能。
在 dbx 中,使用 collector 命令来设置数据收集参数,使用 cont 命令来恢复执行进程。
从进程中分离。
在完成对数据的收集之后,暂停该程序并从 dbx 中分离该进程。
在 dbx 中键入以下内容。
(dbx) detach |
如果要收集任何种类的跟踪数据,则必须在运行程序之前预装入收集器库 libcollector.so,因为该库提供了能使数据收集发生的真正函数的包装。此外,收集器还将包装函数添加到其他系统库调用中,以保证性能数据的完整性。如果未预装入收集器库,则不能插入这些包装函数。有关收集器如何插入系统库函数的更多信息,请参见使用系统库。
要预装入 libcollector.so,必须使用环境变量同时设置库的名称和库的路径,如下表中所示。使用环境变量 LD_PRELOAD 设置库的名称。使用环境变量 LD_LIBRARY_PATH、LD_LIBRARY_PATH_32 或 LD_LIBRARY_PATH_64 设置库的路径。如果未定义 _32 和 _64 变量,则使用 LD_LIBRARY_PATH。如果已经定义了这些环境变量,则向其中添加新值。
表 3–2 用来预装入 libcollector.so 库的环境变量设置
环境变量 |
值 |
---|---|
LD_PRELOAD |
libcollector.so |
LD_LIBRARY_PATH |
/opt/SUNWspro/prod/lib/dbxruntime |
LD_LIBRARY_PATH_32 |
/opt/SUNWspro/prod/lib/dbxruntime |
LD_LIBRARY_PATH_64 |
/opt/SUNWspro/prod/lib/v9/dbxruntime |
LD_LIBRARY_PATH_64 |
/opt/SUNWspro/prod/lib/amd64/dbxruntime |
如果 Sun Studio 软件未安装在 /opt/SUNWspro 中,请向系统管理员咨询正确的路径。可以在 LD_PRELOAD 中设置全路径,但是,当使用 SPARC V9 64 位体系结构时,这样做会使问题复杂化。
运行后删除 LD_PRELOAD 和 LD_LIBRARY_PATH 设置,以便它们对于从同一个 shell 启动的其他程序无效。
如果要从已在运行的 MPI 程序收集数据,则必须将一个单独的 dbx 实例附加到每个进程并针对每个进程启用收集器。在将 dbx 附加到 MPI 作业中的多个进程时,每个进程将被停止并在不同的时间重新启动。时间差异可能会更改 MPI 进程间的交互并影响所收集的性能数据。为了使该问题带来的影响最小,一种解决方案是使用 pstop(1) 命令停止所有进程。但是,在将 dbx 附加到这些进程后,必须从 dbx 重新启动这些进程,重新启动进程时会发生时间延迟,这会影响 MPI 进程的同步。另请参见从 MPI 程序收集数据。
收集器可以从那些使用消息传递接口 (Message Passing Interface, MPI) 库的多进程程序中收集性能数据。Open MPI 库包含在 Sun HPC ClusterToolsTM 7 软件中,Sun MPI 库包含在 ClusterTools 5 和 ClusterTools 6 软件中。可从 http://www.sun.com/software/products/clustertools/ 获取 ClusterTools 软件。
要在使用 ClusterTools 7 时启动并行作业,请使用 Open Run-Time Environment (ORTE) 命令 mpirun。
要在使用 ClusterTools 5 或 ClusterTools 6 时启动并行作业,请使用 Sun Cluster Runtime Environment (CRE) 命令 mprun。
有关更多信息,请参见 Sun HPC ClusterTools 文档。
有关 MPI 和 MPI 标准的信息,请参见 MPI Web 站点 http://www.mcs.anl.gov/mpi/。有关 Open MPI 的更多信息,请参见 Web 站点 http://www.open-mpi.org/。
由于 MPI 和收集器的实现方式,每个 MPI 进程记录一个单独的实验。每个实验必须具有唯一的名称。实验的存储位置和方式取决于 MPI 作业可用的文件系统类型。有关存储实验的问题将在下一个小节存储 MPI 实验中讨论。
要从 MPI 作业收集数据,可以在 MPI 下运行 collect 命令,也可以在 MPI 下启动 dbx 并使用 dbx collector 子命令。这些任务将在在 MPI 下运行 collect 命令和通过在 MPI 下启动 dbx 来收集数据中讨论。
由于多进程环境比较复杂,因此从 MPI 程序收集性能数据时应当注意一些有关存储 MPI 实验的问题。这些问题涉及到数据收集和存储的效率以及实验的命名。有关命名实验(包括 MPI 实验)的信息,请参见数据的存储位置。
用来收集性能数据的每个 MPI 进程都创建其自己的实验。当某个 MPI 进程创建实验时,它会锁定实验目录。所有其他 MPI 进程都必须等到该锁定被释放之后才能使用此目录。因此,如果将实验存储到所有 MPI 进程都可以访问的文件系统,则会按顺序创建这些实验;但是如果将实验存储到每个 MPI 进程的本地文件系统,则会并行创建这些实验。
如果允许收集器创建实验名称,则可以避免与实验名称和存储位置有关的问题。请参见下一节缺省的 MPI 实验名称。
如果未指定实验名称,则使用缺省的实验名称。收集器使用 MPI 等级以标准格式 experiment.m.er 构造实验名称,其中 m 是 MPI 等级。如果指定了实验组,则主干 experiment 为实验组名称的主干,否则主干为 test。无论使用的是公共文件系统还是本地文件系统,实验名称都是唯一的。因此,如果使用本地文件系统记录实验并将其复制到公共文件系统,则复制这些实验并重新构造任何实验组文件时不必重命名实验。在多数情况下,您应当允许收集器创建实验名称,以确保名称在所有文件系统的范围内是唯一的。
如果您将实验存储在公共文件系统上,并以标准格式 experiment. n.er 指定实验名称,那么当每个实验的 n 值递增时,每个实验将被赋予一个唯一的名称。实验是按照 MPI 进程获取实验目录锁的顺序来编号的,因而无法保证与进程的 MPI 等级相对应。如果您将 dbx 附加到正在运行的 MPI 作业中的 MPI 进程,则实验编号由附加的顺序来确定。
如果您将每个实验都存储在其自己的本地文件系统上并指定一个显式的实验名称,则每个实验都可能会获得这个名称。例如,假设您在具有四个单处理器节点的群集中运行 MPI 作业,这四个节点分别标记为 node0、node1、node2 和 node3。每个节点具有一个名为 /scratch 的本地磁盘,您将实验存储在该磁盘的 username 目录中。由 MPI 作业创建的实验具有下面的全路径名称。
node0:/scratch/username/test.1.er node1:/scratch/username/test.1.er node2:/scratch/username/test.1.er node3:/scratch/username/test.1.er |
包括节点名称的全名是唯一的,但在每个实验目录中都有一个名为 test.1.er 的实验。如果在 MPI 作业完成后将实验移到公共位置,则必须确保这些名称仍然是唯一的。例如,要将这些实验移到假设可以从所有节点访问的起始目录并重命名这些实验,请键入以下命令。
rsh node0 ’er_mv /scratch/username/test.1.er test.0.er’ rsh node1 ’er_mv /scratch/username/test.1.er test.1.er’ rsh node2 ’er_mv /scratch/username/test.1.er test.2.er’ rsh node3 ’er_mv /scratch/username/test.1.er test.3.er’ |
对于大型 MPI 作业,可能需要使用脚本将实验移到公共位置。请不要使用 UNIX® 命令 cp 或 mv;应当使用上例中所示的 er_cp 或 er_mv,如处理实验中所述。
如果不知道哪些本地文件系统可用,请使用 df -lk 命令或咨询系统管理员。请始终确保用来存储实验的目录已经存在、其定义是唯一的以及不将其用于任何其他实验,还要确保文件系统具有足够的空间来容纳这些实验。有关如何估计所需空间的信息,请参见估计存储要求。
除非您能够访问用于运行实验的装入对象和源文件或者拥有具备相同路径和时间戳的副本,否则在计算机或节点间复制或移动实验时不能在带注释的反汇编代码中查看带注释的源代码或源代码行。
要在 MPI 的控制下使用 collect 命令收集数据,,请使用与 ClusterTools 版本相对应的语法,如下所示。
在 Sun HPC ClusterTools 7 上:
% mpirun -np n collect [collect-arguments] program-name [program-arguments] |
在 Sun HPC ClusterTools 6 和更低版本上:
% mprun -np n collect [collect-arguments] program-name [program-arguments] |
在以上两种情况下,n 都表示要由 MPI 创建的进程数。此过程会创建 n 个单独的 collect 实例,每个实例都记录一个实验。有关实验的存储位置和方法的信息,请阅读数据的存储位置一节。
为了确保将来自不同 MPI 运行的实验集存储在不同的位置,可以使用 -g 选项为每个 MPI 运行创建一个实验组。实验组应当存储在所有 MPI 进程都可以访问的文件系统上。创建实验组还有助于将单个 MPI 运行的实验集装入性能分析器。如果不创建组,则可以使用 -d 选项为每个 MPI 运行指定一个单独的目录。
要在 MPI 的控制下启动 dbx 并收集数据,请使用下面的语法。
在 Sun HPC ClusterTools 7 上:
% mpirun -np n dbx program-name < collection-script |
在 Sun HPC ClusterTools 6 或更低版本上:
% mprun -np n dbx program-name < collection-script |
在以上两种情况下,n 都表示要由 MPI 创建的进程数,collection-script 都表示包含设置和启动数据收集所必需的命令的 dbx 脚本。此过程会创建 n 个单独的 dbx 实例,每个实例都记录其中一个 MPI 进程上的实验。如果未定义实验名称,则使用 MPI 等级对实验进行标记。有关实验的存储位置和方法的信息,请阅读存储 MPI 实验一节。
通过在程序中使用收集脚本以及对 MPI_Comm_rank() 的调用,可以使用 MPI 等级来对实验进行命名。例如,在 C 程序中插入以下行。
ier = MPI_Comm_rank(MPI_COMM_WORLD,&me); |
在 Fortran 程序中插入以下行。
call MPI_Comm_rank(MPI_COMM_WORLD, me, ier) |
例如,如果将该调用插入到第 17 行,则可以使用类似以下内容的脚本。
stop at 18 run program-arguments rank=$[me] collector enable collector store filename experiment.$rank.er cont quit |
通过在 ppgsz 命令上运行 collect 并指定 -F on 或 -F all 标志,可以将 collect 与 ppgsz(1) 一起使用。创始实验位于 ppgsz 可执行文件上,我们不需要关注它。如果您的路径找到 32 位版本的 ppgsz,并且实验在支持 64 位进程的系统上运行,则首先要做的是针对它的 64 位版本执行 exec,创建 _x1.er。该可执行文件将进行派生,创建 _x1_f1.er。
子进程尝试针对路径上的第一个目录中指定的目标执行 exec,然后针对第二个目录中的目标执行 exec,依此类推,直到其中一个 exec 尝试成功。例如,如果第三个尝试成功,则前两个后续实验分别命名为 _x1_f1_x1.er 和 _x1_f1_x2.er,并且这两个实验都完全为空。目标上的实验是来自成功的 exec 的某个实验(在本例中为第三个实验),命名为 _x1_f1_x3.er 并存储在创始实验之下。通过针对 test.1.er/_x1_f1_x3.er 调用分析器或 er_print 实用程序,可以直接处理该目标。
如果 64 位 ppgsz 是初始进程,或者如果在 32 位内核上调用 32 位 ppgsz,那么,针对实际目标执行 exec 操作的派生子进程的数据位于 _f1.er 中,而实际目标的实验位于 _f1_x3.er 中,前提是采用与上例相同的路径。