【问题标题】:how does a c# profiler work?c# 分析器是如何工作的?
【发布时间】:2011-08-14 05:24:33
【问题描述】:

我很好奇典型的 C# 分析器是如何工作的?

虚拟机中是否有特殊的钩子?

是否容易扫描函数调用的字节码并将调用注入到启动/停止计时器?

或者这真的很难,这就是为什么人们要花钱购买工具来做到这一点?

(作为旁注,我发现有点有趣,因为它非常罕见 - 谷歌在搜索“how does a c# profiler work?”时完全错过了这艘船 - 结果是关于空调......)

【问题讨论】:

  • 通常很多分析器会非常频繁地对堆栈进行快照以查看它当前的位置。然后他们使用这些快照构建统计数据。当然,C# 很可能不是这种情况,所以请谨慎对待。
  • 当我在 Google 上搜索该字符串时,它工作正常。但请注意,当您单击链接时,页面标题中的搜索字符串在“c”之后被截断:# 可能在某处搞砸了……
  • 我得到了与@Gabriel 相同的 Google 结果,但将其更改为——“c#”分析器如何工作——修复了这个问题。我仍然没有得到任何好的答案,这么好的问题。将 C# 更改为 CLR,将 Profiler 更改为 Profiling,您可能会得到更好的结果。
  • 请注意,它不是 C# 分析器 - 它是 CLR 分析器。因此:google.com/search?q=how+does+a+CLR+oprofiler+work%3F

标签: c# profiler


【解决方案1】:

这是一篇讨论仪器和采样方法的长篇文章的链接:

http://smartbear.com/support/articles/aqtime/profiling/

【讨论】:

  • 它所说的采样只是 gprof 模型,差不多 30 年了。现代采样器做得更好。
【解决方案2】:

扫描字节码是否容易 函数调用和注入调用 启动/停止计时器?

或者真的很难,这就是为什么 人们为执行此操作的工具付费?

注入调用非常困难,需要工具来完成。

这不仅很难,而且是一种非常间接的查找瓶颈的方法。 原因是瓶颈是代码中的一个或少量语句,它们占了大部分时间的花费,时间可以显着减少 - 即它不是真正必要的,即它是浪费的。 如果你可以知道你的一个例程的平均包含时间(包括 IO 时间),如果你可以将它乘以它被调用的次数,然后除以总时间,你可以知道这个例程的时间百分比需要。 如果百分比很小(例如 10%),您可能在其他地方遇到更大的问题。 如果百分比较大(例如 20% 到 99%),您可能会在例程中遇到瓶颈。 因此,现在您必须在例程中 寻找它,查看它调用的事物以及它们所花费的时间。此外,您还希望避免被递归(调用图的错误)所迷惑。

有一些分析器(例如用于 Linux、Shark 等的Zoom)以不同的原理工作。 原理是有一个函数调用堆栈,并且在一个例程负责的所有时间里(要么做工作,要么等待其他例程做它请求的工作),它在堆栈上。 因此,如果它负责 50% 的时间(比如说),那么这就是它在堆栈上的时间量, 不管它被调用了多少次,或者每次调用花费了多少时间。 不仅例程在堆栈上,而且花费时间的特定代码行也在堆栈上。 您无需寻找它们。 您不需要的另一件事是测量精度。 如果您采集 10,000 个堆栈样本,则有罪线将测量为 50 +/- 0.5%。 如果您抽取 100 个样本,它们将被测量为 50 +/- 5%。 如果您抽取 10 个样本,它们将被测量为 50 +/- 16%。 在每种情况下您都会找到它们,这就是您的目标。 (并且递归并不重要。这意味着给定的行可以在给定的堆栈示例中出现多次。)

在这个问题上,有很多混乱。无论如何,对发现瓶颈最有效的分析器是那些在挂钟时间对堆栈进行采样并逐行报告百分比的分析器。 (这很容易看出某些myths about profiling 是否正确。)

【讨论】:

  • +1!听起来我们应该为 dotNET 编写一个新的分析器,并牢记这个简单的概念。就 UI 而言,我在考虑 WinDirStat,只是我们会显示在各种方法中花费的时间,按 namespaces.classes 分组。
  • @GregC:我很久以前写的。当您按下两个 shift 键时,我只是让它收集堆栈样本。然后我有一个蝴蝶视图,专注于一行代码,而不是一个函数。它从一条 % 高的线开始,您可能会上下碰到相邻的线。它做了一个很好的演示,但我发现对于认真的工作来说,由于多种原因,它无法击败纯手动的方法,所以我让它休息了。无论如何,如果你做一些类似于 Zoom 的事情,你将有一个赢家,恕我直言。
  • @GregC:我所说的不击败手动方法的意思是,手动收集几个样本肯定会更麻烦,选择一条“热”线并从该线上下查看树。这有点乏味。但是,如果有什么东西引起了我的注意,我会采集更多样本,直到它再次出现,然后我研究它以叙述程序在做什么以及为什么。这可能意味着查看堆栈之外的其他数据。当我完全理解它时,我可以判断它是否真的很浪费并且可以用更好的东西代替。因此,找到高百分比线只是该过程的一个引导。
【解决方案3】:

1) 没有“典型”之类的东西。人们通过多种方式收集配置文件信息:对 PC 进行时间采样、检查堆栈跟踪、捕获方法/语句/编译指令的执行计数、在代码中插入探针以收集计数以及可选地调用上下文以获取调用上下文中的配置文件数据基础。这些技术中的每一种都可能以不同的方式实现。

2) 有分析“C#”和分析“CLR”。在 MS 世界中,您可以分析 CLR 并将 CLR 指令位置反向翻译为 C# 代码。我不知道 Mono 是否使用相同的 CLR 指令集;如果他们没有,那么您将无法使用 MS CLR 分析器;您必须使用 Mono IL 分析器。或者,您可以检测 C# 源代码以收集分析数据,然后在 MS、Mono 或某人的 C# 兼容自定义编译器或在诸如 WinCE 等嵌入式系统中运行的 C# 上编译/运行/收集该数据,空间是宝贵的,并且像 CLR-built-ins 这样的功能往往会被忽略。

检测源代码的一种方法是使用源到源转换,将代码从其初始状态映射到包含数据收集代码和原始程序的代码。这个paper on instrumenting code to collect test coverage data 展示了如何使用程序转换系统插入测试覆盖率探针,方法是在执行代码块时插入设置块特定布尔标志的语句。计数分析器用计数器递增指令代替这些探针。时序分析器为这些探针插入时钟快照/增量计算。我们的C# Profiler 以两种方式实现了 C# 源代码的计数和时序分析;它还通过使用收集执行路径的更复杂的探针来收集调用图数据。因此,它可以通过这种方式在调用图上生成时序数据。这个方案适用于任何你可以获得一半体面的解决时间价值的地方。

【讨论】:

    【解决方案4】:

    Microsoft 提供免费的 CLR Profiler 4.0 版。

    https://www.microsoft.com/downloads/en/details.aspx?FamilyID=be2d842b-fdce-4600-8d32-a3cf74fda5e1

    顺便说一句,CLR Profiler 文档中有一个很好的部分详细描述了它的工作原理,第 103 页。作为发行版的一部分有源代码。

    【讨论】:

    • 很高兴知道,但与问题的答案无关。
    • +1 反对投票者。您直接回答了 OP 的问题。
    • CLR Profiler 附带其源代码,如果有人对它的工作原理感兴趣。
    • @Omer Raviv:这正是我要说的 :)
    猜你喜欢
    • 2011-06-12
    • 1970-01-01
    • 2015-05-21
    • 2013-06-02
    • 2010-10-02
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 2013-02-02
    相关资源
    最近更新 更多