一:背景

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. 轻量级Web框架Flask(二)

    Flask-SQLAlchemy MySQL是免费开源软件,大家可以自行搜索其官网(https://www.MySQL.com/downloads/) 测试MySQL是否安装成功 在所有程序中,找到M ...

  2. Linux中如何通过yum或者apt下载安装MySQL

    一.   yum mysql5.7以下 mysql5.7以上 Centos8 可以,但是需要重新配置文件 可以,但是需要重新配置文件 可以,但是需要重新配置文件 Centos7 可以直接yum,但是是 ...

  3. Restless API 与 Restful API

    Restful  API: 1.CURD(增删改查) 由请求方式决定 2.请求方式有:get/post/delete/put 3.同一个路径可以进行多个操作 Restless API 1.CURD(增 ...

  4. vue-element-admin 动态菜单改造

    vue-element-admin 动态菜单改造 vue-element-admin 是一款优秀后台前端解决方案,它基于 vue 和 element-ui实现.开源后台管理系统解决方案项目 Boot- ...

  5. canvas-绘制3D金字塔

    var canvas1 = document.getElementById("canvas1"); var context = canvas1.getContext("2 ...

  6. C# List转SqlServer、MySql中in字符串

    var oneList = new List<string> { "1", "2", "3" }; var oneString ...

  7. 解决Kibana(OpenSearch)某些字段无法搜索问题

    背景 最近在OpenSearch查看线上日志的时候,发现某个索引下有些字段无法直接在界面上筛选,搜索到也不高亮,非常的不方便,就像下面这样 字段左侧两个筛选按钮禁用了无法点击,提示 Unindexed ...

  8. 2022-08-18:每一个序列都是[a,b]的形式,a < b 序列连接的方式为,前一个序列的b,要等于后一个序列的a 比如 : [3, 7]、[7, 13]、[13, 26]这三个序列就可以依次连

    2022-08-18:每一个序列都是[a,b]的形式,a < b 序列连接的方式为,前一个序列的b,要等于后一个序列的a 比如 : [3, 7].[7, 13].[13, 26]这三个序列就可以 ...

  9. Grafana系列-统一展示-8-ElasticSearch日志快速搜索仪表板

    系列文章 Grafana 系列文章 概述 我们是基于这篇文章: Grafana 系列文章(十二):如何使用 Loki 创建一个用于搜索日志的 Grafana 仪表板, 创建一个类似的, 但是基于 El ...

  10. @csrf_exempt

    在Django中对于基于函数的视图我们可以 @csrf_exempt 注解来标识一个视图可以被跨域访问.那么对于基于类的视图,我们应该怎么办呢? 简单来说可以有两种访问来解决 方法一:在类的 disp ...