DotTrace系列:2. 理解四大经典的诊断类型(下)
一:背景
1. 讲故事
前面我们已经聊过四大诊断类型中的前三个 Sampling,Tracine,Line-by-Line,这篇补上最后一个诊断类型 Timeline,这也是真实场景中使用最多的,它能够采集到所有它能采集到的,比如:
- 线程栈数据 (函数执行时间)
- ETW事件 (Windows日志)
- TPL数据(方便绘制异步栈)
- 按时序绘制时间轴 (Timeline)
二:Timeline 解读
1. 一个简单的测试案例
为了方便演示,我们还是用上一篇的矩阵运算的例子,参考代码如下:
using System;
using System.Diagnostics;
namespace MatrixOperations
{
internal class Program
{
static void Main(string[] args)
{
const int baseSize = 1000;
const int iterations = 3;
for (int i = 0; i < iterations; i++)
{
int matrixSize = baseSize - (i * 100);
PerformMatrixMultiplication(matrixSize);
}
}
static void PerformMatrixMultiplication(int matrixSize)
{
Console.WriteLine($"\n=== 处理 {matrixSize}x{matrixSize} 矩阵 ===");
Console.WriteLine("创建随机矩阵...");
var matrixA = GenerateRandomMatrix(matrixSize, matrixSize);
var matrixB = GenerateRandomMatrix(matrixSize, matrixSize);
Console.WriteLine("执行矩阵乘法...");
var timer = Stopwatch.StartNew();
var resultMatrix = MultiplyMatrices(matrixA, matrixB);
timer.Stop();
Console.WriteLine($"运算完成,耗时: {timer.Elapsed.TotalSeconds:0.000} 秒");
DisplayMatrixPreview(resultMatrix);
}
static double[,] GenerateRandomMatrix(int rows, int cols)
{
var random = new Random();
var matrix = new double[rows, cols];
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
matrix[i, j] = random.NextDouble() * 100;
}
}
return matrix;
}
static double[,] MultiplyMatrices(double[,] matrixA, double[,] matrixB)
{
int aRows = matrixA.GetLength(0);
int aCols = matrixA.GetLength(1);
int bCols = matrixB.GetLength(1);
if (matrixA.GetLength(1) != matrixB.GetLength(0))
throw new ArgumentException("矩阵维度不匹配");
var result = new double[aRows, bCols];
for (int i = 0; i < aRows; i++)
{
for (int j = 0; j < bCols; j++)
{
double sum = 0;
for (int k = 0; k < aCols; k++)
{
sum += matrixA[i, k] * matrixB[k, j];
}
result[i, j] = sum;
}
}
return result;
}
static void DisplayMatrixPreview(double[,] matrix, int previewSize = 3)
{
Console.WriteLine($"\n矩阵预览 (前{previewSize}x{previewSize}个元素):");
int rows = Math.Min(previewSize, matrix.GetLength(0));
int cols = Math.Min(previewSize, matrix.GetLength(1));
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
Console.Write($"{matrix[i, j],8:0.00} ");
}
Console.WriteLine();
}
}
}
}
接下来打开 dotrace,选择 Timeline 模式,采样频次默认是 1000samples/s,即每秒1000次采样,这个相比 Sampling 模式的5~11s 要快得多,也让采集结果成倍的增加,如果你想采集的更密集些,可以设置为 8000 samples/sec,最后就是启动 Start,截图如下:

采集完成之后,就能看到如下的 采集结果界面,映入眼帘的就是的Timeline 时间轴,

在卦中的时间轴上标记着二类数据:
- 线程活动的时序分布。
- GC Wait时间(GC触发时的累计阻塞时间)
结果都有了,接下来回答三个问题来熟悉下 Timeline 模式吧。
三:几个常见的疑问解答
1. 哪个函数最耗时
宏观观察时间轴,我们发现 Main线程的轴上有一段很长的深绿色,说明它曾在这个时段活动,接下来在 Thread State 面板中选择 Running 状态,然后选择 Main 线程进行过滤。

从卦中可以看到,在追踪的13s周期中,Main在第4s时开始发飙,从 Hotspots 下的 8s MultiplyMatrices 来看,时间都被它吃了,在 Running:CPU Core 中能看到线程大多都在 core11 和 core9 上跑,找到可疑函数后,可以右键选择 Show Code 观察 MultiplyMatrices 方法的源代码,截图如下:

至此我们找到了耗费cpu的热点函数。
2. 为什么深绿色是不间断的
这是一个挺有意思的问题,熟悉操作系统知识的朋友应该知道Windows是抢占式操作系统,每个线程都会分配到一个时间片,在落地上用 量程(Quantum) 表示,所以这些间断的很显然是Main线程从失宠到得宠的一个过程,即图中的 粉色区域。

接下来在 Thread State 面板中选择 Waiting,下钻 粉色条段。

从卦中可以看到这个状态叫 Waiting for CPU,即正等待CPU再次调度。
3. 观察 GC 的运作情况
GC运作的详细信息其实用 perfview 是比较合适的,毕竟一个程序在运行过程中会很容易达到成千上万次GC,如果GC比较少的话,还是可以用 dottrace 观察一下的,接下来简单修改代码,在 MultiplyMatrices 方法的最后加上 GC.Collect(),参考如下:
static double[,] MultiplyMatrices(double[,] matrixA, double[,] matrixB)
{
int aRows = matrixA.GetLength(0);
int aCols = matrixA.GetLength(1);
int bCols = matrixB.GetLength(1);
if (matrixA.GetLength(1) != matrixB.GetLength(0))
throw new ArgumentException("矩阵维度不匹配");
var result = new double[aRows, bCols];
for (int i = 0; i < aRows; i++)
{
for (int j = 0; j < bCols; j++)
{
double sum = 0;
for (int k = 0; k < aCols; k++)
{
sum += matrixA[i, k] * matrixB[k, j];
}
result[i, j] = sum;
}
}
GC.Collect(); //故意触发阻塞GC
return result;
}
启动 dottrace 跟踪,完成之后截图如下:

打开卦之后,选中 Main线程,GarbageCollection事件以及Running状态,可以清晰的看到,当前触发了 3次 阻塞GC,1次后台GC。
四:总结
整体上来说,dottrace最大的优点就是时间轴,在某些场景下比 perfview 的表格展示法更加清楚,timeline模式也是在真实场景中用的最多的一种洞察方式。
作为JetBrains社区内容合作者,如有购买jetbrains的产品,可以用我的折扣码 HUANGXINCHENG,有25%的内部优惠哦。

DotTrace系列:2. 理解四大经典的诊断类型(下)的更多相关文章
- 老生常谈系列之Aop--Aop的经典应用之Spring的事务实现分析(三)
老生常谈系列之Aop--Aop的经典应用之Spring的事务实现分析(三) 前言 上一篇文章老生常谈系列之Aop--Aop的经典应用之Spring的事务实现分析(二)从三个问题导入,分析了Spring ...
- OpenStack实践系列⑦深入理解neutron和虚拟机
OpenStack实践系列⑦深入理解neutron和虚拟机 五.深入理解Neutron 5.1 虚拟机网卡和网桥 [root@node1 ~]# ifconfig brq65c11cc3-8e: fl ...
- 微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件
原文:微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件 开篇介绍 大多数情况下我们的 SSIS 包都会配置在 SQL Agent ...
- 【Xamarin挖墙脚系列:时刻下载最新的Mac环境下的Xamarin安装包】
原文:[Xamarin挖墙脚系列:时刻下载最新的Mac环境下的Xamarin安装包] 打开这两个地址,就能看到最新的安装包了.... http://www.jianshu.com/p/c67c14b3 ...
- C++ : 从栈和堆来理解C#中的值类型和引用类型
C++中并没有值类型和引用类型之说,标准变量或者自定义对象的存取默认是没有区别的.但如果深入地来看,就要了解C++中,管理数据的两大内存区域:栈和堆. 栈(stack)是类似于一个先进后出的抽屉.它的 ...
- JavaScript进阶系列04,函数参数个数不确定情况下的解决方案
本篇主要体验函数参数个数不确定情况下的一个解决方案.先来看一段使用函数作为参数进行计算的实例. var calculate = function(x, y, fn) { return fn(x, y) ...
- 【ABAP系列】SAP ABAP ALV里日期类型的F4帮助
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP ALV里日期类 ...
- SpringCloud 源码系列(5)—— 负载均衡 Ribbon(下)
SpringCloud 源码系列(4)-- 负载均衡 Ribbon(上) SpringCloud 源码系列(5)-- 负载均衡 Ribbon(下) 五.Ribbon 核心接口 前面已经了解到 Ribb ...
- vue 快速入门 系列 —— 使用 vue-cli 3 搭建一个项目(下)
其他章节请看: vue 快速入门 系列 使用 vue-cli 3 搭建一个项目(下) 上篇 我们已经成功引入 element-ui.axios.mock.iconfont.nprogress,本篇继续 ...
- 前端提升生产力系列三(vant3 vue3 移动端H5下拉刷新,上拉加载组件的封装)
| 在日常的移动端开发中,经常会遇到列表的展示,以及数据量变多的情况下还会有上拉和下拉的操作.进入新公司后发现移动端好多列表,但是在看代码的时候发现,每个列表都是单独的代码,没有任何的封装,都是通过v ...
随机推荐
- APEX实战第2篇:构建自己第一个APEX程序
为了尽快实现从0到1的突破,第一个程序就选择一个最简单易懂的生活场景. 后续随着APEX学习过程不断迭代增强这个程序. 现在就开始吧,我给孩子看一些公开网络课时,习惯把课程资源做分片,然后有计划的让孩 ...
- BUUCTF---robomunication
略有抽象,第一次接触直接上题解吧
- 【Linux】Vim 设置
[Linux]Vim 设置 零.起因 刚学Linux,有时候会重装Linux系统,然后默认的vi不太好用,需要进行一些设置,本文简述如何配置一个好用的Vim. 壹.软件安装 sudo apt-get ...
- 学习Linux只要学会这个命令就够了!
大家好,我是良许. 这段时间又是搬家,又是找新办公室,现在终于安顿下来了,有时间给大家分享干货了. 今天给大家介绍一个 Linux 超级实用命令,有了这个命令,你就可以愉快使用 Linux 上几乎所有 ...
- 快戳进来!PostgreSQL实战型系列文章来了!
快戳进来!PostgreSQL实战型系列文章来了! Whoami:6年+金融.政府.医疗领域工作经验的DBA Certificate:PGCM.OCP.YCP Skill:Oracle.Mysql.P ...
- 《数组》--DAY1--二分查找
分治算法--二分查找(返回下标) 1.定义:在有序列表中,每次查找范围折半 列表若存在重复元素,返回下标不唯一 优点:比较次数少,速度快,性能好:缺点:要求列表有序 注意区分while(left &l ...
- 使用Python计算汉密尔顿路径
引言 在图论中,汉密尔顿路径(Hamiltonian Path)是一个经典问题,它在很多实际应用中都有广泛的应用,如网络路由.旅行商问题等.今天,我们将一起探讨如何使用 Python 来计算汉密尔顿路 ...
- docker容器运行,交互式与守护式的区别
一.使用交互式运行容器,容器运行后直接进入到容器内部,退出容器内部后,容器直接关闭
- CTF靶场学习-XXE漏洞篇
XXE漏洞1(无限制) XXE特征:在HTTP的Request报文出现一下请求报文,即表明此时是采用XML进行数据传输,就可以测试是否存在XML漏洞. 默认xxe,没有任何限制,可以直接读取flag ...
- Laravel报错Call to undefined function Termwind\ValueObjects\mb_strimwidth()解决办法
Laravel报错Call to undefined function Termwind\ValueObjects\mb_strimwidth() 通常是因为php的mbstring扩展没有打开 解决 ...