Oracle® Developer Studio 12.5:性能分析器

退出打印视图

更新时间: 2016 年 6 月
 
 

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

使用与特定事件的数据一起记录的调用堆栈将度量分配到程序指令。如果该信息可用,则会将每条指令都映射到一行源代码,而分配到该指令的度量也被分配到该行源代码。有关如何完成此过程的更多详细说明,请参见了解性能分析器及其数据

除了源代码和指令,还会将度量分配到更高级别的对象:函数和装入对象。调用堆栈包含在执行分析时记录的有关函数调用到达指令地址的序列的信息。性能分析器使用调用堆栈来计算程序中每个函数的度量。这些度量称为函数级度量。

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

性能分析器可计算三种类型的函数级度量:独占度量、非独占度量和归属度量。

  • 函数的独占度量通过函数本身内部发生的事件计算得出:这种度量不包括来自对其他函数调用的度量。

  • 非独占度量通过函数本身和其调用的函数内部发生的事件计算得出:这种度量包括来自对其他函数调用的度量。

  • 归属度量说明了非独占度量在多大程度上来自对(或从)其他函数的调用:这种度量归属到其他函数的度量。

对于只出现在调用堆栈底部的函数(叶函数),独占度量和非独占度量是相同的。

对于装入对象,也要计算独占度量和非独占度量。装入对象的独占度量通过累加装入对象中所有函数上函数级别的度量计算得出。装入对象的非独占度量与函数的非独占度量的计算方法相同。

函数的独占度量和非独占度量给出了有关所有通过函数记录的路径信息。归属度量给出了有关通过函数记录的特定路径的信息。这些度量显示了度量在多大程度上来自特定函数调用。调用中所涉及的两个函数称为调用方被调用方。对于调用树中的每个函数:

  • 函数调用方的归属度量说明了函数的非独占度量在多大程度上归因于来自每个调用方的调用。调用方的归属度量的总和等于函数的非独占度量。

  • 函数的被调用方的归属度量说明了函数的非独占度量在多大程度上来自对每个被调用方的调用。它们的和加上函数的独占度量等于函数的非独占度量。

各度量间的关系可通过以下等式表示:

image:显示各度量间关系的等式

    通过比较调用方或被调用方的归属度量和非独占度量,可以得到以下进一步的信息:

  • 调用方的归属度量和非独占度量之间差额说明了度量在多大程度上来自对其他函数的调用以及调用方本身的工作。

  • 被调用方的归属度量和非独占度量之间的差额说明了被调用方的非独占度量在多大程度上来自从其他函数对它的调用。

    要定位可改善程序性能的位置,请执行以下操作:

  • 使用独占度量定位具有高度量值的函数。

  • 使用非独占度量确定程序中哪个调用序列导致高度量值。

  • 使用归属度量跟踪导致高度量值的函数的特定调用序列。

解释归属度量:示例

图 1 中说明了独占、非独占和归属度量,该图包含完整的调用树。其中的焦点是中心函数,即函数 C。

图的后面显示了该程序的伪代码。

图 1  说明独占、非独占和归属度量的调用树

image:说明独占、非独占和归属度量的调用树。

Main 函数调用函数 A 和函数 B,将 10 个单位的非独占度量归属函数 A 并将 20 个单位归属函数 B。这些是函数 Main 的被调用方归属度量。它们的总和 (10+20) 加上函数 Main 的独占度量等于函数 main 的非独占度量 (32)。

由于函数 A 将其所有时间都花费在对函数 C 的调用上,因此它的独占度量为 0 个单位。

函数 C 由函数 A 和函数 B 这两个函数调用,将 10 个单位的非独占度量归属函数 A 并将 15 个单位归属函数 B。这些是调用方归属度量。它们的总和 (10+15) 等于函数 C 的非独占度量 (25)。

调用方归属度量相当于函数 A 和 B 的非独占度量与独占度量之间的差异,这表示它们各自仅调用函数 C。(事实上,这些函数可能调用其他函数,但时间很短,不会显示在实验中。)

函数 C 调用函数 E 和函数 F 这两个函数,将 10 个单位的非独占度量归属函数 E 并将 10 个单位归属函数 F。这些是被调用方归属度量。它们的总和 (10+10) 加上函数 C 的独占度量 (5) 等于函数 C 的非独占度量 (25)。

对于函数 E 和函数 F 来说,被调用方归属度量和被调用方非独占度量是相同的。这表示函数 E 和函数 F 都仅由函数 C 调用。对于函数 E 来说,独占度量和非独占度量是相同的,但对于函数 F 来说则不同。这是由于函数 F 调用另一个函数(函数 G),而函数 E 没有。

下面显示了该程序的伪代码。

    main() {
       A();
       /Do 2 units of work;/
       B();
    }

    A() {
       C(10);
    }

    B() {
       C(7.5);
       /Do 5 units of work;/
       C(7.5);
    }

    C(arg) {
          /Do a total of "arg" units of work, with 20% done in C itself,
          40% done by calling E, and 40% done by calling F./
    }

递归如何影响函数级度量

递归函数直接或间接的调用使得度量的计算复杂化。 性能分析器将函数的度量作为一个整体显示,而不是显示函数的每个调用的度量:因此,必须将一系列递归调用的度量压缩为单一度量。此行为不会影响通过调用堆栈底部的函数(叶函数)计算得出的独占度量,但会影响非独占度量和归属度量。

非独占度量是通过将事件的度量添加到调用堆栈中函数的非独占度量来计算的。 为了确保在递归调用堆栈中不重复计算度量,事件的度量仅能向每个唯一函数的非独占度量添加一次。

归属度量是通过非独占度量来计算的。 在最简单的递归中,递归函数具有两个调用方:它本身和另一个函数(初始化函数)。如果在最后的调用中完成了所有工作,会将递归函数的非独占度量归属到它本身,而不是初始化函数。之所以发生此归属,是因为递归函数的所有更高调用的非独占度量均被视为零,以避免重复计算度量。但是,初始化函数会由于递归调用而作为被调用方正确归属到递归函数的非独占度量部分。