【问题标题】:Profiling multithreaded code, how does sampling work分析多线程代码,采样如何工作
【发布时间】:2016-07-29 12:27:24
【问题描述】:
我正在使用 Visual Studio 来分析我的多线程 C++ 应用程序。
根据我对采样方法的了解,我了解到它会以指定的时间间隔查看处理器以查看正在执行的函数。
我很好奇它如何处理多线程代码。很有可能在不同内核的不同线程上同时执行 2 个或多个函数。在这种情况下,采样方法是否会为这两个函数增加计数器?我相信这就是实际发生的事情。
这实际上使得从分析报告中获得洞察力变得困难。收集样本最多的函数,如果在工作线程上执行,可能在不同的核心(而不是主线程)上执行,并且可能根本不会影响应用程序性能。但是,如果它切换出主线程来执行它的工作,那么它应该会对性能产生明显的影响。
有没有更好的方法来分析多线程代码?
【问题讨论】:
标签:
c++
multithreading
visual-studio
profiling
【解决方案1】:
在对函数执行进行采样时,分析器通常会单独对每个软件线程进行采样。因此,如果你有 3 个线程,分别执行 CPU 密集型的 foo()、bar() 和 baz() 函数,并且采样频率为 100Hz,分析会话的持续时间为 1s,那么每个线程将获得 100 个样本的功能。
一个不错的分析器通常还会为您提供一种按给定线程过滤数据的方法,以便您可以查看哪些热点存在于哪个线程上隔离。例如,如果主线程是使用您使用的框架完成 UI 渲染的地方,那么主线程上发生的事情可能很重要。
弄清楚在后台线程中完成的计算如何影响应用程序的响应能力本身就是一个广泛的话题,而且通常是特定于应用程序的。一些模式:
- 查找主线程阻塞的位置。它可能会阻塞等待后台计算的结果。
- 查看主线程是否存在由于没有现成可用数据而不得不跳过某些操作的点。这在 UI / 渲染处理中特别常见 - 如果在需要渲染帧时数据还没有准备好,那么代码就没有更好的办法了,因为跳过渲染帧会导致 UI 中出现用户可见的卡顿。
希望这会有所帮助。
【解决方案2】:
有没有更好的方法来分析多线程代码?
我总是要问,因为它们不一样:
您是否正在寻找 1) 什么占用了挂钟时间,并且可以对其进行纠正以加快应用程序的速度,或者 2) 测量各种类型,如函数调用计数、CPU 自时间、CPU 包含时间、热路径等。 ?
假设答案是1,我和很多人使用的方法是简单pause the application,必要时在Visual Studio IDE下多次。
当你这样做时,它会暂停所有线程。
您可以显示每个线程的调用堆栈。这向您展示了它在等待什么,以及为什么。
一个或多个线程将在部分暂停时处于您认为可以避免的某些计算或某些系统等待或 I/O 的过程中。
你可以称之为“穷人的探查器”,
但它是如何超越分析器输出的:
您不必关心问题是在计算中还是在 I/O 中,或者猜测是哪一个并选择不同的分析方法。无论哪种方式,你都看到了。
如果您想知道函数/方法所用时间的包含部分,粗略地说,它是函数在堆栈上的样本部分。任何代码行也是如此。
如果你想知道排他(self)分数,那就是函数或代码行位于堆栈的end时。
如果您想知道函数 A 调用函数 B 所花费的时间比例,那就是 A 调用 B 的样本比例。
如果您对 A 通过中介调用 B 感兴趣,您也可以看到这一点(没有调用图可以告诉您)。
假设堆栈有 30 层深,以一些 I/O 结束,并且您想知道代码的哪一部分导致它这样做,只需向上扫描堆栈,查看每一行代码直到你找到它。
请注意,这可能不是“热路径”,因为可能有多种方法可以找到问题代码。
执行此操作时,您不仅可以看到负责的代码行,还可以检查相关数据变量的值。
探查器无法向您显示这些;你必须猜。
告诉你很多事情不是问题不会浪费你的时间,因为它们只占很小的百分比。
(有时人们认为他们只是在寻找小东西,比如 5% 或更少,同时做出乐观的假设,没有什么比这更大的了。分析器可以引导人们做出这样的假设,因为有了它你就看不到 em> 任何更大的东西。)
它允许您专注于您可以做某事的代码,您的代码,而不是系统代码。
您不必通过时间线来寻找感兴趣的区间。
当它让你等待时你暂停它;其他任何时候都很难暂停。
所以它会告诉你为什么它让你等待。