跳过导航链接 | |
退出打印视图 | |
![]() |
Oracle Solaris Studio 12.3:性能分析器 Oracle Solaris Studio 12.3 Information Library (简体中文) |
性能分析器在 "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() 的信息,如下所示:
如果未提供信息(未调用 collector_func_load()),则在函数列表中,动态编译和装入的函数会显示为 <Unknown>。分析器中既看不到函数源代码,也看不到反汇编代码。
如果没有提供源文件名和行号表,但提供了函数的名称、大小以及地址,则函数列表中将显示动态编译和装入的函数的名称及度量。带注释的源代码是可用的,并且反汇编指令是可见的,只是行号被指定为 [?],这表示行号未知。
如果提供了源文件名,但未提供行号表,分析器显示的信息将与不提供源文件名所显示的信息类似,只是带注释的源代码开头将显示一个特殊索引行,以指示该函数由不带行号的指令组成。例如:
1.121 1.121 <Function func0, instructions without line numbers> 1. #include <stdio.h>
如果提供了源文件名和行号表,将按照与常规编译函数相同的方式在“函数”标签、“源”标签和“反汇编”标签中显示函数及其度量。
有关收集器 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()>
本机代码是最初用 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 指令。