我的手上有一个严重的头疼。我正在调查我们的应用程序中的WPF组件的性能问题。
我们的.net应用程序非常庞大,几乎全部采用Windows窗体。作为新计划的一部分,我们使用丰富的WPF ui重写了我们的核心组件之一。有很多WinForms< - > WPF互操作正在将这个东西粘在一起,我怀疑这可能与我所看到的有些相关。
当我在ANTS探查器中分析慢速操作时,我发现函数UnsafeNativeMethods.IntGetMessageW内发生了很多活动。 ANTS报告了与我们所有业务逻辑和wpf渲染内容相结合的CPU活动。该函数没有使用循环的托管代码下线,因此无论IntGetMessageW正在做什么,我都会追求。
我对win32编程并不是特别精通,但我知道在该上下文中消息循环的基础知识。我在这里看到的并不是我们手动完成的任何事情 - 在我们的代码中,我们不会直接与底层的messageloop本身或者可以在WPF调度程序上访问的任何更复杂的东西进行交互。
我们这里讨论的WPF组件是从Window继承而来的(即它不仅仅是一个控件/用户控件),我们使用ShowDialog从我们更高级别的逻辑中显示它,用于在旧的WinForms版本上调用ShowDialog零件。我们在WPF组件中使用了一些WindowsFormsIntegrationHost控件,以保持与我们在WPF中无法重写的一些现有部分的兼容性。
我已经研究了好几天了,但是从来没有发现过很多东西。我一直在寻找关于输入消息(鼠标和键盘)的模糊相关帖子,但我不知道我能做些什么来验证它;我已经尝试过屠宰代码来删除我能做的所有鼠标/键盘操作。
我很难到达任何地方,主要是因为这行代码是完全孤立的(不是我可以指出实际上来自我们代码的任何内容的父或子),并且完全不透明它正在做什么。
这是ShowDialog函数的ANTS调用图的图像,显示了到达此处的调用路径:
我完全意识到这可能是必须要作为WPF的一部分完成的事情(尽管我们在WPF中编写的其他组件不显示此行为),或者这只是ANTS分析器中的一个非常奇怪的错误,但此时我需要以某种方式验证它。如果有人能告诉我这里发生了什么或者可能会发生什么 - 或者指出我可以通过某种方式自己解决这个问题,我将以你的方式引导各种善意的业力。
更新: 在下面的一些讨论中,这是ANTS的另一个视图 - 这个更好地说明了我所遇到的混乱(这是在“CPU时间”模式下的ANTS视图)。我匆忙审查了部分代码,但没有系统相关的功能:
感谢您的期待!
答案 0 :(得分:3)
是的,这很正常。任何GUI应用程序总是执行GetMessageW(),等待Windows向其发送消息。它实际上并没有烧掉CPU周期,只是在内部同步对象上被阻塞,直到发出某种UI事件的信号。
这当然会使分析UI应用程序变得困难,您真的需要单元测试来测试应用程序的子组件。
答案 1 :(得分:1)
在分析应用程序时,您需要区分方法中花费的时间和消耗的 CPU周期。许多分析工具会向您显示在一个方法中花费的总时间 - 在像GetMessageW
这样的东西的情况下会非常高。 GUI应用程序的主线程的所有活动似乎都在该方法中发生。这不一定是个问题,但是......这可能只是主要的消息泵等待同步对象而不是实际消耗周期。
我建议您首先使用ANTS探查器中的采样功能来识别最常被称为 的方法,并将这些方法与消耗最多CPU周期的方法相关联。 完成后,您可以决定在哪里检测应用程序以进一步深入了解,并了解调用图对于CPU密集程度最高的位置的外观。
您应该首先怀疑自己的代码。很少有类似WPF或Win32基础架构的东西导致性能低下或CPU利用率过高。可能,问题出在您的实现中 - 它可以帮助您全面了解CPU周期在程序中的使用情况。
我建议您也花一些时间learning the capabilities of the profiler最有效。在您了解他们试图向您展示的内容之前,Profilers可能是复杂且令人困惑的工具。如果您还没有这样做,RedGate的联系人应该是一个很好的起点。例如,时间轴视图实际上可能是开始查看高CPU活动发生位置的好地方,并将分析限制在执行代码的那些段中。
调用图是ANTS中另一个有用的工具,因为它可以帮助您深入研究最昂贵的代码区域。关键是要确保您正在查看总体费用,而不仅仅是总时间。
答案 2 :(得分:0)
看起来你的消息泵正在大量涌现。可能很有趣,看看你的消息队列填充了什么样的消息。你能在窗口上使用Spy ++看看发生了什么吗?
修改强>
我误解了这个问题。
Hans Passant是对的,你的程序正在等待GetMessage处理一些事件。
答案 3 :(得分:0)
我在搜索有关同一问题的信息时发现了这一点。我会添加我所知道的内容,看看它是否有帮助:
我在WinXP上运行 - WPF框架在Vista和Win7中比在XP中更集成。其中一些可能是由于WPF如何在XP桌面上运行,而不是在其中运行。
我正在运行一个纯本机WPF应用程序 - 没有WinForms或其他代码。
我试图确定为什么简单地滚动窗口会消耗100%的CPU并且在执行此操作时会出现断断续续的情况。
运行AQtime性能分析器,我发现IntGetMessageW占用了100%CPU使用率的最大部分。这不是因为IntGetMessageW正在等待消息,而是函数实际正在做的事情。
我还没有看到的一件事是,IntGetMessageW可能从来都不是一个快速的方法,也许WPF只是过度使用它。 WPF中的数据绑定可能使用本机Win32消息泵来更新WPF中的依赖项属性。如果是这种情况,可能是我的窗口只有太多的绑定。