繁体   English   中英

调试高CPU使用率

[英]Debug High CPU Usage

我有一个使用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

使用WinDbg调试性能问题将需要进行几次转储。 一个转储只是时间上的快照,不能为您提供完整的图片。

现在(在进行转储时),线程可能什么都不做。 您确定转储时使用了100%CPU吗? 还是在进行转储前一毫秒内从100%恢复?

!runaway显示的值是程序整个生命周期内的累积值。 这只是告诉您该线程在过去已经工作了很多。 它不会告诉您现在正在做什么或将来将要做什么。

尽管它是由马克·鲁西诺维奇(Mark Russinovich)和其他一些专家完成的,但对于初学者而言,这并不是一件容易的事。

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

如果您确实想采用这种方法,请至少将ProcDump(SysInternals)-ma -c -n -s选项一起使用以收集一些不错的CPU高转储。

尝试从进程资源管理器和将procmon Sysinternals的 尽管它可能无法立即为您提供答案,但它为流程提供了许多上下文,并可能有助于您了解应用程序正在执行的不同操作。 在ProcMon中,只需将过滤器设置为您感兴趣的任何ProcessName。 在进程资源管理器中,找到进程,右键单击->属性。 您将看到诸如线程和TCP连接之类的内容以及许多其他内容。

一切都很好。 这里有一个问题,你用windbg得到一个堆栈跟踪,有一些建议,然后个唱当你说出了神奇的话“生产环境”世界变了。

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

对于此应用程序,一旦达到100%峰值,它就不会重新启动该应用程序。

基本上,这意味着它已损坏,并且已严重损坏。

我还观察到您有一个多线程应用程序,这使得找出问题出处变得更加困难。

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

好吧,基本上列表是:

  • 调试
  • 剖析
  • 运行单元测试
  • ...清单不停。

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

目前,这对您没有任何帮助。 也就是说,修复错误后,我认为长期考虑这些问题很重要。 我不确定这是否适用于您的情况-但根据我的经验,您通常会遇到类似这样的错误,这意味着您仍有很多工作要做。

它已经坏了,所以不可能破解

首先,让我们对其进行修复。 让我们面对残酷的事实。 它已经被破坏了,所以如果我们暂时将其破坏,那就很好了。

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

获得像Red Gate ANTS这样的专业性能分析器。 安装,开始。 另外,您需要在生产服务器上放置PDB和源代码(与开发计算机相同的文件夹结构),并且我可能会在其中放置调试DLL。 这只是暂时的,在我们发现错误之后,这些东西应该会再次消失。 正如我所说,您不希望在生产环境中使用此功能。

不要对您的生产应用程序保持温和,仅对源代码使用“行级”或“方法级”配置文件。 它不会破坏您的应用程序,只会使其变慢。 您也可以“暂停”探查器,这基本上意味着不再收集任何采样数据-在错误到达之前,这是一个好主意。

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

调试器

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

sysinternals的process explorer器是一种可能的堆栈跟踪应用程序。 以管理员身份运行,双击进程,转到“线程”选项卡,然后为每个线程单击“堆栈跟踪”(或双击),直到发现有趣的东西。

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

祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM