1

我需要实现执行时间测量功能。我想过两种可能。

  • 首先 - 定期 time() 调用,只需记住每个执行步骤开始的时间和每个执行步骤完成的时间。Unix timeshell 命令以这种方式工作。

  • 第二种方法是抽样。每个执行步骤在执行开始之前设置某种标志(例如 - 在堆栈帧中创建一些对象),并在完成时将其销毁。计时器定期扫描所有标志并生成执行时间配置文件。如果某个执行步骤比其他执行步骤花费更多时间 - 它将被扫描更多次。许多分析器都是这样工作的。

我需要在我的服务器应用程序中添加一些分析功能,什么方法更好,为什么?我认为第二种方法不太准确,第一种方法增加了对分析库代码的依赖。

4

4 回答 4

1

当 boost 是一个选项时,您可以使用timer library

于 2012-10-30T10:46:31.627 回答
1

在我的分析器中,我使用了您提到的第一种方法的扩展版本。

我有一个提供上下文对象的类。您可以在工作代码中将它们定义为自动对象,一旦执行流离开定义它们的上下文(例如,函数或循环),就会被释放。构造函数调用GetTickCount(它是一个Windows项目,你可以选择适合你的目标平台的类似函数)并存储这个值,而析构函数GetTickCount再次调用并计算这个时刻和开始之间的差异。每个对象都有唯一的上下文 ID(可以在同一上下文中自动生成为静态对象),因此分析器可以汇总具有相同 ID 的所有时间,这意味着相同的上下文已经传递了多次。还计算执行次数。

这是预处理器的宏,它有助于分析函数:

#define _PROFILEFUNC_  static ProfilerLocator locator(__FUNC__); ProfilerObject obj(locator);

当我想分析一个函数时,我只需在函数的开头插入PROFILEFUNC 。这会生成一个静态对象locator,该对象标识上下文并将其名称存储为函数名称(您可以决定选择其他命名)。然后自动ProfilerObject在堆栈上创建并“跟踪”自己的创建和删除,并将其报告给分析器。

于 2012-10-30T10:53:44.893 回答
1

确保您真的知道您在编写的分析器中要查找的内容,每当您收集某段代码的总执行时间时,它将包括在其所有子代码中花费的时间,这可能很难真正找到系统中的瓶颈是什么,因为最顶层的函数总是会冒出最昂贵的函数——比如 main()。

我的建议是挂钩每个函数的序言和结尾(如果您的应用程序是 CLR 应用程序,您可以ICorProfilerInfo::SetEnterLeaveFunctionHooks使用开始和每个函数的代码)并以树的形式为您分析的每个线程收集您的时间。

这个算法看起来和这个有点相似:

  • 为您监控的每个线程创建一个类似堆栈的数据结构。
  • 每当您收到有关开始执行的函数的通知时,将可以识别该函数的内容推送到该堆栈中。

    • 如果该函数不是堆栈上的唯一函数,那么您知道尚未返回的前一个函数是调用您的函数的函数。
    • 在您最喜欢的数据结构中跟踪那些被调用者调用的关系。
  • 每当一个方法返回时,它的标识符将始终位于其线程堆栈的顶部。它的总执行时间等于(最后一个(它的)标识符被压入堆栈的时间 - 当前时间)。弹出堆栈的标识符。

通过这种方式,您将对占用执行时间的内容进行树状细分,您可以在其中查看子调用占函数总执行时间的原因。

玩得开心!

于 2012-10-30T10:58:37.397 回答
1

第二种方法本质上是堆栈采样。您可以尝试通过某种进出事件捕获自己来完成,或者如果有一个实用程序来实际读取堆栈会更好。后者的优势在于您可以获得代码行分辨率,而不仅仅是方法级别。

很多人对此并不了解,那就是时间测量的精度远不如问题识别的精度重要

即使在 I/O 或其他阻塞期间进行采样也很重要,因此您不会对不必要的 I/O 视而不见。如果您担心与其他流程的竞争可能会增加时间,请不要担心,因为真正重要的不是绝对时间测量,而是百分比。例如,如果一行代码在堆栈上占挂钟时间的 50%,因此要负责这么多,那么无论发生什么其他事情,删除它都会使应用程序的速度加倍。

分析不仅仅是获取样本。人们通常对他们对他们的所作所为很随意,但这就是钱的所在。首先,包含时间是方法或代码行在堆栈上的时间分数。忘记“自我”时间——它包含在包容性时间中。忘记调用计数 - 它与包含百分比的关系充其量是非常间接的。如果你在总结,最好的方法是有一个“蝴蝶视图”,它的重点是一行代码。它的左右是堆栈样本上紧邻其上方和下方的代码行。每行代码旁边都有一个百分比 - 包含该行代码的堆栈样本的百分比。(不用担心递归。这根本不是问题。)

比任何类型的总结更好的是让用户自己看到堆栈样本的一小部分随机选择。这样,用户就可以全面了解每个快照的使用时间。保证出现在多个样本上的任何可避免的活动都有可能实现一些严重的加速。人们经常认为“嗯,这可能只是侥幸,而不是真正的瓶颈”。不是这样。修复它会得到回报,也许是一点点,也许是很多,但平均而言——意义重大。人们不应该被风险厌恶所统治。

更多关于这一切。

于 2012-10-30T13:30:51.100 回答