一:背景

准备开个系列来聊一下 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. PerfView专题 (第二篇):如何寻找 C# 中的 Heap堆内存泄漏

    一:背景 上一篇我们聊到了如何去找 热点函数,这一篇我们来看下当你的程序出现了 非托管内存泄漏 时如何去寻找可疑的代码源头,其实思路很简单,就是在 HeapAlloc 或者 VirtualAlloc ...

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

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

  3. PerfView专题 (第九篇):洞察 C# 中的 LOH 内存碎片化

    一:背景 在 内存泄漏 的系列问题中,有一类问题是 内存碎片化 导致的,而且这种更容易发生在 LOH 上,因为它默认不开启 对象压缩,一般遇到这种情况,优先让朋友执行下面的代码应急. GCSettin ...

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

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

  5. TTD 专题 (第一篇):C# 那些短命线程都在干什么?

    一:背景 1.讲故事 在分析的众多dump中,经常会遇到各种奇葩的问题,仅通过dump这种快照形式还是有很多问题搞不定,而通过 perfview 这种粒度又太粗,很难找到问题之所在,真的很头疼,比如本 ...

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

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

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

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

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

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

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

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

随机推荐

  1. SPPNet(特征金字塔池化)学习笔记

    SPPNet paper:Spatial pyramid pooling in deep convolutional networks for visual recognition code 首先介绍 ...

  2. Pandas 分组聚合 :分组、分组对象操作

    1.概述 1.1 group语法 df.groupby(self, by=None, axis=0, level=None, as_index: bool=True, sort: bool=True, ...

  3. A* K短路

    注:\(A*\) 求解K短路效率极其低下,时间复杂度\(O(nklog\ n)\),空间视题目而定,因为本质是爆搜,可求解数据范围较小的题目. 我们使用\(A*\)求解k短路: 首先需要预处理出估价函 ...

  4. ZJOI2020

    [ZJOI2015] 地震后的幻想乡 给定一个无向图 \(G\) ,\(n\) 个点 \(m\) 条边每条边权为 \([0,1]\) 的随机实数,求这张图的最小生成树的最大边权期望. \(1\le n ...

  5. 3000帧动画图解MySQL为什么需要binlog、redo log和undo log

    全文建立在MySQL的存储引擎为InnoDB的基础上 先看一条SQL如何入库的: 这是一条很简单的更新SQL,从MySQL服务端接收到SQL到落盘,先后经过了MySQL Server层和InnoDB存 ...

  6. 字节开源RPC框架Kitex的日志库klog源码解读

    前言 这篇文章将着重于分析字节跳动开源的RPC框架Kitex的日志库klog的源码,通过对比Go原生日志库log的实现,探究其作出的改进. 为了平滑学习曲线,我写下了这篇分析Go原生log库的文章,希 ...

  7. 隐式转换导致的cpu负载近100%

    1.背景:从昨天晚上通过钉钉和邮箱一直接收到频繁报cpu负载超过90%,刚好BI同事晚上.凌晨在线上配合审计频繁DML数据库(备注:BI有一个同事有个库的DML权限,后面等审计完会收回)加上我线上线下 ...

  8. robotframework之环境安装

    一.安装python2.7环境,python --version查询python安装的版本 二.setuptools安装

  9. BUUCTF-神秘龙卷风

    神秘龙卷风 通过提示知道压缩包密码是四位纯数字,通过爆破得到 得到一串编码 看样子应该是brainfuck编码 flag{e4bbef8bdf9743f8bf5b727a9f6332a8}

  10. BSS应用程序云原生部署的8大挑战

    云原生部署改变了软件开发.根据云原生计算基金会(CNCF)2021年年度调查,96%的组织正在使用或评估Kubernetes.更确切地说,560万开发者在使用Kubernetes,比去年增加了67%. ...