JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris Studio 12.3:性能分析器     Oracle Solaris Studio 12.3 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

1.  性能分析器概述

2.  性能数据

3.  收集性能数据

编译和链接程序

源代码信息

静态链接

共享对象处理

编译时优化

编译 Java 程序

为数据收集和分析准备程序

使用动态分配的内存

使用系统库

使用信号处理程序

使用 setuidsetgid

数据收集的程序控制

C 和 C++ 接口

Fortran 接口

Java 接口

C、C++、Fortran 和 Java API 函数

动态函数和模块

collector_func_load()

collector_func_unload()

数据收集的限制

基于时钟的分析的限制

时钟分析中的运行时失真和扩大

收集跟踪数据的限制

跟踪过程中的运行时失真和扩大

硬件计数器溢出分析的限制

硬件计数器溢出分析中的运行时失真和扩大

后续进程中数据收集的限制

OpenMP 分析的限制

Java 分析的限制

用 Java 编程语言所编写的应用程序的运行时性能失真和扩大

数据的存储位置

实验名称

实验组

子孙进程的实验

MPI 程序的实验

内核和用户进程上的实验

移动实验

估计存储要求

收集数据

使用 collect 命令收集数据

数据收集选项

-p option

-h counter_definition_1...[, counter_definition_n]

-s option

-H option

-M option

-m option

-S option

-c option

-I directory

-N library_name

-r option

实验控制选项

-F option

-j option

-J java_argument

-l signal

-t duration

-x

-y signal [ ,r]

输出选项

-o experiment_name

-d directory-name

-g group-name

-A option

-L size

-O file

其他选项

-P process_id

-C comment

-n

-R

-V

-v

使用 collect 实用程序从正在运行的进程中收集数据

使用 collect 实用程序从正在运行的进程中收集数据

使用 dbx collector 子命令收集数据

dbx 运行收集器:

数据收集子命令

profile option

hwprofile option

synctrace option

heaptrace option

tha option

sample option

dbxsample { on | off }

实验控制子命令

disable

enable

pause

resume

sample record name

输出子命令

archive mode

limit value

store option

信息子命令

show

status

在 Oracle Solaris 平台上使用 dbx 从正在运行的进程中收集数据

从不受 dbx 控制的正在运行的进程中收集数据

从正在运行的程序中收集跟踪数据

从 MPI 程序收集数据

对 MPI 运行 collect 命令

存储 MPI 实验

从脚本收集数据

collectppgsz 一起使用

4.  性能分析器工具

5.  er_print 命令行性能分析工具

6.  了解性能分析器及其数据

7.  了解带注释的源代码和反汇编数据

8.  操作实验

9.  内核分析

索引

为数据收集和分析准备程序

对于大多数程序来说,您不必为数据收集和分析做任何特殊的准备。如果程序执行下列任一操作,则应当阅读下面的一个或多个小节:

此外,如果要在运行时控制程序中的数据收集,还应当阅读相关小节。

使用动态分配的内存

许多程序依赖于动态分配的内存,它们使用诸如以下各项的功能:

必须小心确保程序不依赖于动态分配的内存的初始内容,除非内存分配方法明确地说明要设置初始值:例如,比较 malloc(3C) 手册页中对 callocmalloc 的描述。

偶尔,使用动态分配的内存的程序似乎可以单独地正常运行,但是启用性能数据收集之后就会失败。症状可能包括意外的浮点行为、段故障或特定于应用程序的错误消息。

如果应用程序单独运行时未初始化的内存偶然设置为良性值,但应用程序与性能数据收集工具一起运行时未初始化的内存被设置为其他值,则会出现这种行为。发生这种情况时,问题不出在性能工具上。依赖于动态分配的内存内容的任何应用程序都具有潜在的已知问题:除非明确说明使用其他方式,否则操作系统将为动态分配的内存随机提供任意内容。即使目前操作系统会始终将动态分配的内存设置为某个值,但是将来在使用操作系统的后续修订版或将程序移植到其他操作系统时,这些潜在的已知问题会引起意外的行为。

下列工具可以帮助您找到这些潜在的已知问题:

使用系统库

收集器插入各种系统库的函数,以收集跟踪数据并确保数据收集的完整性。下面的列表描述了收集器插入库函数调用的情况。

在某些情况下,插入不会成功:

收集器插入失败可能会导致性能数据丢失或无效。

er_sync.soer_heap.soer_mpviewn.so(其中 n 表示 MPI 版本)库仅在分别请求同步等待跟踪数据、堆跟踪数据或 MPI 跟踪数据时装入。

使用信号处理程序

收集器使用两个信号来收集分析数据:SIGPROF 用于所有实验;SIGEMT(在 Solaris 平台上)或 SIGIO(在 Linux 平台上)仅用于硬件计数器实验。收集器为其中的每个信号安装一个信号处理程序。该信号处理程序截获并处理它自己的信号,但是会将其他信号传递到所安装的其他信号处理程序。如果程序为这些信号安装其自己的信号处理程序,则收集器会将其信号处理程序作为主处理程序重新安装,以保证性能数据的完整性。

collect 命令还可以将用户指定的信号用于暂停和恢复数据收集以及记录样本。尽管在安装用户处理程序时向实验中写入警告,但这些信号不受收集器保护。确保收集器对指定信号的使用与应用程序对相同信号的使用之间没有冲突是您的责任。

由收集器安装的信号处理程序会设置一个确保系统调用不被信号传送中断的标志。如果程序的信号处理程序将该标志设置为允许中断系统调用,则设置该标志可以更改程序的行为。在异步 I/O 库 libaio.so 中就有一个行为更改的重要示例,它将 SIGPROF 用于异步取消操作,并且中断系统调用。如果已安装收集器库 libcollector.so则取消信号总是来得太迟,以至于无法取消异步 I/O 操作。

如果在未预装入收集器库的情况下将 dbx 附加到进程并启用性能数据收集,并且程序随后安装其自身的信号处理程序,则收集器不再重新安装其自身的信号处理程序。在这种情况下,程序的信号处理程序必须确保 SIGPROFSIGEMT 信号被传递,以便性能数据不丢失。如果程序的信号处理程序中断系统调用,那么程序行为和分析行为都将与预装入收集器库时不同。

使用 setuidsetgid

由于动态装入器实施了一定的限制,因此将难以使用 setuid(2) 和收集性能数据。如果您的程序调用 setuid 或执行 setuid 文件,则收集器可能无法写入实验文件,原因是它缺少新用户 ID 的必需权限。

collect 命令通过将共享库 libcollector.so 插入目标的地址空间 (LD_PRELOAD) 来运行。如果对调用 setuidsetgid 或创建调用 setuidsetgid 的子孙进程的可执行文件调用过的 collect 命令进行调用,可能会出现多个问题。如果您不是超级用户,在运行实验时,收集会因为共享库未安装在可信目录中而失败。解决方法是以超级用户身份运行实验,或使用 crle(1) 授予权限。应对安全障碍时请格外小心,操作风险需自行承担。

运行 collect 命令时,必须为您、由使用 exec() 执行的程序的 setuid 属性和 setgid 属性设置的任何用户或组以及该程序自身设置的任何用户或组,将 umask 设置为允许写权限。如果未正确设置掩码,某些文件可能无法写入实验,并且可能无法处理实验。如果可以写入日志文件,尝试处理实验时将显示错误。

如果目标本身发出了设置 UID 或 GID 的任何系统调用,或者如果目标更改其 umask,然后对其他某个可执行文件派生或运行 exec(),或者 crle 用于配置运行时链接程序如何搜索共享对象,则可能会出现其他问题。

如果在更改其有效 GID 的目标上以超级用户身份启动实验,实验终止时自动运行的 er_archive 进程将失败,原因是它需要未标记为可信的共享库。在这种情况下,您可以在实验终止后立即在记录实验的计算机上明确地手动运行 er_archive 实用程序(或 er_print 实用程序或 analyzer 命令)。

数据收集的程序控制

如果要控制程序中的数据收集,收集器共享库 libcollector.so 包含了一些可以使用的 API 函数。这些函数是用 C 语言编写的。另外,也提供 Fortran 接口。C 接口和 Fortran 接口都是在由库所提供的头文件中定义的。

API 函数定义如下所示。

void collector_sample(char *name);
void collector_pause(void);
void collector_resume(void);
void collector_terminate_expt(void);

CollectorAPI 类为 Java 程序提供了类似的功能,Java 接口中对其进行了介绍。

C 和 C++ 接口

可以通过包括 collectorAPI.h 并与 -lcollectorAPI(包含用于检查底层 libcollector.so API 函数是否存在的实际函数)相链接来访问收集器 API 的 C 和 C++ 接口。

如果没有活动的实验,API 调用将被忽略。

Fortran 接口

Fortran API libfcollector.h 文件定义了库的 Fortran 接口。要使用该库,必须使用 -lcollectorAPI 链接应用程序。(还提供了该库的替代名称 -lfcollector,目的在于实现向后兼容性。除动态函数、线程暂停和恢复调用等功能外,Fortran API 提供了与 C 和 C++ API 相同的功能。

要使用 Fortran 的 API 函数,请插入下面的语句:

include "libfcollector.h"

注 - 请勿使用 -lcollector 链接任何语言的程序。否则,收集器可能会出现不可预知的行为。


Java 接口

使用以下语句可以导入 CollectorAPI 类并访问 Java API。但是请注意,必须使用指向 /installation_directory/lib/collector.jar 的类路径来调用应用程序,其中 installation_directory 是 Oracle Solaris Studio 软件的安装目录。

import com.sun.forte.st.collector.CollectorAPI;

Java CollectorAPI 方法的定义如下所示:

CollectorAPI.sample(String name)
CollectorAPI.pause()
CollectorAPI.resume()
CollectorAPI.terminate()

除动态函数 API 之外,Java API 包含与 C 和 C++ API 相同的函数。

C 头文件 libcollector.h 包含一些宏,这些宏的作用是如果当时未在收集数据,则跳过对实际 API 函数的调用。在这种情况下,不动态装入函数。但是,由于在某些情况下这些宏不能很好地运行,所以使用这些宏会有风险。使用 collectorAPI.h 较为安全,因为它不使用宏,而是直接引用函数。

如果正在收集性能数据,则 Fortran API 子例程会调用 C API 函数,否则这些子例程将返回。检查的开销很低,不会对程序性能产生太大的影响。

如本章稍后所述,要收集性能数据就必须使用收集器运行您的程序。插入对 API 函数的调用不会启用数据收集功能。

如果要在多线程程序中使用 API 函数,应当确保它们只由一个线程调用。API 函数执行适用于进程(而不是单独的线程)的操作。如果每个线程都调用 API 函数,则记录的数据可能会与预期不同。例如,如果一个线程在其他线程到达程序中的同一点之前调用了 collector_pause()collector_terminate_expt(),则会针对所有线程暂停或终止收集,从而丢失那些正在执行 API 调用之前代码的线程的数据。

C、C++、Fortran 和 Java API 函数

对 API 函数的描述如下所示。

动态函数和模块

如果 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 HotSpot 虚拟机编译的 Java 方法,该虚拟机使用的是另一个接口。Java 接口提供已编译到收集器的方法的名称。您可以查看 Java 编译方法的函数数据和带注释的反汇编列表,但不能查看带注释的源代码列表。

对 API 函数的描述如下所示。

collector_func_load()

将有关动态编译的函数的信息传递到收集器,以便在实验中进行记录。下表对参数列表进行了描述。

表 3-1 collector_func_load() 的参数列表

参数
定义
name
性能工具所使用的动态编译函数的名称。该名称不必是函数的实际名称。虽然该名称不应包含嵌入的空格或引号字符,但无须遵循通常的函数命名约定。
alias
用于描述函数的任意字符串。它可以是 NULL。它不经过任何方式的解释,可以包含嵌入的空格。它显示在分析器的“摘要”标签中。它可用于指示函数的内容或动态构造函数的原因。
sourcename
构造函数时所在源文件的路径。它可以是 NULL。该源文件用于带注释的源代码列表。
vaddr
函数的装入地址。
size
以字节为单位的函数大小。
lntsize
对行号表中条目数量的计数。如果未提供行号信息,则计数应为零。
lntable
包含 lntsize 条目的表,其中每个条目都是一对整数。第一个整数是偏移量,第二个整数是行号。在一个条目的偏移量和下一个条目中所给出的偏移量之间的所有指令都归属于在第一个条目中提供的行号。偏移量必须按数字升序列出,但行号的顺序可以是任意的。如果 lntableNULL,则没有可用的函数源代码列表,不过反汇编列表是可用的。

collector_func_unload()

通知收集器位于地址 vaddr 的动态函数已卸载。