繁体   English   中英

分析算法

[英]Profiling algorithm

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

  • 第一个 - 定时time()调用,只记住每个执行步骤开始的时间和每个执行步骤完成的时间。 Unix time shell命令就是这样工作的。

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

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

当boost是一个选项时,您可以使用计时器库

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

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

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

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

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

确保你在你正在编写的探查器中真正知道你在寻找什么,每当你收集某段代码的总执行时间时,它将包括花在所有孩子身上的时间,这可能很难要真正找到系统中的瓶颈,因为最顶级的功能总是会成为最昂贵的功能 - 例如main()。

我建议挂钩每个函数的序言和尾声(如果你的应用程序是一个CLR应用程序,你可以使用ICorProfilerInfo::SetEnterLeaveFunctionHooks来做到这一点,你也可以在每个方法的开头使用宏,或任何其他机制这将在开头和每个函数中注入您的代码)并以树的形式为您的分析的每个线程收集您的时间。

对此的算法看起来与此类似:

  • 对于您正在监视的每个线程,创建一个类似堆栈的数据结构。
  • 每当您收到有关开始执行的函数的通知时,请将能够识别该函数的内容推送到该堆栈中。

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

通过这种方式,您可以对执行时间的执行时间进行树状细分,您可以在其中查看函数的总执行时间。

玩得开心!

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

很多人都没有这样做,这就是定时测量的精确度远远低于问题识别的精度

即使在I / O或其他阻塞期间采样也很重要,因此您不会对不必要的I / O视而不见。 如果你担心与其他过程的竞争会使时间膨胀,那就不要了,因为真正重要的不是绝对的时间测量,而是百分比。 例如,如果一行代码在堆栈上占据挂钟时间的50%,并由此负责,那么摆脱它将使应用程序的速度加倍,无论其他情况如何。

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

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

更多关于这一点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM