一:背景

1. 讲故事

在 dump 分析旅程中,经常会遇到很多朋友反馈一类问题,比如:

  • 方法平时都执行的特别快,但有时候会特别慢,怎么排查?
  • 我的方法第一次执行特别慢,能看到慢在哪里吗?

相信有朋友肯定说,加些日志不就好了,大方向肯定是没问题的,但加日志的颗粒度会比较粗而且侵入性也比较大,比如说这个方法不是你的,或者说这个方法是操作系统的,一般情况下对他们无法干涉,那如何洞察在你作用域之外的方法性能呢?作为 CLR团队首推的 PerfView 性能分析工具,必须要 KO 这些问题,接下来我们就简单聊一聊。

二:PerfView 洞察慢速方法

1. 测试代码

为了方便讲述,我们模拟这样的一种情况,一个方法第一次执行会特别慢(5s),后面执行都很快(3s),测试代码如下:


internal class Program
{
static void Main(string[] args)
{
mytest1(5000); for (int i = 0; i < int.MaxValue; i++) { }; mytest1(3000); Console.ReadLine();
} static void mytest1(int senconds)
{
Console.WriteLine("mytest1 start...");
Thread.Sleep(senconds);
Console.WriteLine("mytest1 end...");
}
}

那如何用 perfview 来洞察呢?玩过 perfview 的朋友都知道它是带时间轴的,我们可以对上面的慢速方法 mytest1 适当的放大,一直找到那一次的慢速调用,为了能够记录到 Thread 使用 CPU 的情况,需要开启 ThreadTime 选项,截图如下:

完整的 Command 命令如下:


PerfView.exe "/DataFile:PerfViewData.etl" /BufferSizeMB:256 /StackCompression /CircularMB:500 /KernelEvents:ThreadTime /ClrEvents:GC,Binder,Security,AppDomainResourceManagement,Contention,Exception,Threading,JITSymbols,Type,GCHeapSurvivalAndMovement,GCHeapAndTypeNames,Stack,ThreadTransfer,Codesymbols,Compilation /NoGui /NoNGenRundown /Merge:True /Zip:True collect

有了这些基础之后,先用 perfview 开启收集,然后执行应用程序,程序执行完成之后停止 perfview 收集,稍等片刻之后就有一个生成好的 zip 文件。

2. perfview 洞察

这里选择 Thread Time Stacks 视图,在弹框中选择我们的应用程序 ConsoleApp2,截图如下:

从卦象上看,当前的 ConsoleApp2 耗费了 3.2s 的CPU时间,总跟踪时间 17.19s

既然说了方法慢那必然是知道方法名的,只不过不知道慢在方法哪里,对应代码就是 mytest1() 方法,在 perfview 面板的 Find 输入框上搜索一下 mytest1 方法就可以找到,截图如下:

那这一行怎么解读呢? 我稍微说一下吧。

  • First:表示 mytest1 第一次被调用的时间戳
  • Last: 表示 myttest1 最后一次被释放的时间戳
  • when: 这里面是 32 个时间间隔的桶,每个桶的值是资源消化的比重。
  • TimeBucket: 一个桶的时间刻度,比如上图中的 633.8 ms

有了这些基础接下来就可以放大时间轴了,依次点击: First列 -> 右键菜单 -> Set Time Range ,放大后的截图如下:

When 列的 999999999999992________599999999 可以看到,当前这 11s 的挂钟时间内大概有两次 mytest1 调用,其实的 9 表示这个桶内消耗的单个资源的90%,我们要调查的就是其中 999999999999992 段,双击 When 列的 999999999999992 ,右键选择 Set Time Range 即可,截图如下:

放大到这里就差不多了,我们已经进入了第一次 mytest1 方法调用的作用域内,接下来依次点击 右键 -> Goto -> Goto Item in Callee 来观察下这个方法的下层到底都是写什么。

从卦中的 Inc 列来看,当前的 mytest1 方法耗费了 5.01s,其内部的 Thread.Sleep() 耗费了 5.005s ,这和测试代码中的 mytest1(5000); 不约而同。

哈哈,这不就找到了问题所在,在你的真实场景下,你可以继续观察底层的调用栈,找到问题所在。

三:总结

相信这篇能够给一些在慢速方法查找上有困惑的朋友找到一些灵感,还是那句话,CLR团队首推的 PerfView 在运行期监控方面是王者般的存在,与 WinDbg 优势互补。

PerfView专题 (第十五篇): 如何洞察 C# 中的慢速方法的更多相关文章

  1. PerfView专题 (第十二篇):对 C# 下的 SDK 类库进行监控(大结局)

    一:背景 本篇是我们系列文章的最后一篇,前面的文章中大多是在 CLR Runtime 以及 OS 层面进行监控来发现各种可疑的程序问题,除了这两个层面,其实我们还可以对 SDK 中一些类进行洞察,比如 ...

  2. 第二十五篇:在SOUI中做事件分发处理

    不同的SOUI控件可以产生不同的事件.SOUI系统中提供了两种事件处理方式:事件订阅 + 事件处理映射表(参见第八篇:SOUI中控件事件的响应) 事件订阅由于直接将事件及事件处理函数连接,不存在事件分 ...

  3. python学习之【第十五篇】:Python中的常用模块之time模块

    1.前言 在Python中,对时间的表示或操作通常要使用到time模块.本篇博文就来记录一下time模块中常用的几种时间表示转换方法. 2. 三种时间表示形式 2.1 时间戳 从1970年1月1日零点 ...

  4. 第十五篇:在SOUI中消息通讯

    SOUI是一套基于Win32 SDK的窗口开发的一套DirectUI框架.在SOUI中除了有真窗口使用窗口消息通讯机制外,还有SOUI控件之间的通讯,及控件的事件处理等. 1.真窗口消息通讯 因此可以 ...

  5. Python之路(第二十五篇) 面向对象初级:反射、内置方法

    [TOC] 一.反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它 ...

  6. 解剖SQLSERVER 第十五篇 SQLSERVER存储过程的源文本存放在哪里?(译)

    解剖SQLSERVER 第十五篇  SQLSERVER存储过程的源文本存放在哪里?(译) http://improve.dk/where-does-sql-server-store-the-sourc ...

  7. Python之路【第十五篇】:Web框架

    Python之路[第十五篇]:Web框架   Web框架本质 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. 1 2 3 4 5 6 ...

  8. 第十五篇 Integration Services:SSIS参数

    本篇文章是Integration Services系列的第十五篇,详细内容请参考原文. 简介在前一篇,我们使用SSDT-BI将第一个SSIS项目My_First_SSIS_Project升级/转换到S ...

  9. 【译】第十五篇 Integration Services:SSIS参数

    本篇文章是Integration Services系列的第十五篇,详细内容请参考原文. 简介在前一篇,我们使用SSDT-BI将第一个SSIS项目My_First_SSIS_Project升级/转换到S ...

  10. 跟我学SpringCloud | 第十五篇:微服务利剑之APM平台(一)Skywalking

    目录 SpringCloud系列教程 | 第十五篇:微服务利剑之APM平台(一)Skywalking 1. Skywalking概述 2. Skywalking主要功能 3. Skywalking主要 ...

随机推荐

  1. 如何在 .NET Core WebApi 中处理 MultipartFormDataContent 中的文件

    在上一篇文章(如何在 .NET Core WebApi 中处理 MultipartFormDataContent)中,我们有描述过如何以最简单的方式在 .NET Core WebApi 中处理 Mul ...

  2. SpringBoot开启日志级别

    #开启logging logging.level.org.springframework.boot.autoconfigure: error logging: level: main.blog.map ...

  3. ping功能实现(ICMP)

    简单记录下项目中ping功能实现 笔记:ping功能实现 void Handler::handlePingDepot(const char *ip) { int mSize=50*1024; bzer ...

  4. Nginx部署多个vue前端项目

    前言:在前端项目的部署上需要让2个前端项目都部署到一个IP地址和端口下,那么我们这里就要用到Nginx了,接下来我们看看如何在一个Nginx下部署2个前端项目. 例如我的服务器地址是 http://1 ...

  5. 编程开发8大语言详解,为什么Java是我最推荐的?

    一. 前言 很多没有接触过编程语言的同学,都会觉得编程开发特别高端和神奇,担心理解不了更担心学不会. 当然,也有人会认为,你既然是做编程的,那么你应该什么都会,什么软件的开发都能完成,这是平哥经常听到 ...

  6. JS 打开本地应用软件

    我们有遇到可以直接打开QQ的跳转链接,也有遇到过直接启动office打开文档. 具体是如何操作的呢? 添加注册表项 首先需要在注册表中添加应用软件的启动地址,操作方式如下 在HKEY_CLASSES_ ...

  7. Python 将函数存储在模块中

    将函数存储在模块中 将函数存储在被称为模块的独立文件中,在将模块导入到主程序中 import语句允许在当前运行的程序文件中使用模块中的代码 通过将函数存储在独立的文件中,可影藏程序的代码细节,将重点放 ...

  8. [SWPUCTF 2021 新生赛]简简单单的逻辑

    得到一个.py文件,一般是没壳的,不过还是要养成习惯,查个壳: 意料之中,啥也没有,打开文件: 给了我们一个加密逻辑,然后最后一行给了一个结果:那么就是根据上述的逻辑,反解密出flag就好了 分析一下 ...

  9. Selenium - 元素操作(2) - 页面滚动条

    Selenium - 元素操作 函数滚动 一般元素定位,元素如果不在浏览器的可视位置(即可见只是不在可视位置),会自动把元素滚动到可视位置,但也有不会自己滚动的(比较少). 那我们就可以用seleni ...

  10. React笔记-Hooks(九)(非常全面)

    React笔记-Hooks(九) Hooks 概念 React Hooks 的意思是 组件尽量写成纯函数 如果需要外部功能和副作用 就用钩子把外部代码"钩"进来 函数组件和类组件区 ...