Diagnosing Performance Variations by Comparing Multi-Level Execution Traces

本篇文章更像是大杂烩(因为很多在引自己组里的文章)。提了一个ECCT,把分布式系统的线程之间的等待原因也标注出来了。

TraceCompare,这是一个能够自动识别用户空间和内核层面上同一任务的执行组之间差异的框架。 许多性能问题表现为变化,我们的框架很容易识别。 我们的比较算法考虑到所有影响分析执行的完成时间的线程。 差异与应用程序代码相关联,以促进对所发现问题的纠正。 任务执行的性能特征由一个新的数据结构表示,称为增强型调用上下文树(ECCT)。

Design

TraceCompare的设计和实现分成四个部分。

  • 一个数据模型,在数据库中存储任务执行的性能特征
  • 通过追踪来记录建立这个数据库所需的信息,并使其开销最小
  • 用于从trace中建立数据库的算法
  • 高亮显示各组任务执行之间差异的用户界面

Data Model

增强型调用上下文树(ECCT)。

对于所有时间都花在CPU上且涉及单线程的执行,ECCT的结构与CCT的结构是一致的。 在分析执行过程中,使用相关call stack中花费的时间来注释每个节点。

对于包含CPU外等待时间或涉及多个线程(可能分布在多个主机上)的执行,CCT得到了增强。 首先,对于任何非CPU的等待时间,一个以等待原因命名的人工函数(定时器、块设备、网络、抢占......)被推到堆栈上。 第二,每当一个线程在等待另一个线程时,第二个线程的堆栈就会与第一个线程的堆栈相连接。 当线程之间有一连串的依赖关系时,这个规则可以根据需要递归应用。 这些依赖关系可以是直接的(一个线程在等待另一个线程计算结果或执行动作),也可以是间接的(一个线程在等待另一个线程释放资源,如CPU或mutex)。

Tracing Task Execution

本文用的是LTTng。

为了能够在不同的执行之间进行比较,有必要对事件进行解复用。

有时,Linux内核的现有事件可以用于这一目的。例如,syscall_exit_accept事件和syscall_entry_shutdown事件。 如果不行,就只能将LTTng-UST的探针必须静态地插入到源代码中。

同时利用另外一篇工作里介绍的关键路径算法来寻找线程之间的阻塞关系。

本文还想在用户不需要改代码的情况下进行检测。 因此preload lttng-profile。每次定时器结束或者syscall的时候都会捕获call stack,并发出一个有时间戳的LTTng-UST事件。 为了提高性能,只对持续时间超过阈值的系统调用进行用户空间堆栈的捕获(100ms)。 系统调用的持续时间由一个内核模块来跟踪。

Building a Task Execution Database

主要分成四步

  1. Compute the critical path of the execution
  2. Generate an ECCT for the execution
  3. Compute global execution metrics
  4. Insert the execution’s ECCT and metrics in a database

这里面很多都是引用自己组里的之前的工作,介绍太简单了。

Comparing Task Executions

主要是两个部分:Filters和Flame Graph。 Filters可以选择自己感兴趣的指标,能够看到对应的其他指标的变化。 Flame Graph的亮点在于Diff。