IntroPerf: Transparent Context-Sensitive Multi-Layer Performance Inference using System Stack Traces

核心观点是OS tracer一般是由系统调用触发的,系统调用和函数调用之间有gap。 文章主要是通过Event Tracing Framework for Windows(ETW)采集的system call stack去反向构造延时,通过call stack来推断函数调用,基于此进行分析。

虽然剖析器或基于源代码的工具可以在开发阶段使用,即在一个定义良好的环境中对程序进行诊断,但许多性能错误在这样的阶段幸存下来,并影响生产运行。 操作系统内核级追踪器由于独立于程序和库,通常用于开发后的诊断;然而,它们缺乏详细的特定程序指标来推断性能问题,如函数延迟和程序上下文。

在本文中,我们提出了一个新的性能推断系统,称为IntroPerf。 它通过利用大多数商品操作系统中广泛存在的操作系统跟踪器,透明地生成细粒度的性能信息--就像应用剖析工具的信息。 以系统堆栈跟踪为输入,IntroPerf可以实现透明的上下文敏感的性能推断,并在从用户函数到内核的多层次范围内诊断应用程序的性能。

论文主要有以下两个贡献

  • 我们提出了一种新的性能推断技术,根据调用上下文的连续性,用系统堆栈跟踪来估计程序函数实例的延迟。这种技术主要是将操作系统跟踪器的系统堆栈痕迹转换为函数实例的延迟,以实现对性能异常的细粒度定位。
  • 通过对多个系统层次的上下文敏感的性能分析,自动定位内部和外部的性能瓶颈。IntroPerf通过在调用上下文树中组织和分析估计的函数延迟,以上下文敏感的方式定位性能瓶颈。IntroPerf在性能注释的调用路径上的排名机制会自动突出潜在的性能瓶颈,不管这些瓶颈是在程序内部还是外部。

Design

在post-development阶段对性能缺陷的有效诊断提出了几个要求。 - 问题1:使用一个广泛部署的通用跟踪框架收集跟踪数据。 - RQ2:在细粒度的函数层面上,利用调用上下文信息进行应用性能分析。 - RQ3:通过系统堆栈追踪对程序执行进行合理的覆盖,以实现性能调试。

Architecture

IntroPerf的结构如图2所示。输入是系统堆栈traces,是由操作系统追踪器收集的堆栈traces。 正如第1节所简述的那样,这些事件并不能直接表明函数的延迟--这是一个对瓶颈分析有用的指标--因为这些事件的时间戳是针对操作系统事件的。

为了解决这个问题,IntroPerf提供了对应用程序性能的推断。 关键思想是函数上下文在堆栈中的连续性:衡量一个函数的上下文在堆栈中没有变化的情况下持续了多长时间。 从本质上讲,IntroPerf将系统的堆栈痕迹转换成一组函数延迟(第3.3节),以及它们的调用上下文信息。 这个上下文显示了从 "main "函数开始的特定的函数调用序列;因此,它对于检测性能异常和函数执行方式之间的任何关联是非常有用的。 这种对上下文敏感的性能分析需要频繁而有效地记录和检索调用上下文;为此,IntroPerf有一个动态调用上下文索引的组件(第3.2节)。

上下文敏感的性能分析,确定哪些函数是性能瓶颈,以及它们存在于哪些调用环境中。 们的机制从追踪中的堆栈的所有层推断出函数的延迟。这就导致了函数延迟的潜在重叠。 使用函数调用的层次结构(第3.4.1节)来提取真正的贡献延时。 然后,我们的算法对每个动态调用上下文的性能进行排名,并列出延迟最高的调用上下文和每个上下文中延迟最高的函数(第3.4.2节),这就是作为IntroPerf的输出产生的性能错误候选列表。

Calling Context Tree Construction and Dynamic Calling Context Indexing

为了推理性能症状和调用上下文之间的相关性,有必要将每个函数调用与其索引的动态调用上下文联系起来。

我们使用调用上下文树(CCT)数据结构的一个变种[10]。 通过给通往每个路径末端的指针分配一个唯一的数字,我们用一个唯一的整数ID来索引每个路径。

Inference of Function Latencies

就是通过call stack反向构造延时数据。看图3就很清楚了。

比如,在t1和t2期间,它是在A->B->D的环境中被调用的。 然而,在t3,它的上下文变成了A->C->D。证明他的call stack变了。t3的D不是t2和t1的D。

以两种模式推断函数的延迟,即保守估计和积极估计。 保守模式通过上下文的最后一个事件来估计一个函数的结束,而激进模式则通过不同上下文的起始事件来估计它。

对于一个CCT来说,一个函数节点v被扩展为有三个额外的字段:v.C是每个节点中积累的函数数;v.μa和v.μc分别是激进和保守模式下的平均函数延迟。

Context-Sensitive Analysis of Inferred Performance

首先,我们对多层的函数延迟进行归一化处理,以消除跨调用栈层的重叠,并以自上而下的方式提取真正的贡献延迟。 其次,我们提出了一个基于调用上下文的排名机制,该机制自动定位潜在的根源上下文和上下文中的瓶颈函数。

Top-Down Latency Normalization

递归地从PA-CCT中的调用者函数中减去被调用者函数的延迟。得到一个non-overlapped的延时。

Performance-Annotated Calling Context Ranking

我们的方法对热点调用上下文进行排名,除了热点函数外,特别是在触发高延迟的情况下,还暴露了调用堆栈中密切相关的函数,如调用者和被调用者。 调用上下文中的调用关系允许开发者检查调用堆栈中可能对热点函数产生影响的邻近函数,并找到最合适的代码区域进行修补,特别是在涉及复杂的代码语义时。

为了定位热点调用上下文,我们通过遍历CCT生成一组调用路径并对其进行排序。

热点排名调查性能缺陷的一个挑战是,有些代码是固有的CPU密集型,无论工作负载如何变化,都会排名靠前(例如,加密,压缩函数)。 为了解决这个问题并提高排名输出的质量,我们在对调用环境进行排名时采用了一种系统的差异化方法。 该方法使用两组由工作负载样本产生的CCT,在两个不同的输入下:一个是程序被测试并确认能按预期工作的基本输入,另一个是用户发现并报告有性能缺陷症状的错误输入。 通过将基于基本输入的推断执行摘要与基于有缺陷的输入的推断执行摘要相减,我们将对有缺陷的输入敏感的热点放在更高的等级上,并减少常见热点的重要性。 为了应用这一技术,我们首先需要定义多个工作负载中的路径的等价性。

我们定义,如果两条路径的代表函数在相同的顺序下是相同的,则两条路径是等价的。 路径的差分成本计算如下。P1和P2分别是针对一个基本输入和一个错误输入的。 在动态调用上下文的两组路径之间的比较中,由于错误的输入,可能会出现一个新的上下文。 在这种情况下,我们认为基本工作负载的延迟为零,只使用错误输入的上下文。

最后对3.4.2中的式子进行分数排名。