Oracle Solaris Studio 12.2:性能分析器

数据收集的工作原理

运行数据收集的输出是实验,该实验在文件系统中存储为带有各种内部文件和子目录的目录。

实验格式

所有实验都必须具有以下三个文件:

此外,实验还具有表示整个处理过程中的分析事件的二进制数据文件。每个数据文件都具有一系列事件,如下面解释性能度量所述。对于每种类型的数据,都将使用单独的文件,但每个文件都由目标中的所有 LWP 共享。

对于基于时钟的分析或硬件计数器溢出分析,将数据写入时钟周期或计数器溢出调用的信号处理程序中。对于同步跟踪、堆跟踪、MPI 跟踪或开放式 MP 跟踪,从 LD_PRELOAD 环境变量在用户调用的常规例程上插入的 libcollector 例程写入数据。每个这样的插入例程都部分填充数据记录,然后调用用户调用的常规例程,在该例程返回时填充数据记录的其余部分,并将记录写入数据文件。

所有数据文件都按块进行内存映射和写入。以这样的方式填充记录以便始终具有有效的记录结构,这样就可以在写入时读取实验。缓冲区管理策略设计用于最大限度地减少 LWP 之间的争用和序列化。

实验可以选择性地包含文件名为 notes 的 ASCII 文件。使用 collect 命令的 -C comment 参数时会自动创建此文件。创建实验后,可以手动创建或编辑该文件。该文件的内容会置于实验标题之前。

archives 目录

每个实验都具有一个 archives 目录,该目录包含描述 map.xml 文件中引用的每个装入对象的二进制文件。这些文件由 er_archive 实用程序(它在数据收集结束时运行)生成。如果进程异常终止,则可能无法调用 er_archive 实用程序,在这种情况下,归档文件由 er_print 实用程序或分析器在实验上首次调用时写入。

子孙进程

子孙进程将其实验写入创始进程的实验目录内的子目录。

对这些新实验的命名可指示其衍生情况,如下所示:

例如,如果创始进程的实验名称为 test.1.er,则其第三个派生创建的子进程的实验为 test.1.er/_f3.er。如果该子进程执行新映像,则对应的实验名称为 test.1.er/_f3_x1.er。后续实验由与父实验相同的文件组成,但是它们没有后续实验(所有后续实验都由创始实验中的子目录表示),而且它们没有归档子目录(所有归档都在创始实验中进行)。

动态函数

目标创建动态函数的实验在 map.xml 文件中具有描述这些函数的附加记录,还具有一个附加文件 dyntext,该文件包含动态函数的实际指令的副本。生成动态函数的带注释反汇编时需要该副本。

Java 实验

Java 实验在 map.xml 文件中具有附加记录,这两个记录用于 JVM 软件因其内部目的而创建的动态函数和目标 Java 方法的动态编译 (HotSpot) 版本。

此外,Java 实验具有一个 JAVA_CLASSES 文件,该文件包含有关调用的所有用户 Java 类的信息。

使用 JVMTI 代理记录 Java 跟踪数据,该代理是 libcollector.so 的一部分。该代理接收映射到记录的跟踪事件中的事件。该代理还接收类装入和 HotSpot 编译(用于写入 JAVA_CLASSES 文件)的事件以及 map.xml 文件中 Java 编译的方法记录。

记录实验

可以使用以下三种不同方法记录实验:

分析器 GUI 中的“性能收集”窗口中运行 collect 实验。

collect 实验

使用 collect 命令记录实验时,collect 实用程序会创建实验目录,并设置 LD_PRELOAD 环境变量,以确保将 libcollector.so 及其他 libcollector 模块预装入到目标的地址空间。然后,该 collect 实用程序设置环境变量,将实验名称和数据收集选项通知 libcollector.so,并执行自己顶部的目标。

libcollector.so 及其相关模块负责写入所有实验文件。

创建进程的 dbx 实验

在启用数据收集的情况下使用 dbx 启动进程时,dbx 还会创建实验目录,并确保预装入 libcollector.so。然后 dbx 在其第一个指令前的断点处停止进程,并调用 libcollector.so 中的初始化例程以启动数据收集。

Java 实验不能由 dbx 收集,因为 dbx 使用 Java 虚拟机调试接口 (Java Virtual Machine Debug Interface, JVMDI) 代理进行调试,而该代理无法与数据收集所需的 Java 虚拟机工具接口 (Java Virtual Machine Tools Interface, JVMTI) 代理共存。

正在运行的进程上的 dbx 实验

在正在运行的进程上使用 dbx 启动实验时,dbx 会创建实验目录,但不能使用 LD_PRELOAD 环境变量。dbx 对目标进行交互式函数调用以打开 libcollector.so,然后调用 libcollector.so 初始化例程,就像它创建进程时那样。与 collect 实验中一样,数据由 libcollector.so 及其模块写入。

由于进程启动时 libcollector.so 不在目标地址空间中,因此取决于插入用户可调用函数(同步跟踪、堆跟踪、MPI 跟踪)的任何数据收集可能都不起作用。通常,符号已经解析为底层函数,因此无法发生插入。此外,以下子孙进程也取决于插入,对于 dbx 在正在运行的进程上创建的实验无法正常工作。

如果在使用 dbx 启动进程之前或者在使 dbx 附加到正在运行的进程之前已显式预装入 libcollector.so,可以收集跟踪数据。