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

4.  性能分析器工具

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

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

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

工具如何查找源代码

带注释的源代码

性能分析器"源"标签布局

标识初始源代码行

"源"标签中的索引行

编译器注释

通用子表达式删除

循环优化

函数内联

并行化

带注释的源代码中的特殊行

源代码行度量

解释源代码行度量

度量格式

带注释的反汇编代码

解释带注释的反汇编代码

指令发送分组

指令发送延迟

硬件计数器溢出的归属

"源"、"反汇编"和 `PC` 标签中的特殊行

外联函数

编译器生成的主体函数

动态编译的函数

Java 本机函数

克隆函数

静态函数

非独占度量

分支目标

存储和装入指令的注释

在不运行实验的情况下查看源代码/反汇编代码

-func

-{source,src} item tag

-{disasm,dis} item tag

-{cc,scc,dcc} com-spec

-outfile filename

-V

8.  操作实验

9.  内核分析

索引

“源”、“反汇编”和 "PC" 标签中的特殊行

性能分析器在 "Source"(源)、"Disassembly"(反编译)和 "PCs" (PC) 标签中显示的某些行并不直接对应于代码行、指令行或程序计数器行。以下部分介绍了这些特殊的行。

外联函数

外联函数可以在反馈优化编译期间创建。在“源”标签和“反汇编”标签中,外联函数显示为特殊的索引行。在“源”标签中,在已转换为外联函数的代码块中会显示一条注释。

                   Function binsearchmod inlined from source file ptralias2.c into the 
0.       0 .         58.         if( binsearchmod( asize, &element ) ) {
0.240    0.240       59.             if( key != (element << 1) ) {
0.       0.          60.                 error |= BINSEARCHMODPOSTESTFAILED;
                        <Function: main -- outline code from line 60 [_$o1B60.main]>
0.040    0.040     [ 61]                 break;
0.       0.          62.             }
0.       0.          63.         }

在“反汇编”标签中,外联函数通常在文件结尾处显示。

                        <Function: main -- outline code from line 85 [_$o1D85.main]>
0.       0.             [ 85] 100001034:  sethi       %hi(0x100000), %i5
0.       0.             [ 86] 100001038:  bset        4, %i3
0.       0.             [ 85] 10000103c:  or          %i5, 1, %l7
0.       0.             [ 85] 100001040:  sllx        %l7, 12, %l5
0.       0.             [ 85] 100001044:  call        printf ! 0x100101300
0.       0.             [ 85] 100001048:  add         %l5, 336, %o0
0.       0.             [ 90] 10000104c:  cmp         %i3, 0
0.       0.             [ 20] 100001050:  ba,a        0x1000010b4
                        <Function: main -- outline code from line 46 [_$o1A46.main]>
0.       0.             [ 46] 100001054:  mov         1, %i3
0.       0.             [ 47] 100001058:  ba          0x100001090
0.       0.             [ 56] 10000105c:  clr         [%i2]
                        <Function: main -- outline code from line 60 [_$o1B60.main]>
0.       0.             [ 60] 100001060:  bset        2, %i3
0.       0.             [ 61] 100001064:  ba          0x10000109c
0.       0.             [ 74] 100001068:  mov         1, %o3

外联函数的名称显示在方括号中,并对外联代码段的有关信息进行编码,这些信息包括从中提取代码的函数名称以及源代码中该段的起始行号。这些改编名称 (mangled name) 可能随发行版的不同而不同。分析器提供了函数名称的可读版本。有关更多详细信息,请参阅外联函数

如果在收集应用程序的性能数据时调用了外联函数,则分析器会在带注释的反汇编代码中显示一个特殊行,以显示该函数的非独占度量。有关更多详细信息,请参见非独占度量

编译器生成的主体函数

编译器并行化函数中的循环或具有并行化指令的区域时,将会创建初始源代码中不存在的新主体函数。OpenMP 软件执行概述中介绍了这些函数。

编译器将改编名称分配给主体函数,这些主体函数对并行结构的类型、从中提取结构的函数名称、初始源代码中该结构的起始行号以及并行结构的序列号进行了编码。这些改编名称 (mangled name) 因微任务化库的发行版而异,但均会取消改编 (demangle) 为更易于理解的名称。

下面显示的是一个由编译器生成的典型主体函数,如计算机模式下的函数列表中所示。

7.415      14.860      psec_ -- OMP sections from line 9 [_$s1A9.psec_]
3.873       3.903      craydo_ -- MP doall from line 10 [_$d1A10.craydo_]

从上面的示例可以看出,最先显示的是从中提取结构的函数名称,接着是并行结构的类型,然后是并行结构的行号,最后在方括号中显示的是由编译器生成的主体函数的改编名称 (mangled name)。类似地,在反汇编代码中,也会生成一个特殊索引行。

0.       0.            <Function: psec_ -- OMP sections from line 9 [_$s1A9.psec_]>
0.       7.445         [24]    1d8cc:  save        %sp, -168, %sp
0.       0.            [24]    1d8d0:  ld          [%i0], %g1
0.       0.            [24]    1d8d4:  tst         %i1
0.       0.            <Function: craydo_ -- MP doall from line 10 [_$d1A10.craydo_]>
0.       0.030         [ ?]    197e8:  save        %sp, -128, %sp
0.       0.            [ ?]    197ec:  ld          [%i0 + 20], %i5
0.       0.            [ ?]    197f0:  st          %i1, [%sp + 112]
0.       0.            [ ?]    197f4:  ld          [%i5], %i3

对于 Cray 指令,函数可能与源代码行号不相关。在这种情况下,会在行号的位置显示 [ ?]。如果索引行显示在带注释的源代码中,则该索引行指示不带行号的指令,如下所示。

                     9. c$mic  doall shared(a,b,c,n) private(i,j,k)
                  
                   Loop below fused with loop on line 23
                   Loop below not parallelized because autoparallelization 
                     is not enabled
                   Loop below autoparallelized
                   Loop below interchanged with loop on line 12
                   Loop below interchanged with loop on line 12
3.873     3.903         <Function: craydo_ -- MP doall from line 10 [_$d1A10.craydo_],
                      instructions without line numbers>
0.        3.903     10.            do i = 2, n-1

注 - 在实际显示中,索引行和编译器注释行并不换行。


动态编译的函数

动态编译的函数是指程序执行时编译和链接的函数。收集器中并没有有关用 C 或 C++ 编写的动态编译函数的信息,除非用户使用收集器 API 函数 collector_func_load() 提供所需的信息。“函数”标签、“源”标签和“反汇编”标签中显示的信息取决于传递给 collector_func_load() 的信息,如下所示:

有关收集器 API 函数的更多信息,请参见动态函数和模块

对于 Java 程序,大部分方法由 JVM 软件解释。在解释执行期间,在单独的线程上运行的 Java HotSpot 虚拟机会监视性能。在监视过程中,虚拟机可以决定使用已解释的一个或多个方法,生成相应的机器码,并执行更有效的机器码版本,而不是解释原始代码。

对于 Java 程序,无需使用收集器 API 函数;分析器通过在该方法的索引行下方使用一个特殊行,表明在带注释的反汇编代码列表中存在 Java HotSpot 编译的代码,如以下示例所示。

                   11.    public int add_int () {
                   12.       int       x = 0;
2.832     2.832      <Function: Routine.add_int: HotSpot-compiled leaf instructions>
0.        0.         [ 12] 00000000: iconst_0
0.        0.         [ 12] 00000001: istore_1

反汇编代码列表仅显示已解释的字节代码,而不显示编译的指令。缺省情况下,在该特殊行的旁边显示已编译代码的度量。该独占和非独占 CPU 时间与各行已解释字节代码的所有独占和非独占 CPU 时间总和不同。通常,如果多次调用该方法,已编译指令的 CPU 时间将大于已解释字节代码的 CPU 时间总和,原因是已解释代码只是在最初调用该方法时执行一次,而已编译代码则在其后执行。

带注释的源代码不显示 Java HotSpot 编译的函数。而是显示一个特殊索引行,以指示不带行号的指令。例如,下面显示了与上例显示的反汇编提取对应的带注释的源代码:

                     11.    public int add_int () {
2.832     2.832        <Function: Routine.add_int(), instructions without line numbers>
0.        0.         12.       int       x = 0;
                       <Function: Routine.add_int()>

Java 本机函数

本机代码是最初用 C、C++ 或 Fortran 编写,由 Java 代码通过 Java 本地接口 (Java Native Interface, JNI) 调用的已编译代码。以下示例来自与演示程序 jsynprog 关联的文件 jsynprog.java 的带注释的反汇编代码。

                     5. class jsynprog
                        <Function: jsynprog.<init>()>
0.       5.504          jsynprog.JavaCC() <Java native method>
0.       1.431          jsynprog.JavaCJava(int) <Java native method>
0.       5.684          jsynprog.JavaJavaC(int) <Java native method>
0.       0.             [  5] 00000000: aload_0
0.       0.             [  5] 00000001: invokespecial <init>()
0.       0.             [  5] 00000004: return

由于本机方法不包含在 Java 源代码中,jsynprog.java 的带注释的源代码的开头会显示每个 Java 本机方法,并使用一个特殊的索引行来指示不带行号的指令。

0.       5.504          <Function: jsynprog.JavaCC(), instructions without line 
                           numbers>
0.       1.431          <Function: jsynprog.JavaCJava(int), instructions without line 
                           numbers>
0.       5.684          <Function: jsynprog.JavaJavaC(int), instructions without line 
                           numbers>

注 - 在实际的带注释的源代码显示中,索引行并不换行。


克隆函数

编译器能够识别可以对其执行额外优化的函数调用。所传递的部分参数是常量的函数调用即是这类调用的其中一个示例。当编译器识别出它可以优化的特定调用时,会创建该函数的副本(称为克隆) 并生成优化代码。

在带注释的源代码中,编译器注释将指示是否创建了克隆函数:

0.       0.       Function foo from source file clone.c cloned, 
                   creating cloned function _$c1A.foo; 
                   constant parameters propagated to clone
0.       0.570     27.    foo(100, 50, a, a+50, b);

注 - 在实际的带注释的源代码显示中,编译器注释行并不换行。


克隆函数名称是标识特定调用的改编名称。在上面的示例中,编译器注释指示克隆的函数名称为 _$c1A.foo。在函数列表中,该函数显示为:

0.350     0.550     foo
0.340     0.570     _$c1A.foo

因为每个克隆函数都具有不同的指令集,所以带注释的反汇编代码列表会分别显示这些克隆函数。这些函数与任何源文件都没有关联,因此其指令也与任何源代码行号无关。下面显示了某个克隆函数的带注释的反汇编代码的前几行。

0.       0.           <Function: _$c1A.foo>
0.       0.           [?]    10e98:  save        %sp, -120, %sp
0.       0.           [?]    10e9c:  sethi       %hi(0x10c00), %i4
0.       0.           [?]    10ea0:  mov         100, %i3
0.       0.           [?]    10ea4:  st          %i3, [%i0]
0.       0.           [?]    10ea8:  ldd         [%i4 + 640], %f8

静态函数

静态函数通常在库中使用,因此库内部使用的名称不会与用户可能使用的名称发生冲突。库被剥离后,静态函数的名称将从符号表中删除。在这种情况下,分析器会为包含剥离静态函数的库中的每个文本区域生成人工名称。该名称的格式为 <static>@0x12345,其中 @ 符号后的字符串是库中文本区域的偏离量。分析器无法区分连续的剥离静态函数和单个这样的函数,因此可能出现两个或多个这样的函数,且其度量合并在一起。可在 jsynprog 演示程序的函数列表中找到静态函数的示例,如下所示。

0.       0.       <static>@0x18780
0.       0.       <static>@0x20cc
0.       0.       <static>@0xc9f0
0.       0.       <static>@0xd1d8
0.       0.       <static>@0xe204

在 "PC" 标签中,上述函数使用如下所示的偏移量表示:

0.       0.       <static>@0x18780 + 0x00000818
0.       0.       <static>@0x20cc + 0x0000032C
0.       0.       <static>@0xc9f0 + 0x00000060
0.       0.       <static>@0xd1d8 + 0x00000040
0.       0.       <static>@0xe204 + 0x00000170

在 "PC" 标签中,在被剥离的库内调用的函数的替代表示方法为:

<library.so> -- no functions found + 0x0000F870

非独占度量

在带注释的反汇编代码中,有一些特殊的行标记外联函数占用的时间。

以下示例显示了当调用外联函数时显示的带注释的反汇编代码:

0.       0.        43.         else
0.       0.        44.         {
0.       0.        45.                 printf("else reached\n");
0.       2.522         <inclusive metrics for outlined functions>

分支目标

带注释的反汇编代码列表中显示的一行人工行 <branch target> 与指令的某个 PC 对应,在该指令中使用回溯查找它的有效地址失败,原因是该回溯算法遇到了分支目标。

存储和装入指令的注释

利用 -xhwcprof 选项进行编译时,编译器将为存储 (st) 和装入 (ld) 指令生成附加信息。可以在反汇编代码列表中查看带有注释的 st ld 指令。