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.  性能数据

收集器收集何种数据

时钟数据

Oracle Solaris 下基于时钟的分析

Linux 下基于时钟的分析

对 MPI 程序的基于时钟的分析

对 OpenMP 程序的基于时钟的分析

Oracle Solaris 内核的基于时钟的分析

硬件计数器溢出分析数据

硬件计数器列表

有别名的硬件计数器列表的格式

原始硬件计数器列表的格式

同步等待跟踪数据

堆跟踪(内存分配)数据

MPI 跟踪数据

全局(抽样)数据

如何将度量分配到程序结构

函数级度量:独占、非独占和归属

解释归属度量:示例

递归如何影响函数级度量

3.  收集性能数据

4.  性能分析器工具

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

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

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

8.  操作实验

9.  内核分析

索引

收集器收集何种数据

收集器使用多种方法收集各种数据:

分析数据和跟踪数据都包含有关特定事件的信息,并且这两种类型的数据都会转换为性能度量。全局数据不会转换为度量,而是用于提供标记器,这些标记器可用于将程序执行划分为很多时间段。通过全局数据,可以了解该时间段内程序执行的总体情况。

每个分析事件或跟踪事件收集的数据包都包含以下信息:

有关线程和轻量级进程的更多信息,请参见第 6 章

除了通用数据外,每个事件特定的数据包还包含特定于数据类型的信息。

数据类型及其使用方法将在下列子节中介绍:

时钟数据

进行基于时钟的分析时,收集的数据取决于操作系统所提供的度量。

Oracle Solaris 下基于时钟的分析

在 Oracle Solaris 下的基于时钟的分析中,每个线程的状态都按固定的时间间隔存储。这种时间间隔称为分析间隔。这些信息存储在一个整数数组中:数组的一个元素用于内核维护的十个微记帐状态中的每一个状态。收集的数据通过性能分析器转换为每个状态所用的时间和分析间隔的精度。缺省分析间隔约为 10 毫秒 (10 ms)。收集器提供的高精度分析间隔大约为 1 毫秒,低精度分析间隔大约为 100 毫秒,如果操作系统允许,则可使用任意的间隔。运行 collect -h 命令(不带任何其他参数)可列显运行该命令的系统所允许的范围和精度。

下表定义了从基于时钟的数据计算得来的度量。

表 2-1 Solaris 计时度量

度量
定义
用户 CPU 时间
在 CPU 中按用户模式运行所用的时间。
挂钟时间
在线程 1 上花费的时间。该时间通常称为“挂钟时间”。
总线程时间
全部线程时间的总和。
系统 CPU 时间
在 CPU 中或陷阱状态下按内核模式运行所用的线程时间。
等待 CPU 时间
等待 CPU 所用的线程时间。
用户锁定时间
等待锁定所用的线程时间。
文本缺页时间
等待文本页所用的线程时间。
数据缺页时间
等待数据页所用的线程时间。
其他等待时间
等待内核页所用的线程时间,或休眠/停止所用的时间。

对于多线程实验,将计算所有线程的时间(挂钟时间除外)的总和。所定义的挂钟时间对于多程序多数据 (multiple-program multiple-data, MPMD) 目标没有意义。

计时度量按多种类别说明程序消耗时间的位置,并且可用于改善程序的性能。

Linux 下基于时钟的分析

在 Linux 操作系统下,可用的度量只有用户 CPU 时间。虽然报告的总 CPU 占用时间是准确的,但分析器不可能像在 Oracle Solaris 中那样准确地确定实际系统 CPU 时间的时间比例。虽然分析器显示的信息好像是轻量级进程 (lightweight process, LWP) 数据,但实际上 Linux 中没有 LWP 的数据;所显示的 LWP ID 实际上是线程 ID。

对 MPI 程序的基于时钟的分析

可以在用 Oracle Message Passing Toolkit(以前称为 Sun HPC ClusterTools)运行的 MPI 实验上收集时钟分析数据。Oracle Message Passing Toolkit 必须至少为版本 8.1。

Oracle Message Passing Toolkit 已集成在 Oracle Solaris 11 发行版中。如果系统中安装了此工具包,您可以在 /usr/openmpi 中找到它。如果您的 Oracle Solaris 11 系统中尚未安装此工具包,当为系统配置了软件包系统信息库时,可以使用命令 pkg search openmpi 搜索该软件包。有关在 Oracle Solaris 11 中安装软件的更多信息,请参见《Adding and Updating Oracle Solaris 11 Software Packages》(添加并更新 Oracle Solaris 11 软件包)。

在 MPI 实验上收集时钟分析数据时,可以显示两个其他度量:

在 Oracle Solaris 上,以串行或并行方式执行工作时,“MPI 工作”会累积。在以下情况下“MPI 等待”会累积:MPI 运行时正在等待进行同步时、该等待正在使用 CPU 时间或正在休眠时,以及正在以并行方式执行工作,但未在 CPU 上调度线程时。

在 Linux 上,仅当进程在用户模式或系统模式下处于活动状态时,“MPI 工作”和“MPI 等待”才会累积。除非您已指定 MPI 应执行忙等待,否则,Linux 上的“MPI 等待”将没有用处。


注 - 如果要在 Linux 上使用 Oracle Message Passing Toolkit 8.2 或 8.2.1,可能需要解决方法。版本 8.1 或 8.2.1c 不需要解决方法,或者如果要使用 Oracle Solaris Studio 编译器,则任何版本都不需要解决方法。

Oracle Message Passing Toolkit 版本号由安装路径指定,例如 /opt/SUNWhpc/HPC8.2.1,或者,您可以按照如下所示键入 mpirun —V 查看输出,其中版本以斜体表示:

mpirun (Open MPI) 1.3.4r22104-ct8.2.1-b09d-r70

如果您的应用程序是使用 GNU 或 Intel 编译器编译的,并且要对 MPI 使用 Oracle Message Passing Toolkit 8.2 或 8.2.1,则要获取 MPI 状态数据,必须使用 -WI--enable-new-dtags 选项和 Oracle Message Passing Toolkit link 命令。这些选项将使可执行文件定义 RPATHRUNPATH,从而可使用 LD_LIBRARY_PATH 环境变量启用 MPI 状态库。


对 OpenMP 程序的基于时钟的分析

如果对 OpenMP 程序执行基于时钟的分析,将提供以下两种附加度量:“OpenMP 工作”和“OpenMP 等待”。

在 Oracle Solaris 上,以串行或并行方式执行工作时,“OpenMP 工作”会累积。在以下情况下“OpenMP 等待”会累积:OpenMP 运行时正在等待进行同步时、该等待正在使用 CPU 时间或正在休眠时,以及正在以并行方式执行工作,但未在 CPU 上安排线程时。

在 Linux 操作系统上,仅当进程在用户模式或系统模式下处于活动状态时,“OpenMP 工作”和“OpenMP 等待”才会累积。除非您已指定 OpenMP 应执行忙等待,否则,Linux 上的“OpenMP 等待”将没有用处。

OpenMP 程序的数据可以在三种视图模式中的任一种模式下显示。在用户模式下,从线程按实际从主线程克隆的方式显示,并使其调用堆栈匹配主线程的调用堆栈。调用堆栈中来自 OpenMP 运行时代码 (libmtsk.so) 的框架将进行压缩。在专家用户模式下,主从线程的显示方式不同,编译器生成的显式函数可见,来自 OpenMP 运行时代码 (libmtsk.so) 的框架将进行压缩。对于计算机模式,将显示实际的本机堆栈。

Oracle Solaris 内核的基于时钟的分析

er_kernel 实用程序可以收集有关 Oracle Solaris 内核的基于时钟的分析数据。

er_kernel 实用程序捕获内核分析数据,并将数据记录为分析器实验,其格式与 collect 实用程序在用户程序上创建的实验格式相同。实验可以由 er_print 实用程序或性能分析器进行处理。内核实验可以显示函数数据、调用方-被调用方数据、指令级数据和时间线,但是不能显示源代码行数据(因为大多数 Oracle Solaris 模块不包含行号表)。

有关更多信息,请参见第 9 章

硬件计数器溢出分析数据

硬件计数器可跟踪诸如高速缓存未命中次数、高速缓存停止周期、浮点运算、分支误预测、CPU 周期以及执行指令之类的事件。在硬件计数器溢出分析中,当运行线程的 CPU 的指定硬件计数器发生溢出时,收集器将记录一个分析数据包。计数器将重置并继续进行计数。分析数据包中包括溢出值和计数器类型。

各种处理器芯片系列支持同时存在二到十八个硬件计数器寄存器。收集器可收集一个或多个寄存器上的数据。对于每个寄存器,收集器允许选择寄存器的类型来监视溢出并为寄存器设置溢出值。有些硬件计数器可以使用任意寄存器,而有些计数器仅可以使用特定的寄存器。因此,在一个实验中并非可以选择所有的硬件计数器组合。

硬件计数器溢出分析还可以在内核上通过 er_kernel 实用程序执行。有关更多信息,请参见第 9 章

硬件计数器溢出分析数据由性能分析器转换为计数度量。对于以循环方式计数的计数器,所报告的度量会转换为次数;而对于不以循环方式计数的计数器,所报告的度量为事件计数。在具有多个 CPU 的机器上,用于转换度量的时钟频率为各个 CPU 时钟频率的调和平均数。因为每种类型的处理器都有其自己的一组硬件计数器,并且硬件计数器的数目庞大,因此,此处未列出硬件计数器的度量。下一小节讲述如何找出可用的硬件计数器。

硬件计数器的一个用途是可诊断进出 CPU 的信息流问题。例如,高速缓存未命中次数计数较高表明,重新组织程序的结构来改进数据或文本的位置或提高高速缓存的重用率可以改善程序性能。

某些硬件计数器与其他计数器相互关联。例如,分支误预测和指令高速缓存未命中次数通常是相关的,因为分支误预测会导致将错误的指令装入到指令高速缓存,而这些指令必须替换为正确的指令。这种替换会导致指令高速缓存未命中,或指令转换后备缓冲器 (instruction translation lookaside buffer, ITLB) 未命中,或甚至缺页。

通常会在导致事件和相应事件计数器溢出的指令之后,向硬件计数器溢出传送一条或多条指令:这称为“失控 (skid)”,它会使计数器溢出分析数据难以解释。如果缺少对精确识别因果指令的硬件支持,可以对候选的因果指令尝试合适的回溯搜索。

收集期间支持和指定这种回溯时,硬件计数器分析数据包还包括适用于硬件计数器事件的候选内存引用指令的 PC(program counter,程序计数器)和 EA(effective address,有效地址)。(在分析期间需要进行后续处理来验证候选事件 PC 和 EA)。关于内存引用事件的这一附加信息为各种面向数据的分析(又称为数据空间分析)提供了方便。仅在运行 Oracle Solaris 操作系统的基于 SPARC 的平台上支持回溯。

在一些 SPARC 芯片上,计数器中断是精确的,无需回溯。此类计数器的事件类型后面用字 precise 表示。

如果在与内存有关的精确计数器上前置一个 + 号,将启用内存空间分析,这将有助于确定是哪些程序行或内存地址导致了与内存有关的程序延迟。有关内存空间分析的更多信息,请参见数据空间分析和内存空间分析

也可以为时钟分析指定候选事件 PC 和 EA 的回溯和记录,尽管数据可能难以解释。硬件计数器回溯更为可靠。

硬件计数器列表

由于硬件计数器是特定于处理器的,因此可以选用的计数器取决于所使用的处理器。性能工具为许多可能常用的计数器提供了别名。通过在特定系统上的终端窗口中键入不带任何其他参数的 collect -h,您可从收集器获得该系统上可用的硬件计数器列表。如果处理器和系统支持硬件计数器分析,则 collect -h 命令会列显两个包含有关硬件计数器信息的列表。第一个列表包含别名为通用名称的硬件计数器;第二个列表包含原始硬件计数器。如果性能计数器子系统和 collect 命令都不知道特定系统上的计数器名称,这些列表将为空。但是,在大多数情况下,可以用数值指定计数器。

以下示例显示了计数器列表中的条目。有别名的计数器将首先显示在列表中,然后是原始硬件计数器列表。该示例中的每一行输出都按打印格式显示。

Aliased HW counters available for profiling:
cycles[/{0|1|2|3}],31599989 (`CPU Cycles', alias for Cycles_user; CPU-cycles)
insts[/{0|1|2|3}],31599989 (`Instructions Executed', alias for Instr_all; events)
loads[/{0|1|2|3}],9999991 (`Load Instructions', alias for Instr_ld; 
      precise load-store events)
stores[/{0|1|2|3}],1000003 (`Store Instructions', alias for Instr_st; 
      precise load-store events)
dcm[/{0|1|2|3}],1000003 (`L1 D-cache Misses', alias for DC_miss_nospec; 
      precise load-store events)
...
Raw HW counters available for profiling:
...
Cycles_user[/{0|1|2|3}],1000003 (CPU-cycles)
Instr_all[/{0|1|2|3}],1000003 (events)
Instr_ld[/{0|1|2|3}],1000003 (precise load-store events)
Instr_st[/{0|1|2|3}],1000003 (precise load-store events)
DC_miss_nospec[/{0|1|2|3}],1000003 (precise load-store events)
有别名的硬件计数器列表的格式

在有别名的硬件计数器列表中,第一个字段(例如,cycles)提供可以在 collect 命令的 -h counter... 参数中使用的别名。此别名还是在 er_print 命令中使用的标识符。

第二个字段列出计数器的可用寄存器,例如 [/{0|1|2|3}]

第三个字段(例如 9999991)是计数器的缺省溢出值。对于有别名的计数器,选择的缺省值可提供合理的抽样率。由于实际抽样率变化相当大,因此可能需要指定缺省值以外的值。

第四个字段(在圆括号中)包含类型信息。它提供简短描述(例如 CPU Cycles)、原始硬件计数器名称(例如 Cycles_user)以及计数单位类型(例如 CPU-cycles)。

类型信息字段中的可能条目包括下列项:

如果类型信息的最后一个单词或仅有的单词是:

在示例中的有别名的硬件计数器列表中,类型信息包含一个单词的,如第一个计数器的 CPU-cycles 和第二个计数器的 events。类型信息包括两个单词的,如第三个计数器的 load-store events

原始硬件计数器列表的格式

原始硬件计数器列表中包含的信息是有别名的硬件计数器列表中信息的子集。原始硬件计数器列表中的每行包括由 cputrack(1) 使用的内部计数器名称、可以在其上使用计数器的寄存器编号、缺省溢出值、类型信息和计数器单位(可以是 CPU-cyclesevents)。

如果计数器度量与运行的程序无关的事件,则类型信息的第一个单词是 not-program-related。对于这样的计数器,分析不会记录调用堆栈,而是显示人工函数 collector_not_program_related 中所用的时间。线程和 LWP ID 会被记录,但没有任何意义。

原始计数器的缺省溢出值为 1000003。对于大多数原始计数器来说,此值并非理想值,所以您应在指定原始计数器时指定溢出值。

同步等待跟踪数据

在多线程程序中,不同线程执行的任务同步会导致应用程序的执行延迟,例如,一个线程要访问已被其他线程锁定的数据时就不得不等待。这些事件称为同步延迟事件,并通过跟踪对 Solaris 或 pthread 线程函数的调用来收集这些事件。收集和记录这些事件的过程称为同步等待跟踪。等待锁定花费的时间称为等待时间

只有等待时间超过阈值(单位为微秒)时,才会记录事件。阈值为 0 表示跟踪所有的同步延迟事件,而不管等待时间为何。缺省阈值通过运行校准测试决定,在该测试中对线程库的调用不会出现任何同步延迟。阈值是这些调用的平均时间与某个因子(当前为 6)的乘积。该过程可防止对此类事件进行记录:即等待时间仅在于调用本身,而与实际的延迟无关。因此,数据量会大大减少,但同步事件的计数可能会被明显低估。

Java 程序不支持同步跟踪。

同步等待跟踪数据被转换为以下度量。

表 2-2 同步等待跟踪度量

度量
定义
同步延迟事件
对等待时间超过指定阈值的同步例程的调用数目。
同步等待时间
超过指定阈值的等待时间的总和。

通过该信息,您可以确定函数或装入对象对同步例程进行调用时是会经常被阻塞还是会经历很长时间的等待。高同步等待时间表示线程间的争用。您可以通过重新设计算法,尤其是重新组织锁的结构,以便仅包含需要锁定的每个线程的数据来减少争用。

堆跟踪(内存分配)数据

对未正确管理的内存分配和解除分配函数进行调用可能会造成数据的使用效率降低,从而导致应用程序的性能降低。在堆跟踪中,收集器通过插入 C 标准库内存分配函数 mallocreallocvallocmemalign 以及解除分配函数 free 跟踪内存分配和解除分配请求。对 mmap 的调用被视为内存分配,它允许记录 Java 内存分配的堆跟踪事件。Fortran 函数 allocatedeallocate 调用 C 标准库函数,因此会间接跟踪这些例程。

不支持对 Java 程序的堆分析。

堆跟踪数据会被转换为以下度量。

表 2-3 内存分配(堆跟踪)度量

度量
定义
分配数
对内存分配函数的调用数。
分配的字节
每次调用内存分配函数时分配的字节总数。
泄漏数
调用内存分配函数(未对解除分配函数进行相应的调用)的数量。
泄漏的字节
已分配但未解除分配的字节数。

收集堆跟踪数据有助于识别程序中的内存泄漏,或定位内存分配效率不高的位置。

内存泄漏的另一个常用定义(例如在 dbx 调试工具中)为:内存泄漏是一个动态分配的内存块,在程序的数据空间中没有任何指向它的指针。此处所使用的泄漏定义包括这种替换的定义,但也包括存在指针的内存。

MPI 跟踪数据

收集器可以收集有关对消息传递接口 (Message Passing Interface, MPI) 库的调用的数据。

使用开源 VampirTrace 5.5.3 发行版来实现 MPI 跟踪。该跟踪可识别以下 VampirTrace 环境变量:

VT_STACKS
控制是否在数据中记录调用堆栈。缺省设置为 1。将 VT_STACKS 设置为 0 将禁用调用堆栈。
VT_BUFFER_SIZE
控制 MPI API 跟踪收集器的内部缓冲区的大小。缺省值为 64M(64 兆字节)。
VT_MAX_FLUSHES
控制在终止 MPI 跟踪前刷新缓冲区的次数。缺省值是 0,这表示只要缓冲区满了就允许刷新到磁盘。将 VT_MAX_FLUSHES 设置为正数将为刷新缓冲区的次数设置限制。
VT_VERBOSE
启用各种错误和状态消息显示。缺省值为 1,在此情况下可打开紧急的错误和状态消息。如果出现问题,请将此变量设置为 2

有关这些变量的更多信息,请参见 Technische Universität Dresden Web 站点上的 Vampirtrace 用户手册。

在达到缓冲区限制之后发生的 MPI 事件将不会写入跟踪文件,这将导致跟踪不完整。

要去掉限制并获取应用程序的完整跟踪,请将 VT_MAX_FLUSHES 环境变量设置为 0。该设置将导致 MPI API 跟踪收集器在缓冲区已满时刷新磁盘的缓冲区。

要更改缓冲区大小,请设置 VT_BUFFER_SIZE 环境变量。该变量的最佳值取决于要跟踪的应用程序。设置较小的值将增加应用程序可以使用的内存,但是将触发 MPI API 跟踪收集器频繁进行缓冲区刷新。这些缓冲区刷新可能会显著改变应用程序的行为。另一方面,设置较大的值(如 2 G)可以使 MPI API 跟踪收集器刷新缓冲区的次数降至最低,但是将减少应用程序可以使用的内存。如果没有足够的内存可用来容纳缓冲区和应用程序数据,应用程序的某些部分可能会交换至磁盘,从而导致应用程序的行为发生显著改变。

下面列出了用于收集数据的函数

MPI_Abort
MPI_Accumulate
MPI_Address
MPI_Allgather
MPI_Allgatherv
MPI_Allreduce
MPI_Alltoall
MPI_Alltoallv
MPI_Alltoallw
MPI_Attr_delete
MPI_Attr_get
MPI_Attr_put
MPI_Barrier
MPI_Bcast
MPI_Bsend
MPI_Bsend-init
MPI_Buffer_attach
MPI_Buffer_detach
MPI_Cancel
MPI_Cart_coords
MPI_Cart_create
MPI_Cart_get
MPI_Cart_map
MPI_Cart_rank
MPI_Cart_shift
MPI_Cart_sub
MPI_Cartdim_get
MPI_Comm_compare
MPI_Comm_create
MPI_Comm_dup
MPI_Comm_free
MPI_Comm_group
MPI_Comm_rank
MPI_Comm_remote_group
MPI_Comm_remote_size
MPI_Comm_size
MPI_Comm_split
MPI_Comm_test_inter
MPI_Dims_create
MPI_Errhandler_create
MPI_Errhandler_free
MPI_Errhandler_get
MPI_Errhandler_set
MPI_Error_class
MPI_Error_string
MPI_File_close
MPI_File_delete
MPI_File_get_amode
MPI_File_get_atomicity
MPI_File_get_byte_offset
MPI_File_get_group
MPI_File_get_info
MPI_File_get_position
MPI_File_get_position_shared
MPI_File_get_size
MPI_File_get_type_extent
MPI_File_get_view
MPI_File_iread
MPI_File_iread_at
MPI_File_iread_shared
MPI_File_iwrite
MPI_File_iwrite_at
MPI_File_iwrite_shared
MPI_File_open
MPI_File_preallocate
MPI_File_read
MPI_File_read_all
MPI_File_read_all_begin
MPI_File_read_all_end
MPI_File_read_at
MPI_File_read_at_all
MPI_File_read_at_all_begin
MPI_File_read_at_all_end
MPI_File_read_ordered
MPI_File_read_ordered_begin
MPI_File_read_ordered_end
MPI_File_read_shared
MPI_File_seek
MPI_File_seek_shared
MPI_File_set_atomicity
MPI_File_set_info
MPI_File_set_size
MPI_File_set_view
MPI_File_sync
MPI_File_write
MPI_File_write_all
MPI_File_write_all_begin
MPI_File_write_all_end
MPI_File_write_at
MPI_File_write_at_all
MPI_File_write_at_all_begin
MPI_File_write_at_all_end
MPI_File_write_ordered
MPI_File_write_ordered_begin
MPI_File_write_ordered_end
MPI_File_write_shared
MPI_Finalize
MPI_Gather
MPI_Gatherv
MPI_Get
MPI_Get_count
MPI_Get_elements
MPI_Get_processor_name
MPI_Get_version
MPI_Graph_create
MPI_Graph_get
MPI_Graph_map
MPI_Graph_neighbors
MPI_Graph_neighbors_count
MPI_Graphdims_get
MPI_Group_compare
MPI_Group_difference
MPI_Group_excl
MPI_Group_free
MPI_Group_incl
MPI_Group_intersection
MPI_Group_rank
MPI_Group_size
MPI_Group_translate_ranks
MPI_Group_union
MPI_Ibsend
MPI_Init
MPI_Init_thread
MPI_Intercomm_create
MPI_Intercomm_merge
MPI_Irecv
MPI_Irsend
MPI_Isend
MPI_Issend
MPI_Keyval_create
MPI_Keyval_free
MPI_Op_create
MPI_Op_free
MPI_Pack
MPI_Pack_size
MPI_Probe
MPI_Put
MPI_Recv
MPI_Recv_init
MPI_Reduce
MPI_Reduce_scatter
MPI_Request_free
MPI_Rsend
MPI_rsend_init
MPI_Scan
MPI_Scatter
MPI_Scatterv
MPI_Send
MPI_Send_init
MPI_Sendrecv
MPI_Sendrecv_replace
MPI_Ssend
MPI_Ssend_init
MPI_Start
MPI_Startall
MPI_Test
MPI_Test_cancelled
MPI_Testall
MPI_Testany
MPI_Testsome
MPI_Topo_test
MPI_Type_commit
MPI_Type_contiguous
MPI_Type_extent
MPI_Type_free
MPI_Type_hindexed
MPI_Type_hvector
MPI_Type_indexed
MPI_Type_lb
MPI_Type_size
MPI_Type_struct
MPI_Type_ub
MPI_Type_vector
MPI_Unpack
MPI_Wait
MPI_Waitall
MPI_Waitany
MPI_Waitsome
MPI_Win_complete
MPI_Win_create
MPI_Win_fence
MPI_Win_free
MPI_Win_lock
MPI_Win_post
MPI_Win_start
MPI_Win_test
MPI_Win_unlock

MPI 跟踪数据会被转换为以下度量。

表 2-4 MPI 跟踪度量

度量
定义
MPI 发送数
已启动 MPI 点对点发送数
发送的 MPI 字节
“MPI 发送”中的字节数
MPI 接收数
已完成 MPI 点对点接收数
接收的 MPI 字节
“MPI 接收”中的字节数
MPI 时间
对 MPI 函数的所有调用所花费的时间
其他 MPI 事件
对既没有发送也没有接收点对点消息的 MPI 函数的调用数

MPI 时间是 MPI 函数中所用的总线程时间。如果还收集了 MPI 状态时间,则除 MPI_Init 和 MPI_Finalize 之外的所有 MPI 函数的 MPI 工作时间加上 MPI 等待时间应大约等于 MPI 工作时间。在 Linux 上,MPI 等待和工作基于用户 CPU 时间加系统 CPU 时间,而 MPI 时间基于实际时间,所以这些数值将不匹配。

当前,仅针对点对点消息收集 MPI 字节和消息计数;不针对集体通信函数记录 MPI 字节和消息计数。“接收的 MPI 字节”度量会计算所有消息中接收的实际字节数。“发送的 MPI 字节”会计算所有消息中发送的实际字节数。“MPI 发送数”会计算发送的消息数,“MPI 接收数”会计算接收的消息数。

收集 MPI 跟踪数据有助于标识 MPI 程序中可能因 MPI 调用而产生性能问题的位置。可能发生的性能问题的例子有负载平衡、同步延迟和通信瓶颈。

全局(抽样)数据

全局数据由收集器以称为样本数据包的数据包来记录。每个包中都包含一个数据包头、时间戳、内核的执行统计数据(如缺页和 I/O 数据)、上下文切换以及各种页面驻留(工作集和分页)统计数据。记录在样本包中的数据对程序来说是全局的,且不会转换为性能度量。记录样本包的过程称为抽样。

在以下情况下,样本包会被记录下来:

性能工具使用记录在样本包中的数据,按时间周期将数据分组,这称为样本。您可以通过选择一组样本过滤特定于事件的数据,以便只查看这些特定时间周期的信息。您也可以查看每个样本的全局数据。

性能工具不对不同种类的采样点进行区分。要利用采样点进行分析,您应只选择一种点进行记录。具体地说,如果要记录与程序结构或执行序列有关的样本点,则应关闭定期抽样,并使用在 dbx 停止进程时,或将信号传送到正使用 collect 命令记录数据的进程时,或调用收集器 API 函数时记录的样本。