WPA 图表:CPU Sampling

Posted by sssa2000 on 2017-05-02

本文将简单谈一下 WPA 中的某一类图表 CPU Sampling。

当获得etw的快照之后,就能够使用wpa来进行分析。获取etw的快照可以使用wpa、也可以使用xperf,也可以使用UIforETW。我个人喜欢用 UIforETW。使用UIforETW 获得Tracing的快照之后,可以直接在UIforETW的界面直接选择使用WPA 打开这个快照。

CPU Sampling 类型的图表是最常用的图表。其实在VisualStudio中已经有这样的功能了,就是VS自带的性能Profile功能。这里只是换了个展示的方式罢了。

CPU Sampling 指的是利用采样技术来获取程序运行时间相关的数据的方法。你可以在 WPA 的Computation\CPU Usage(Sampled) 下找到这类的数据。

在CPU Usage(Sampled) 下 有多种图表,这些都是属于CPU Usage(Sampled) 的图表。如下图:

DPC and ISR Usage by Module, Stack

一般来说如果不是做硬件相关或者驱动开发相关的,这个图表可以忽略。

不过概念还是应该有所了解的。

  • ISR:Interrupt Service Routines 可以理解为当硬件中断发生时的回调函数, 这是必须马上做的事情,比如硬件中断,响应鼠标点击。
  • DPC:Deferred Procedure Call Details 延迟过程调用可以推迟做的事情,比如大数据拷贝,U盘拷贝电影。

在windows中,计算机的硬件(例如网卡)如果要使用cpu资源,那么会由硬件生成一个中断,windows拿到中断后,会挂起当前执行的线程,转而执行该中断相关的代码,也就是 ISR。

当执行ISR的过程中,处理器无法做其他的事情,包括响应其他中断。所以,ISR必须快速处理。为了减少执行isr的时间,isr会调度DPC来执行中断中必须完成点任务。对每一个逻辑处理器来说,wondiws维护了一个队列来调度dpcs。Dpcs 的优先级在所有线程优先级之上,逻辑处理器需要完成当前队列中所有的dpc后,才能转而执行线程。

在windows中只要是 ISR 或者 DPC 的代码,优先级都是最高的,所以当处理器执行ISR 或者 DPC 的代码时,用户态代码的线程都是被挂起的。这个特性可能会导致问题,当用户态的线程需要一定的吞吐量或者需要精确计时,例如播放音频或者视频。如果此时处理器在执行 DPCs或者 ISRs,那么可能导致无法及时的完成。

Flame By Process Stack

Flame graph 又叫 火焰图。 这种图表的优势是能够直观的表达:父子关系、时间长短。
在 WPA 的 Flame By Process Stack 图表中,展现的是每个进程中比较耗时的调用栈。注意这里不是每一个时刻的调用栈,而是tracing这段时间内的所有调用栈中,选出来的最耗时的几个。利用火焰图展示出来。

例如在下图中,x轴表示时间,y轴表示的是调用栈的深度。
每一条横杠表示的就是一个调用函数,越底部的表示在调用栈底部,越上面的表示越接近调用栈的栈顶。
从图中可以看出这么几个信息:

  • 这段时间内最深的调用栈在哪。看图中哪里最高,哪里就是最深的调用栈。
  • 哪个调用栈最耗时。看图表底部哪个函数延续了最长时间,那么这个调用栈也就耗费最长。

当我们选中上面的图表中的某一个函数:engine.dll!H3D::Task::ProcessTaskStep,在火焰图中可以很清晰的看到这个函数以及它发起的函数调用,占用整个tracing时间的比例,以及最深的函数调用发生在哪

当选中另一个函数engine.dll!H3D::IOLoadCHRTask::OnParseFile 后,火焰图的变化:

所以,火焰图最适合用在以下情景:

  • 当你想看某个进程的比较耗时的调用栈,并且想看这个栈的深度和持续时间

Randomascii exculsive (module and function)

这个图表是 UIforETW 定制的图表。意思是“函数独占时间信息”。和VS中的 profiler 一样。

这个表格中按照进程、线程 列出了函数独占时间最高的几个函数。如果加载了pdb,就能够看到比较详细的信息。

这里唯一需要解释一下的就是表格中的Count和Weight的含义。
前面提到这里的图表都是通过CPU采样的技术获得的数据,WPT中采用的采样频率默认是1KHz,也就是每毫秒一次。

  • Count表示的是在tracing这段时间内,这个函数命中了多少个采样点。
  • Weight表示的是这些采样点的时间总和。

Randomascii inculsive (stack)

这个图表也是UIforETW定制的,表达的意思是非独占函数花费的时间。

非独占的视图的价值在于确认:耗时的调用栈在哪,谁发起的?
独占的视图用来确认,哪个函数自身花费的时间最长。

Utilization by COFF Group, Module, Function

其实。。。。我也没搞明白这个的具体含义。也没有找到相关的资料介绍。

Utilization by Process and Thread

Utilization by xxx的图表有好多,我觉得最有用的还是这个,其他都大同小异。
这个图表能够显示每一个进程中的每一个线程,在每个采样点时刻使用CPU的情况。
这个图表很有用,因为它能够根据时刻来找到哪个进程、哪个线程占用了CPU资源。能够直观的看到这些线程什么时候繁忙什么时候空闲了。

这里最关键的价值在于它是能够按照时间来检索,配合其他的图表能够发挥很大的威力。

Utilization by xxx Stack

这里包括两个图表:

  • Utilization by Process Stack
  • Utilization by Process, thread Stack

其实就是按进程和线程组织的 非独占的调用栈信息。

总结

我个人最喜欢用 先用 Utilization by Process and Thread 看一下各个进程和线程利用CPU的情况,然后把不想看的进程和线程剔除掉,用 Randomascii inculsive (stack) 和 Randomascii exculsive (module and function) 看看有没有直接能看到的信息