[C#] 网站程序ASP.NET的性能诊断 - CPU分析


微软提供了标准的CLR性能分析类库

https://github.com/Microsoft/clrmd

这个类库是开源的代码。能够获取CLR runtime里面几乎所有的信息。

如何获取clrmd编译后的dll


方法一

在nuget里面搜索clrmd可以很方便的下载

方法二

估计有些同学和我一样喜欢手动挡,那么我这里提供一个下载dll的地址。项目里面只要引用这个dll就能对CLR进行分析诊断了。

https://raw.githubusercontent.com/wsq003/clrmd/master/bin/Microsoft.Diagnostics.Runtime.dll


如何分析CPU消耗


原理

1、操作系统能够记录每个os thread的cpu消耗

2、CLR的managed thread和操作系统的os thread会动态的进行映射

扫描二维码关注公众号,回复: 3794900 查看本文章

3、通过clrmd可以获取每个managed thread的call stack

4、结合123我们可以分析出asp.net里面哪个线程的代码消耗了最多CPU

思路

在asp.net项目里面新增一个‘一般处理程序ashx’页面,比如diagnose.ashx,在这个页面代码里面记录每个os thread的cpu消耗,每个managed thread的call stack,以及os thread和managed thread的对应关系。

反复调用diagnose.ashx,看看最忙的那个os thread是被哪个managed thread占用的。


参考代码

public void ProcessRequest(HttpContext context)
{
    context.Response.ContentType = "text/plain";

    {
        int pid = System.Diagnostics.Process.GetCurrentProcess().Id;
        var msg = GetCallstack(pid);
        context.Response.Write(msg);
    }

    var ths = Process.GetCurrentProcess().Threads;
    foreach (ProcessThread th in ths)
    {
        var msg = string.Format("{0}-{1:0.0}, {2:0.0}, {3:0.0}\r\n",
            th.Id, th.TotalProcessorTime.TotalSeconds, th.PrivilegedProcessorTime.TotalSeconds, th.UserProcessorTime.TotalSeconds);

        context.Response.Write(msg);
    }
}

string GetCallstack(int pid)
{
    try
    {
        using (var dataTarget = DataTarget.AttachToProcess(pid, 5000, AttachFlag.Passive))
        {
            var runtime = dataTarget.ClrVersions[0].CreateRuntime();

            string info = "";
            foreach (var t in runtime.Threads)
            {
                var cs = t.StackTrace.Select(f =>
                {
                    if (f.Method != null)
                    {
                        return f.Method.Type.Name + "." + f.Method.Name;
                    }

                    return null;
                }).ToArray();

                if (cs.Length > 0)
                {
                    info += string.Format("系统线程ID:{0} - CLR线程ID{1}:\r\n", t.OSThreadId, t.ManagedThreadId);

                    foreach (var line in cs)
                    {
                        info += string.Format("{0}\r\n", line);
                    }
                    info += "\r\n";
                }
            }

            return info;
        }

    }
    catch (Exception ex)
    {
        return "获取callstack失败:" + ex.Message;
    }
}



补充说明

因为.net framework rumtime的版本问题,要用一个单独的工具去attach其他进程做分析,有两个思路:

1、可以参考java世界的jvmti。让被诊断的进程自己暴露一个接口,把clr的各种诊断数据都吐出来。

2、可以参考clr profiler,在界面上指定clr的版本,然后attach到进程去。



猜你喜欢

转载自blog.csdn.net/wwwsq/article/details/76537788