一:背景

1. 讲故事

如果要分析 Linux上的 .NET程序 CPU 爆高,按以往的个性我肯定是抓个 dump 下来做事后分析,这种分析模式虽然不重但也不轻,还需要一定的底层知识,那有没有傻瓜式的 CPU 爆高分析方式呢?

相信有很多朋友知道 B站713事件,最终就是用 perf 找到了那个让 cpu 100% 的 lua 函数,截图如下:

这里我们也借助 perf 这款工具实现 .NET程序的 cpu 爆高洞察, perf 就不过多介绍了,它是Linux系统中提供的一款性能分析工具,类似 Windows 的 ETW 跟踪,所以对他的了解是非常重要的。

这里要注意的是我们并不直接使用,而是用微软提供的基于 perf 的高层封装工具 perfCollect,它不仅能收集 perf 能收集的事件,还能收集 .NET 中的 EventSource 事件,简直是福音哈。

PerfCollect 跟踪

1. 测试代码

为了能够让 CPU 爆高,我们故意让其中一个方法死循环,一个方法运行一段时间正常结束,参考代码如下:


namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
Task.Run(() =>
{
Test1();
}); Task.Run(() =>
{
Test2();
}); Console.ReadLine();
} static void Test1()
{
int i = 1;
bool b = false; while (i > 0)
{
b = !b;
}
} static void Test2()
{
for (int i = 0; i < short.MaxValue; i++)
{ }
}
}
}

代码有了就可以 publish 到 centos 上,接下来在 /etc/profile 中增加一个环境变量 export COMPlus_PerfMapEnabled=1 ,目的是让 RIP 能够成功解析到 C# 的方法名,截图如下:

有了这些前置基础,接下来就是把程序跑起来,用 htop 观察下 CPU 的利用率。


[root@localhost data2]# vim /etc/profile
[root@localhost data2]# source /etc/profile
[root@localhost data2]# ls
ConsoleApp1 ConsoleApp1.deps.json ConsoleApp1.dll ConsoleApp1.pdb ConsoleApp1.runtimeconfig.json
[root@localhost data2]# dotnet ConsoleApp1.dll

2. 安装 PerfCollect

刚才也说了 PerfCollect 是微软提供的一款工具,集成了 perf + LTTng 两块,前者用于捕获Linux系统级事件,后者用于捕获 CoreCLR 以及 EventSource 事件,接下来就是下载,赋权限,安装。


[root@localhost data3]# curl -OL https://aka.ms/perfcollect
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:02 --:--:-- 0
100 68590 100 68590 0 0 17540 0 0:00:03 0:00:03 --:--:-- 72658
[root@localhost data3]# chmod +x perfcollect
[root@localhost data3]# sudo ./perfcollect install
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
epel/x86_64/metalink | 28 kB 00:00:00
* base: ftp.sjtu.edu.cn
* epel: d2lzkl7pfhq30w.cloudfront.net
* extras: mirror.lzu.edu.cn
* updates: mirror.lzu.edu.cn
base | 3.6 kB 00:00:00
docker-ce-stable | 3.5 kB 00:00:00
extras | 2.9 kB 00:00:00
packages-microsoft-com-prod | 1.5 kB 00:00:00
updates | 2.9 kB 00:00:00
Package perf-3.10.0-1160.92.1.el7.x86_64 already installed and latest version
Package zip-3.0-11.el7.x86_64 already installed and latest version
Package unzip-6.0-24.el7_9.x86_64 already installed and latest version
Nothing to do
LTTng already installed.

安装好之后进行 10s 采集,采集完之后就会生成一个 ConsoleApp.trace.zip 文件,输出如下:


[root@localhost data3]# ./perfcollect collect ConsoleApp -collectsec 10
Collection started. Collection will automatically stop in 10 second(s). Press CTRL+C to stop early. ...STOPPED. Starting post-processing. This may take some time. Generating native image symbol files
...FINISHED
Saving native symbols
...FINISHED
Resolving JIT and R2R symbols
...FINISHED
Exporting perf.data file
...FINISHED
Compressing trace files
...FINISHED
Cleaning up artifacts
...FINISHED Trace saved to ConsoleApp.trace.zip

最后把 ConsoleApp.trace.zip 复制到 Windows 平台上用 PerfView 分析。

3. Perfview 分析

说句良心话,Perfview 真的是太强大了,什么文件都能从中提取有用信息,比如 .dmp,.nettrace 还有这里的 .zip ,用 Perfview 打开 zip 之后,双击 CPU Stacks 选项,找到我们的 PID 进程即(.NET ThreadPool),截图如下:


[root@localhost data3]# ps -ef | grep dotnet
root 6027 3171 99 23:33 pts/1 00:02:01 dotnet ConsoleApp1.dll
root 6529 5240 0 23:35 pts/2 00:00:00 grep --color=auto dotnet

双击打开之后,去掉 GroupPats 信息,可以看到占比最高的是 Program::Test1() 方法。

有朋友可能要问这个信息怎么解读呢?其实非常简单,perf 也是按照 1ms 采样一次的方式,所以 10s 的样本数: 1w =10 * 1000

从上图中可以看到,总的采样到了 9999 个样本,其中 Program::Test1() 占据了 9993,占比高达 99.9%,到这里我们就定位出了原来这个函数就是 hot 函数。

三:总结

不知道大家发现没有,在 Windows 上很容易监控的东西,在 Linux 上就要麻烦的多,其实很容易理解,Windows 是微软的, .NET 也是微软的,自然是一等公民的存在。

用 perfcollect 洞察 Linux 上.NET程序 CPU爆高的更多相关文章

  1. linux上应用程序的执行机制

    linux上应用程序的执行机制 执行文件是如何在shell中被"执行"的.本文中尽可能少用一些源码,免得太过于无 聊,主要讲清这个过程,感兴趣的同学可以去查看相应的源码了解更多的信 ...

  2. Linux 上 C 程序的内存布局

    在仔细研究这个问题之前,我认为 C 程序在内存中只有代码段,堆和栈三部分构成.前几天面试被问到了这个问题,才发现自己的印象是不完全的. 在本文中通过解析析一个 C 程序中变量和函数的地址来分析 C 程 ...

  3. Linux上java程序的jar包启动通用脚本(稳定用过)

    Linux上java程序的jar包启动通用脚本如下: #! /bin/sh export LANG="zh_CN.GBK" SERVICE_NAME=` .sh` SCRIPT_N ...

  4. Linux上使用程序相对路径访问文件【转】

    转自:http://blog.csdn.net/yinxusen/article/details/7444249 今天一个朋友问我这个问题,说为什么在Windows上跑得很好的应用程序,移植到Linu ...

  5. 某工控图片上传服务 CPU 爆高分析

    一:背景 1.讲故事 今天给大家带来一个入门级的 CPU 爆高案例,前段时间有位朋友找到我,说他的程序间歇性的 CPU 爆高,不知道是啥情况,让我帮忙看下,既然找到我,那就用 WinDbg 看一下. ...

  6. 分析Linux上的程序依赖

    ldd [path_to_exe] ldd通过调用动态链接器来获取可执行程序的依赖库,但是并不推荐在未知的可执行程序上执行业ldd来获取其依赖库,因为部分版本的ldd会直接通过调用该可执行程序来获取其 ...

  7. linux上安装程序出现的问题汇总

    1.程序在编译过程中出现:variable set but not used [-Werror=unused-but-set-variable] 解决方法:将configure文件和Makefile文 ...

  8. linux环境java程序cpu爆表问题查证

    1.top命令查找导致cup爆表的进程 2. top -H -p10832 (10832是Java进程的PID)命令找出了具体的线程 3.使用用命令 jstack 10832> jstack.t ...

  9. 在 Linux 上找出并解决程序错误的主要方法【转】

    转自:https://www.ibm.com/developerworks/cn/linux/sdk/l-debug/index.html 本文讨论了四种调试 Linux 程序的情况.在第 1 种情况 ...

  10. java程序——CPU过高100%及内存泄露排查

    CPU过高 这类问题可以使用 top 命令观察一些,CPU 是不是都被 Java 程序占用了.比如下面这个截图: 服务器的 CPU 大多都被 Java 占用了.这正是我们之前生产上 CPU 过高的一个 ...

随机推荐

  1. [操作系统] - 进程切换&进程控制

    2.1.6 进程切换 名称解析 进程的上下文(Context) 当一个进程在执行时,CPU的所有寄存器的值.进程的状态以及堆栈中的内容被称为进程的上下文Context 进程的切换(switch) 当内 ...

  2. NLP入门1——李宏毅网课笔记

    近日因为项目需要,开始恶补预习NLP的相关知识.以前也看过两本相关书籍,但是都十分浅显.这次准备详细的学一下并记录. 李宏毅老师的网课是 Deep Learning for Human Languag ...

  3. Docker高级

    一.Docker安装企业级开发应用 1.Docker搭建MySQL主从 (1) 创建master主机MySQL docker run -p 3307:3306 --name mysql-master ...

  4. 企名片Js逆向思路

    企名片Js逆向思路 这个案例不算难,简单说一下思路. 目标链接:https://www.qimingpian.cn/finosda/project/pinvestment 网站更新了https://w ...

  5. Django, urls的参数name的demo

    Django的路由变化 遇到需要修改路由的需求,特别记录一下 项目开始 django-admin startproject sandboxOA. # 外部文件夹可以改变名字, '.'的意思是上一级不需 ...

  6. 18年CCCC赛后总结

    C4赛后总结: 我正式入坑以来,大约5个月,这也是我第一次出去参与这样正式的比赛,其实比赛结果并不尽人意,但有很多还是需要记录下来的,通过这次比赛的确获得了很多的比赛经验: 一赛前: 其实赛前的状态, ...

  7. 2022-12-22:给定一个数字n,代表数组的长度, 给定一个数字m,代表数组每个位置都可以在1~m之间选择数字, 所有长度为n的数组中,最长递增子序列长度为3的数组,叫做达标数组。 返回达标数组的

    2022-12-22:给定一个数字n,代表数组的长度, 给定一个数字m,代表数组每个位置都可以在1~m之间选择数字, 所有长度为n的数组中,最长递增子序列长度为3的数组,叫做达标数组. 返回达标数组的 ...

  8. 2020-09-13:判断一个正整数是a的b次方,a和b是整数,并且大于等于2,如何求解?

    福哥答案2020-09-13: 首先确定b的范围,b的范围一定在[2,logN]里.然后遍历b,求a的范围,如果范围长度等于0,说明这个正整数是a的b次方.1.遍历b范围.二分法求a,a初始范围是[2 ...

  9. 2021-05-12:给定一个数组arr,只能对arr中的一个子数组排序, 但是想让arr整体都有序。返回满足这一设定的子数组中,最短的是多长?

    2021-05-12:给定一个数组arr,只能对arr中的一个子数组排序, 但是想让arr整体都有序.返回满足这一设定的子数组中,最短的是多长? 福大大 答案2021-05-12: 从左往右遍历,缓存 ...

  10. Django4全栈进阶之路20 项目实战(三种方式开发部门管理):方式一:FBV

    1.模型 from django.db import models from django.contrib.auth.models import User # Create your models h ...