调试高CPU使用率

时间:2015-06-03 21:26:17

标签: c# performance debugging cpu-usage ucma

我有一个使用UCMA(统一通信管理API)4.0 SDK的托管应用程序。我正在尝试调试应用程序使用100%的CPU并且系统挂起的问题。我已经使用SOS扩展来尝试调试根本原因。我目前卡住了。我设法找到占用CPU时间的线程ID,但它们大多是非托管线程。我真的需要帮助。

线程15,18,16,17,19,20都是非托管线程并具有相同的调用堆栈。线程9,10,11,12,13,14都是非托管线程,并且也具有相同的调用堆栈。另一个问题是线程21和22似乎在等待一个事件,那么为什么它们被认为是消耗CPU时间的失控线程呢?

有谁知道ZwRemoveIoCompletionEx在做什么?这是像NtWaitForMultipleObjects一样处于休眠状态的东西,还是可以扼杀CPU时间?在此应用程序的情况下,一旦它达到100%,它将永远不会重新启动,直到应用程序重新启动。

0:000> !loadby sos clr
0:009> .time
Debug session time: Wed May 27 15:47:52.000 2015 (UTC - 4:00)
System Uptime: 31 days 1:05:59.329
Process Uptime: 31 days 1:01:27.000
  Kernel time: 0 days 21:44:58.000
  User time: 1 days 16:51:40.000
0:000> !runaway
 User Mode Time
  Thread       Time
  15:113c      0 days 3:46:30.510
  18:1418      0 days 3:18:07.135
  16:1404      0 days 3:08:01.009
  17:140c      0 days 3:07:19.310
  19:1428      0 days 3:04:56.943
  20:1434      0 days 2:52:51.664
  22:1450      0 days 0:47:50.153
   9:11dc      0 days 0:45:02.904
  21:1440      0 days 0:43:34.623
  12:13cc      0 days 0:33:35.298
  11:1250      0 days 0:32:50.386
  14:fbc       0 days 0:31:57.018
  10:1178      0 days 0:29:12.920
  13:13c4      0 days 0:28:42.048
   2:fa8       0 days 0:03:11.678
   4:1164      0 days 0:02:45.080

0:015> kb
RetAddr           : Args to Child                                                           : Call Site
000007fe`fd36546f : 00000000`272946f0 000007fe`e5394b29 00000000`27295b18 00000000`27295b18 : ntdll!ZwRemoveIoCompletionEx+0xa
00000000`7700c089 : 00000000`1c4981e0 00000000`00000001 00000000`00000001 00000000`00000000 : KERNELBASE!GetQueuedCompletionStatusEx+0xdf
000007fe`e51b634b : 00000000`000009b0 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!GetQueuedCompletionStatusExStub+0x19
000007fe`e538fc0b : 00000000`1c4981e0 00000000`1c4981e0 000007fe`e5905340 00000000`00000000 : rtmpal!RtcPalTaskQueueDequeue+0x17
000007fe`e538f960 : 00000000`1f55fcf0 00000000`00000000 00000000`1db59eb0 00000000`1f55fcf0 : Microsoft_Rtc_Internal_Media!CStreamingEngineImpl::EngineWorkerThread+0x267
000007fe`e51b33c8 : 00000000`00000000 00000000`1c40a6a0 00000000`1c4a4f80 00000000`00000000 : Microsoft_Rtc_Internal_Media!CStreamingEngineImpl::EngineWorkerThreadProc+0xf0
000007fe`f22a3d67 : 00000000`00000000 00000000`1c40a6a0 00000000`00000000 00000000`00000000 : rtmpal!RtcPalSetSchedulerPolicy+0x194
000007fe`f22a3f0e : 000007fe`f233cdb0 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!beginthreadex+0x107
00000000`76fd652d : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!endthreadex+0x192
00000000`7720c541 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d

0:022> !clrstack
OS Thread Id: 0x1450 (22)
        Child SP               IP Call Site
000000001fdcda68 000000007723186a [HelperMethodFrame_1OBJ: 000000001fdcda68] System.Threading.WaitHandle.WaitMultiple(System.Threading.WaitHandle[], Int32, Boolean, Boolean)
000000001fdcdba0 000007fee968c64c System.Threading.WaitHandle.WaitAny(System.Threading.WaitHandle[], Int32, Boolean)
000000001fdcdc00 000007fe8e097a70 Microsoft.Rtc.Internal.Media.RtpEventHandlerThread.EventHandlerThreadProc()
000000001fdce8d0 000007fee973d0b5 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000001fdcea30 000007fee973ce19 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
000000001fdcea60 000007fee973cdd7 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
000000001fdceab0 000007fee96b0301 System.Threading.ThreadHelper.ThreadStart()
000000001fdcedc8 000007feed44ffe3 [GCFrame: 000000001fdcedc8] 
000000001fdcf0f8 000007feed44ffe3 [DebuggerU2MCatchHandlerFrame: 000000001fdcf0f8]

0:021> kb
RetAddr           : Args to Child                                                           : Call Site
000007fe`fd331430 : 00000000`00190398 00000000`771f3a92 00000000`c0000008 00000000`00000110 : ntdll!NtWaitForMultipleObjects+0xa
00000000`76fd1220 : 00000000`1edefc18 00000000`1edefc00 00000000`00000000 00000000`00da7a64 : KERNELBASE!WaitForMultipleObjectsEx+0xe8
000007fe`e53bc322 : 00000000`0000cae8 00816179`f67cb320 00000000`1c497eb0 00000000`1edefce0 : kernel32!WaitForMultipleObjects+0xb0
000007fe`e51b33c8 : 00000000`00000000 00000000`00000000 00000000`1dad4630 00000000`1c4a5160 : Microsoft_Rtc_Internal_Media!CStreamingEngineImpl::TimerThreadProc+0x37e
000007fe`f22a3d67 : 00000000`00000000 00000000`1dad4630 00000000`00000000 00000000`00000000 : rtmpal!RtcPalSetSchedulerPolicy+0x194
000007fe`f22a3f0e : 000007fe`f233cdb0 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!beginthreadex+0x107
00000000`76fd652d : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!endthreadex+0x192
00000000`7720c541 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d

0:013> kb
RetAddr           : Args to Child                                                           : Call Site
000007fe`fd36546f : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!ZwRemoveIoCompletionEx+0xa
00000000`7700c089 : 00000000`00000000 00000000`000000b7 00000000`00000001 00000000`1c4a4a40 : KERNELBASE!GetQueuedCompletionStatusEx+0xdf
000007fe`e51c0fef : 000007fe`e5905340 000007fe`e53eb764 00000000`00000000 00000000`1dac2ab0 : kernel32!GetQueuedCompletionStatusExStub+0x19
000007fe`e53eaf4b : 000007fe`e5905340 00000000`35bdd608 00000000`00000001 00000000`1f17fc20 : rtmpal!RtcPalIOCP::GetQueuedCompletionStatus+0x18f
000007fe`e53eac6d : 00000000`00000510 00000000`0000dddd 00000000`1dad9fe0 00000000`1f17fc80 : Microsoft_Rtc_Internal_Media!CTransportManagerImpl::TransportWorkerThread+0xe7
000007fe`e51b33c8 : 00000000`00000000 00000000`1c409460 00000000`1c4a4e40 00000000`00000000 : Microsoft_Rtc_Internal_Media!CTransportManagerImpl::TransportWorkerThreadProc+0x13d
000007fe`f22a3d67 : 00000000`00000000 00000000`1c409460 00000000`00000000 00000000`00000000 : rtmpal!RtcPalSetSchedulerPolicy+0x194
000007fe`f22a3f0e : 000007fe`f233cdb0 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!beginthreadex+0x107
00000000`76fd652d : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : msvcr110!endthreadex+0x192
00000000`7720c541 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x1d

3 个答案:

答案 0 :(得分:1)

使用WinDbg调试性能问题需要多次转储。一次转储只是一个时间快照,并没有给你一个完整的图片。

现在(在转储时),线程可能都无所事事。你确定它在使用转储时使用了100%的CPU吗?或者在转储之前的一百毫秒内从100%恢复?

!runaway显示的值是程序整个生命周期中的累计值。这只是告诉你线程在过去已经运行了很多。它并没有告诉你它现在正在做什么或将来会做什么。

虽然马克·鲁西诺维奇和其他一些裂缝已经完成了,但对于初学者来说这不是一件好事。

由于您需要许多转储才能获得完整的图片,因此请使用其他工具来分析性能问题。典型的工具称为分析器,例如Redgate的ANTS探测器或JetBrains的dotTrace。

如果你真的想这么做,至少使用带有-ma -c -n -s选项的ProcDump (SysInternals)来收集一些不错的高CPU转储。

答案 1 :(得分:0)

SysInternals尝试Process Explorer和ProcMon。虽然它可能不会立即给你答案,但它提供了很多关于这个过程的背景,并且可能有助于揭示应用程序正在做的不同事情。在ProcMon中,只需将过滤器设置为您感兴趣的ProcessName即可。在Process Explorer中,找到该过程,右键单击 - >属性。您将看到线程和TCP连接以及许多其他内容。

答案 2 :(得分:0)

一切都很顺利。有一个问题,你使用windbg得到一个堆栈跟踪,有一些建议然后 wham 当你说出“生产环境”这个神奇的词语时,世界会发生变化。

关于你的其他帖子,我注意到了这一点:

  

在此应用程序的情况下,一旦它达到100%,它将永远不会恢复,直到应用程序重新启动。

基本上这意味着它已经坏了,而且它已经坏了。

我还注意到你有一个多线程应用程序,这使得更难找出出错的地方。

在生产环境中不应该做的事情

嗯,基本上列表是:

  • 调试
  • 仿形
  • 运行单元测试
  • ......列表一直在继续。

如果你有100%的CPU峰值永远不会下降,那么看看其余的软件开发过程可能也很有趣。你有自动(功能)测试代码吗?您是否使用代码覆盖来检查您测试的内容?简而言之:你相信你有一个稳定的环境吗?

目前,这对你没什么帮助。也就是说,在修复bug之后,我认为从长远来看考虑这些问题很重要。我不确定这是否适用于您的情况 - 但根据我的经验,您有这样的错误这一事实通常意味着您仍有一些艰苦的工作要做。

它已经坏了,所以打破它是不可能的

首先,让我们解决它。让我们面对残酷的事实。它已经坏了,所以如果我们暂时打破它,那就没事了。

问题是100%CPU。您需要知道的是CPU使用率在代码中的位置。分析器是最适合的工具。

让自己成为Red Gate ANTS等专业性能分析师。安装,开始。此外,您需要将PDB和源代码(与开发机器相同的文件夹结构)放在生产服务器上,我可能会将调试DLL放在那里。这一切都只是暂时的,在我们发现了我们的错误后,这些东西都应该再次消失。正如我所说,你不希望在生产环境中使用它。

不要对您的生产应用程序保持温和,只需在源代码上使用“行级别”或“方法级别”分析。它不会破坏你的应用程序,只会让它变慢。你也可以“暂停”探查器,这基本上意味着不再收集采样数据 - 这是一个好主意,直​​到bug出现。

当错误出现时,再次继续探查器,并捕获一些数据。

<强>调试器

根据我的经验,在应用程序上进行调试和“堆栈跟踪”有时会破坏它们。我不确定这种情况何时发生 - 但在上述生产环境中,您应该在停止调试过程后重新启动正在调试的应用程序。

一个可能的堆栈跟踪应用程序是来自sysinternals的process explorer。以管理员身份运行,双击该过程,转到“线程”选项卡,然后单击每个线程的“堆栈跟踪”(或双击),直到找到有趣的内容。

如果你发现了WaitSleep,那可能就好了。

祝你好运!