PerfView专题 (第一篇):如何寻找热点函数

打印 上一主题 下一主题

主题 891|帖子 891|积分 2673

一:背景

准备开个系列来聊一下 PerfView 这款工具,熟悉我的朋友都知道我喜欢用 WinDbg,这东西虽然很牛,但也不是万能的,也有一些场景他解决不了或者很难解决,这时候借助一些其他的工具来辅助,是一个很不错的主意。
很多朋友喜欢在项目中以记录日志的方式来监控项目的流转情况,其实 CoreCLR 也是这样的,参考如下代码:
  1. void gc_heap::fix_allocation_context (alloc_context* acontext, BOOL for_gc_p,
  2.                                       BOOL record_ac_p)
  3. {
  4.     dprintf (3, ("Fixing allocation context %Ix: ptr: %Ix, limit: %Ix",
  5.                  (size_t)acontext,
  6.                  (size_t)acontext->alloc_ptr, (size_t)acontext->alloc_limit));
  7. }
  8. void gc_heap::background_sweep()
  9. {
  10.     //concurrent_print_time_delta ("finished with mark and start with sweep");
  11.     concurrent_print_time_delta ("Sw");
  12.     dprintf (2, ("---- (GC%d)Background Sweep Phase ----", VolatileLoad(&settings.gc_index)));
  13.     //block concurrent allocation for large objects
  14.     dprintf (3, ("lh state: planning"));
  15. }
  16. void gc_heap::background_ephemeral_sweep()
  17. {
  18.     dprintf (3, ("bgc ephemeral sweep"));
  19. }
复制代码
那这些日志会送到哪里去呢,当然是 Windows 的 ETW 了,那有什么工具可以方便提取呢? PerfView 就是这么其中一款。
这一篇我们做一个 CPU 爆高的场景下如何寻找 热点函数 的例子,看看如何用 PerfView 去挖。
二:PerfView 寻找热点函数

很多场景下的 CPU 高,是因为某个或者某几个线程在高频的执行某个方法,有可能是死循环,有可能是陷入了CPU密集型方法内,解决这个问题一个好的思路就是对 CPU 进行采样,比如我的 12 核电脑。
  1. 0:000> !cpuid
  2. CP  F/M/S  Manufacturer     MHz
  3. 0  6,5,2                  2592
  4. 1  6,5,2                  2592
  5. 2  6,5,2                  2592
  6. 3  6,5,2                  2592
  7. 4  6,5,2                  2592
  8. 5  6,5,2                  2592
  9. 6  6,5,2                  2592
  10. 7  6,5,2                  2592
  11. 8  6,5,2                  2592
  12. 9  6,5,2                  2592
  13. 10  6,5,2                  2592
  14. 11  6,5,2                  2592
复制代码
1. 如何采样

采样的原理就是周期性的去看下当前的 CPU 核中运行的几个线程正在执行什么方法, 当采样到了几万个或者几十万个样本之后,就可以对这些采集到的方法进行分组排序来找到 topN,那些 TopN 的方法自然就是导致 CPU 爆高可能的诱因。
windbg 有一个 !running 命令可以用来显示当前处理器中正在运行的线程。
  1. lkd> !running
  2. System Processors:  (0000000000000fff)
  3.   Idle Processors:  (000000000000065e)
  4.        Prcbs             Current         (pri) Next            (pri) Idle
  5.   0    fffff80268a33180  ffffaf8ec9bd8080 (15)                       fffff8026b526600  ................
  6.   5    ffffd900e1700180  ffffaf8eca36b080 ( 8)                       ffffd900e170b340  ................
  7.   7    ffffd900e1900180  ffffaf8ec2f18080 ( 8)                       ffffd900e190b340  ................
  8.   8    ffffd900e1a00180  ffffd900e1a0b340 ( 0)                       ffffd900e1a0b340  ................
  9. 11    ffffd900e1d00180  ffffaf8eb6bee080 ( 8)                       ffffd900e1d0b340  ................
复制代码
接下来写一个程序,让其中一个线程无限循环,然后通过 PerfView 去找这个热点。
  1.     internal class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             Task.Run(() => Test1());    //Test1 故意死循环
  6.             Task.Run(() => Test2());    //Test2 是一个正常函数
  7.             Console.WriteLine("我是主线程!");
  8.             Console.ReadLine();
  9.         }
  10.         static void Test1()
  11.         {
  12.             var i = 10;
  13.             var b = true;
  14.             while (i > 0)
  15.             {
  16.                 b = !b;
  17.             }
  18.         }
  19.         static void Test2()
  20.         {
  21.             for (int i = 0; i < 10000; i++)
  22.             {
  23.                 var j = string.Join(",", Enumerable.Range(0, 100));
  24.             }
  25.             Console.WriteLine("Test执行结束");
  26.         }
  27.     }
复制代码
2. 使用 PerfView 采样

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

在这个面板中,选中如下几项。
1)CPU Samples:
  1. 设置对 CPU 进行采样。
复制代码
2)CPU Sample Interval Msec
  1. 设置采样的频次是 1ms/次。
复制代码
3)Max Collect Sec
  1. 设置总共采样多少秒,这里设置为 15 秒。
复制代码
4).NET Symbol Collection
  1. 用来从微软符号服务器上拉取符号,和采样无关哈。
复制代码
上面都设置完毕后,就可以点击 Start Collection 采集了,不出意外的话,15s 之后你就会看到如下的截图。

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

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

从图中可以看到当前 Test1() 方法在 15622 个样本中占比 97.9%,命中次数高达 15290 次,很明显这是一个绝对的 热点函数,接下来就是翻源码为什么 Test1 这么高频?
如果你想看鸡肋的 火焰图,可以点击 Flame Graph 列表项。

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美丽的神话

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表