12

我手上有一个严重的挠头。我正在调查我们应用程序中 WPF 组件的性能问题。

我们的 .net 应用程序非常大,而且几乎完全采用 Windows 形式。作为一项新计划的一部分,我们使用丰富的 WPF ui 重写了我们的核心组件之一。有很多 WinForms<-->WPF 互操作与这个东西粘合在一起,我怀疑这可能与我所看到的有关。

当我在 ANTS 分析器中分析缓慢的操作时,我看到函数 UnsafeNativeMethods.IntGetMessageW 内部发生了很多活动。ANTS 报告的 CPU 活动与我们所有的业务逻辑和 wpf 渲染内容的组合一样多。该函数没有使用循环的托管代码下线,因此无论 IntGetMessageW 正在做什么,这就是我所追求的。

我不是特别精通 win32 编程,但我知道在这种情况下消息循环的基础知识。不过,我在这里看到的都不是我们手动执行的任何操作——在我们的代码中,我们没有直接与底层消息循环本身进行交互,也没有与任何可以在 WPF 调度程序上访问的更复杂的东西进行交互。

我们这里讨论的 WPF 组件是继承自 Window 编写的(即,它不仅仅是一个控件/用户控件),我们使用 ShowDialog 来展示它,该逻辑是在我们用于在该组件的旧 WinForms 版本上调用 ShowDialog 的更高级别逻辑之外的。我们在 WPF 组件内部使用了一些 WindowsFormsIntegrationHost 控件,以保持与我们现有的一些无法在 WPF 中重写的部分的兼容性。

我已经研究了好几天了,但从来没有发现很多事情要做。我一直在寻找有关输入消息(鼠标和键盘)的模糊相关帖子,但我不知道我能做些什么来验证这一点;我已经尝试过删除代码以删除我可以进行的所有鼠标/键盘操作。

我很难到达任何地方,主要是因为这行代码是完全隔离的(不是我可以指出实际上来自我们的代码的任何东西的父或子),并且对于它正在做什么完全不透明。

这是 ShowDialog 函数的 ANTS 调用图的图像,显​​示了到达此处的调用路径: 替代文字

我完全意识到这可能只是作为 WPF 的一部分必须完成的事情(尽管我们在 WPF 中编写的其他组件不会显示这种行为),或者这只是 ANTS 探查器中的一个非常奇怪的错误,但在这一点我需要以一种或另一种方式验证它。如果有人能告诉我这里正在发生或可能发生的事情——或者给我指出一些我自己能够弄清楚的方法,我会按照你的方式引导各种善业。

更新:针对下面的一些讨论,这是 ANTS 的另一种观点——这个观点更好地说明了我的困惑(这是“CPU 时间”模式下的 ANTS 视图)。我匆忙审查了我们的部分代码,但没有一个与系统相关的功能:

替代文字

感谢您的关注!

4

4 回答 4

5

是的,这很正常。任何 GUI 应用程序总是在执行 GetMessageW(),等待 Windows 向它发送消息。这样做实际上并没有消耗 CPU 周期,只是在内部同步对象上阻塞,直到发出某种 UI 事件信号。

这当然会使分析 UI 应用程序变得困难,您确实需要测试应用程序子组件的单元测试。

于 2010-11-08T20:19:37.113 回答
3

在分析应用程序时,您需要区分方法所花费的时间和所消耗的CPU 周期许多分析工具会向您显示在一个方法中花费的总时间——在类似的情况下,GetMessageW这将是相当高的。GUI 应用程序的主线程的所有活动似乎都发生在该方法中。但是,这不一定是问题……这可能只是等待同步对象的主要消息泵,而实际上并未消耗周期。

我建议您首先使用 ANTS 分析器中的采样功能来识别最常调用的方法,并将这些方法与消耗最多 CPU 周期的方法相关联。完成此操作后,您可以决定在哪里检测应用程序以进一步深入了解 CPU 密集型位置的调用图是什么样的。

您应该首先怀疑自己的代码。WPF 或 Win32 基础结构之类的东西很少会导致性能低下或 CPU 利用率高。很可能,问题出在您的实现中——它可以帮助您全面了解 CPU 周期在您的程序中的使用情况。

我建议您也花一些时间学习探查器的功能以使其最有效。探查器可能是复杂且令人困惑的工具,直到您了解它们试图向您展示的内容。如果您还没有这样做,RedGate 的链接教程应该是一个很好的起点。例如,时间线视图实际上可能是开始查看高 CPU 活动发生的位置并将您的分析限制在那些已执行代码段的好地方。

替代文字

调用图是 ANTS 中另一个有用的工具,因为它可以帮助您深入研究最昂贵的代码区域。关键是要确保您着眼于总体成本,而不仅仅是总体时间

替代文字

于 2010-11-08T20:30:15.953 回答
1

我在搜索有关同一问题的信息时发现了这一点。我将添加我所知道的,看看是否有帮助:

我在 WinXP 机器上运行 - WPF 框架在 Vista 和 Win7 中比在 XP 中的集成度更高。其中一些可能是由于 WPF 如何在 XP 桌面“顶部”而不是在其中运行。

我正在运行一个纯原生 WPF 应用程序 - 没有 WinForms 或其他代码。

我遇到了这个问题,试图确定为什么简单地滚动窗口会消耗 100% 的 CPU 并在执行此操作时出现口吃。

运行 AQtime 性能分析器,我看到 IntGetMessageW 占据了 100% CPU 使用率的最大部分。这不是因为 IntGetMessageW 等待消息,而是函数实际在做的事情。

我还没有研究过的一件事是,也许 IntGetMessageW 从来都不是一种快速的方法,也许 WPF 只是过度使用了它。WPF 中的数据绑定可能使用本机 Win32 消息泵来更新 WPF 中的依赖属性。如果是这种情况,可能是我的窗口绑定太多。

于 2010-12-15T21:30:33.027 回答
0

看起来你的消息泵正在抽很多。看看您的消息队列中填充了什么样的消息可能会很有趣。你可以在你的窗口上使用 Spy++ 来查看发生了什么吗?

编辑

我误解了这个问题。

Hans Passant 是对的,您的程序只是在等待 GetMessage 处理某个事件。

于 2010-11-08T20:19:33.800 回答