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

  • PerfView专题 (第十二篇):对 C# 下的 SDK 类库进行监控(大结局)已关闭评论
  • 191 次浏览
  • A+
所属分类:.NET技术
摘要

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


一:背景

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

  1. ArrayPool

  2. Http

  3. Socket

  4. Task

更多资料可以看下:https://docs.microsoft.com/en-us/dotnet/core/diagnostics/well-known-event-providers

接下来就来个简单的抛砖引玉

二:如何洞察

1. ArrayPool 监控

之所以对 ArrayPool 感兴趣,主要还是因为在分析 Dump 的过程中,遇到过几起 LOH 碎片化问题,比如使用第三方模板生成引擎生成 Html 导致大量临时性 char[], byte[],终导致 LOH 破败不堪,所以最后给出的建议是使用这种池化的 ArrayPool,如果可以监控池的租借情况,那是不是挺好的? 哈哈,还真有这样的 ETW,截图如下:

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

为了方便讲解,先上一段简单的测试代码:

     internal class Program     {         static void Main(string[] args)         {             var shared = ArrayPool<int>.Shared;              var rentedArray = shared.Rent(10);              for (int i = 0; i < 10; i++)             {                 rentedArray[i] = i + 1;             }              for (int j = 0; j < 10; j++)             {                 Console.WriteLine(rentedArray[j]);             }              shared.Return(rentedArray);              Console.ReadKey();         }     }  

接下来启动 Perfview,在 Additional Providers 上输入:

 *System.Buffers.ArrayPoolEventSource:::@StacksEnabled=true  

然后开启 Start Collection 观察 Array 的租借情况,稍等片刻后,在 Event 中搜索 ArrayPool 可以看到相关的 ETW 事件,截图如下:

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

Rent 列的 bufferSize="16" 中可知,当前租借了一个 size=16 的数组。

 HasStack="True" ThreadID="15,060" ProcessorNumber="10" bufferId="32,854,180" bufferSize="16" poolId="27,252,167" bucketId="-1"   

因为开启了 Stack 功能,可以在 Time MSec 列上右键选择 Open Any Stacks,在弹窗中可以轻松找到这个 rent 所在的代码,截图如下:

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

2. Http 监控

对 Http 的监控也是由于最近遇到了一个比较头疼的 dump 有感而发的,一个朋友的 dump 出现了 cpu 100% 的情况,我分析下来发现是程序在短时间内出现了大量的 Http Exception,进一步排查怀疑是 sdk 里面的异常,由于被吞了所以上层获取不到,也就找不到是第三方 sdk 哪里的代码块出的问题。

这里的找不到或者很难找到是在 WinDBG 场景下,其实借助 PerfView 还是比较好发现的,途径就是开启 System.Net.Http ETW 事件,它内置了 14 个,太强大了,截图如下:

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

为了方便讲述,先上一段测试代码。

     internal class Program     {         static void Main(string[] args)         {             for (int i = 0; i < 5; i++)             {                 GetString();             }              Console.ReadLine();         }          static async void GetString()         {             try             {                 HttpClient client = new HttpClient();                  var html = await client.GetStringAsync("https://cnblogs1.com");                  Console.WriteLine(html);             }             catch (Exception ex)             {                 Console.WriteLine(ex.Message);             }         }     }  

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

这段代码会抛出异常,然后在 catch 中给吞掉了,因为抛了异常,就可以观察它的 RequestFailed 事件,然后找到对应的 RequestStart 事件,再观察它的调用栈即可。

接下来在 PerfView 中设置 *System.Net.Http:::@StacksEnabled=true,再开启收集按钮,稍等片刻点击 Event 面板,搜集 Http 事件,截图如下:

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

从面板中可以清晰的观察到当前有 5 个请求失败,并且还带了关联的 ActivityID, 接下来可以找 ActivityID=/#18920/1/29/ 对应的 Request/Start 事件。

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

然后在 Time MSec 列上右键点击 Open Any Stacks 按钮,可以轻松的看到,那个 Request/Start 事件是 GetString() 方法触发的,截图如下:

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

3. 总结

总的来说,在 .NET 调试领域,让 PerfView 适当的配合 WinDbg,真的可以 如虎添翼 ,好了,本系列就先写到这里,感谢朋友们对本系列的持续关注。