WinDbg 失控命令输出解释

WinDbg runaway command output explained

我有一个生产 CPU 问题,经过几天的常规 activity 突然 CPU 开始达到峰值。我保存了转储文件和 运行 !运行away 命令以获取最高 CPU 耗时线程的列表。输出如下:

User Mode Time
Thread Time
21:110 0 days 10:51:39.781
19:f84 0 days 10:41:59.671
5:cc4 0 days 0:53:25.343
48:74 0 days 0:34:20.140
47:1670 0 days 0:34:09.812
13:460 0 days 0:32:57.640
8:14d4 0 days 0:19:30.546
7:d90 0 days 0:03:15.000
23:1520 0 days 0:02:21.984
22:ca0 0 days 0:02:08.375
24:72c 0 days 0:02:01.640
29:10ac 0 days 0:01:58.671
27:1088 0 days 0:01:44.390

如您所见,输出显示我有 2 个线程:21 和 19,它们总共消耗了 20 多个小时的 CPU 时间,我能够跟踪其中 1 个线程的调用堆栈像这样:

~21s
!CLRStack

the output doesn't matter at the moment, let's call it the "X callstack"

我想要的是对 !运行away 命令输出的解释。据我了解,转储文件是应用程序当前状态的快照。所以我的问题是:

  1. 当转储过程只用了几秒钟时,运行away 命令如何显示线程 21 的 10:51 小时值?
  2. 这是否意味着我使用 !CLRStack 命令找到的 X 调用堆栈的特定 "instance" 已挂起超过 10 小时?或者它是 21 个线程执行他的整个 X 调用堆栈执行的总时间?如果是这样,那么 21 个线程负责如此多的 X 调用堆栈执行似乎很奇怪。据我所知,起源是一个网络请求(运行time 应该为每个调用分配一个随机线程)

我的猜测可以回答这两个问题:

也许 windbg 通过将线程调用堆栈的实际时间除以转储过程的范围来计算时间,因此如果例如 X 调用堆栈的具体执行花费了 1 秒,而整个转储过程花费了 3 秒秒 (33%),而过程 运行ning 总共 24 小时,输出将显示:

8 小时(24 小时的 33%)

我是对的,还是完全错了?

此答案旨在让 OP 易于理解。它并不打算在所有位和字节中都是正确的。

[...] and dividing it by the scope of the dumping process [...]

这种理解可能是万恶之源:转储一个进程只会让你及时得到进程在某个的状态。转储进程的持续时间为 0.0 秒,因为在操作期间所有线程都被挂起。 (所以,你的过程的相对时间,没有任何改变,时间是静止的;当然挂钟时间会改变)

您认为转储一个进程是为了在更长的时间内对其进行监视,但事实并非如此。转储进程只是需要时间,因为它涉及磁盘 activity 等

所以不,没有 "scope",因此您不能(这真的很难)用故障转储衡量性能问题。

How can the runaway command shows 10:51 hours value for thread 21, [...]

如果您只有一个每秒触发的计时器事件,您的 C# 程序如何知道该程序有多长 运行?答案是:它使用了一个变量并增加了值。

Windows 大致就是这样做的。 Windows 负责线程调度,每次重新调度线程时,它都会更新一个包含线程时间的变量。

写入故障转储时,OS 很久以前收集的信息已包含在故障转储中。

[...] when the dumping process only took a few seconds?

由于崩溃转储是由 WinDbg 的线程获取的,因此该线程占用的时间。您需要调试 WinDbg 并在 WinDbg 线程上执行 !runaway 以查看花费了多少 CPU 时间。可能是一个很好的练习,.dbgdbg(调试调试器)命令对您来说可能是新的;除此之外,这个特殊情况并没有什么帮助。

Does it mean that the specific "instance" of the X callstack I've found with the !CLRStack command is hang more than 10 hours?

没有。这意味着在您创建故障转储的时间点,执行了该特定方法。不多也不少。

此信息与 !runaway 无关,因为该线程可能在很长一段时间内一直在做完全不同的事情,但刚刚结束。

or it's the total time the 21 thread executed his whole X callstacks executions?

没有。故障转储不包含如此详细的性能数据。您需要像 JetBrains dotTrace 这样的性能分析器来获取该信息。探查器会经常查看调用堆栈,然后聚合相同的调用堆栈并得出每个调用堆栈的 CPU 时间。