一:背景

准备开个系列来聊一下 PerfView 这款工具,熟悉我的朋友都知道我喜欢用 WinDbg,这东西虽然很牛,但也不是万能的,也有一些场景他解决不了或者很难解决,这时候借助一些其他的工具来辅助,是一个很不错的主意。

很多朋友喜欢在项目中以记录日志的方式来监控项目的流转情况,其实 CoreCLR 也是这样的,参考如下代码:


void gc_heap::fix_allocation_context (alloc_context* acontext, BOOL for_gc_p,
BOOL record_ac_p)
{
dprintf (3, ("Fixing allocation context %Ix: ptr: %Ix, limit: %Ix",
(size_t)acontext,
(size_t)acontext->alloc_ptr, (size_t)acontext->alloc_limit));
} void gc_heap::background_sweep()
{
//concurrent_print_time_delta ("finished with mark and start with sweep");
concurrent_print_time_delta ("Sw");
dprintf (2, ("---- (GC%d)Background Sweep Phase ----", VolatileLoad(&settings.gc_index))); //block concurrent allocation for large objects
dprintf (3, ("lh state: planning"));
} void gc_heap::background_ephemeral_sweep()
{
dprintf (3, ("bgc ephemeral sweep"));
}

那这些日志会送到哪里去呢,当然是 Windows 的 ETW 了,那有什么工具可以方便提取呢? PerfView 就是这么其中一款。

这一篇我们做一个 CPU 爆高的场景下如何寻找 热点函数 的例子,看看如何用 PerfView 去挖。

二:PerfView 寻找热点函数

很多场景下的 CPU 高,是因为某个或者某几个线程在高频的执行某个方法,有可能是死循环,有可能是陷入了CPU密集型方法内,解决这个问题一个好的思路就是对 CPU 进行采样,比如我的 12 核电脑。


0:000> !cpuid
CP F/M/S Manufacturer MHz
0 6,5,2 2592
1 6,5,2 2592
2 6,5,2 2592
3 6,5,2 2592
4 6,5,2 2592
5 6,5,2 2592
6 6,5,2 2592
7 6,5,2 2592
8 6,5,2 2592
9 6,5,2 2592
10 6,5,2 2592
11 6,5,2 2592

1. 如何采样

采样的原理就是周期性的去看下当前的 CPU 核中运行的几个线程正在执行什么方法, 当采样到了几万个或者几十万个样本之后,就可以对这些采集到的方法进行分组排序来找到 topN,那些 TopN 的方法自然就是导致 CPU 爆高可能的诱因。

windbg 有一个 !running 命令可以用来显示当前处理器中正在运行的线程。


lkd> !running System Processors: (0000000000000fff)
Idle Processors: (000000000000065e) Prcbs Current (pri) Next (pri) Idle
0 fffff80268a33180 ffffaf8ec9bd8080 (15) fffff8026b526600 ................
5 ffffd900e1700180 ffffaf8eca36b080 ( 8) ffffd900e170b340 ................
7 ffffd900e1900180 ffffaf8ec2f18080 ( 8) ffffd900e190b340 ................
8 ffffd900e1a00180 ffffd900e1a0b340 ( 0) ffffd900e1a0b340 ................
11 ffffd900e1d00180 ffffaf8eb6bee080 ( 8) ffffd900e1d0b340 ................

接下来写一个程序,让其中一个线程无限循环,然后通过 PerfView 去找这个热点。


internal class Program
{
static void Main(string[] args)
{
Task.Run(() => Test1()); //Test1 故意死循环
Task.Run(() => Test2()); //Test2 是一个正常函数 Console.WriteLine("我是主线程!");
Console.ReadLine();
} static void Test1()
{
var i = 10;
var b = true; while (i > 0)
{
b = !b;
}
} static void Test2()
{
for (int i = 0; i < 10000; i++)
{
var j = string.Join(",", Enumerable.Range(0, 100));
} Console.WriteLine("Test执行结束");
}
}

2. 使用 PerfView 采样

点击菜单中的 Collect -> Collect ,弹出如下面板。

在这个面板中,选中如下几项。

1)CPU Samples:

设置对 CPU 进行采样。

2)CPU Sample Interval Msec

设置采样的频次是 1ms/次。

3)Max Collect Sec

设置总共采样多少秒,这里设置为 15 秒。

4).NET Symbol Collection

用来从微软符号服务器上拉取符号,和采样无关哈。

上面都设置完毕后,就可以点击 Start Collection 采集了,不出意外的话,15s 之后你就会看到如下的截图。

接下来点击 CPU Stacks,在弹出的面板中选中我们的 程序,双击之后就可以打开如下面板。

从图中可以看到,当前采样了 15622 个样本,符合 15 * 1000 ,接下来把上面的 GroupPats 默认分组给清掉,截图如下:

从图中可以看到当前 Test1() 方法在 15622 个样本中占比 97.9%,命中次数高达 15290 次,很明显这是一个绝对的 热点函数,接下来就是翻源码为什么 Test1 这么高频?

如果你想看鸡肋的 火焰图,可以点击 Flame Graph 列表项。

好了,本篇就先聊这么多吧。

PerfView专题 (第一篇):如何寻找热点函数的更多相关文章

  1. 第一篇博文:PHP函数原型中的可选参数写法为什么这么写?

    第一篇,算是开始吧.简单写点儿东西. 刚开始学PHP,在看PHP Manual时遇到一个问题:含可选参数的函数原型中,可选参数的写法看不懂. 例如explode函数 array explode ( s ...

  2. asp.net signalR 专题—— 第一篇 你需要好好掌握的实时通讯利器

    一:背景 我们知道传统的http采用的是“拉模型”,也就是每次请求,每次断开这种短请求模式,这种场景下,client是老大,server就像一个小乌龟任人摆布, 很显然,只有一方主动,这事情就没那么完 ...

  3. 深入理解javascript函数系列第一篇——函数概述

    × 目录 [1]定义 [2]返回值 [3]调用 前面的话 函数对任何一门语言来说都是一个核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即 ...

  4. 深入理解javascript函数系列第一篇

    前面的话 函数对任何一门语言来说都是核心的概念.通过函数可以封装任意多条语句,而且可以在任何地方.任何时候调用执行.在javascript里,函数即对象,程序可以随意操控它们.函数可以嵌套在其他函数中 ...

  5. 【ABAP系列】SAP ABAP常用函数总结第一篇

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP常用函数总结第一 ...

  6. lua学习之深入函数第一篇

    深入函数第一篇 函数是第一类值,具有特定的词法域 第一类值 第一类值的意思是函数与 lua 中的其他类型如数字,字符串具有相同的权力 函数可以存储到全局变量或局部变量变量,还可以存储到 table 中 ...

  7. 使用WSE实现Web Service安全----我的第一篇

    原文:使用WSE实现Web Service安全----我的第一篇 WSE(Web Services Enhancements)是微软为了使开发者通过.NET创建出更强大,更好用的Web Service ...

  8. 第一篇 入门必备 (Android学习笔记)

    第一篇 入门必备 第1章 初识Android 第2章 搭建你的开发环境 第3章 创建第一个程序--HelloWorld 第4章 使用Android工具   ●Android之父 Android安迪·罗 ...

  9. linux0.11内核源码剖析:第一篇 内存管理、memory.c【转】

    转自:http://www.cnblogs.com/v-July-v/archive/2011/01/06/1983695.html linux0.11内核源码剖析第一篇:memory.c July  ...

  10. [转帖]虚拟内存探究 -- 第一篇:C strings & /proc

    虚拟内存探究 -- 第一篇:C strings & /proc http://blog.coderhuo.tech/2017/10/12/Virtual_Memory_C_strings_pr ...

随机推荐

  1. 矢量图绘制工具Svg-edit调整画布的大小

    矢量图绘制工具Svg-edit调整画布的大小 ------------------------------ ------------------------

  2. Devexpress WidgetView 使用总结

    效果图: 1.添加DocumentManager控件 2.Convert to WidgetView 3.添加Document,设定ControlTypeName属性,第5步用到 4.添加StackG ...

  3. QT中QProcess调用命令行的痛苦经历

    在QT程序中需要将某些目录和文件压缩为一个rar的压缩包,于是想到了在QT中通过QProcess类调用命令行的rar.exe来达到效果,但是没想到QProcess类用起来很麻烦,而且达不到效果,折腾了 ...

  4. Linux阵列 RAID详解

    主要内容:(笔记总结--会不定时补充.修改,如有错误,欢迎指正探讨)    一. RAID详解   二. mdadm工具介绍   三. 创建一个RAID的基本过程   四. 磁盘阵列的管理   五. ...

  5. struts2 ModelDriven 和 Preparable 拦截器

    Struts2 运行流程图-1

  6. "大哥,割草机借我用一下,我修整一下草坪。" ---- 谈谈this与JavaScript函数调用的不解之缘

    在写上一篇有关apply和call的博文时(闲聊JS中的apply和call),起初我还是担心大家理解起来比较困难,因为要理解apply调用方式的前提是,至少先理解在JavaScript中函数调用是什 ...

  7. NSS_03 过滤器

    asp.net mvc3有四类过滤器:授权, 操作,结果, 异常.操行的顺序为:授权,操作,结果,异常. 首先看一下TempData: 数据只能经过至多一次的Controller传递, 并且每个元素至 ...

  8. JobControl管理多job依赖完整示例

    处理 复杂的要求的时候,有时一个mapreduce程序是完成不了的,往往需要多个mapreduce程序,这个时候就要牵扯到各个任务之间的依赖关系,所谓 依赖就是一个MR Job 的处理结果是另外的MR ...

  9. arcgis如何求两个栅格数据集的差集

    栅格数据集没有擦除功能,现在有栅格A和栅格B,怎么求两个栅格的差集C 具体步骤如下: 1.首先利用栅格计算器,把栅格B中的value全部赋值为0 输入语句:"栅格B" * 0 2  ...

  10. 写写Django中DRF框架概述以及序列化器对象serializer的构造方法以及使用

    写写Django中DRF框架概述以及序列化器对象serializer的构造方法以及使用 一.了解什么是DRF DRF: Django REST framework Django REST framew ...