使用Profiler分析程序性能

三个星期之前我向大家求助说,VS的Profiler分析程序性能时无法跟踪框架内部的方法调用。当时我做了不少尝试,例如下载并配置了.NET Framework的symbol文件和源代码,还尝试使用了ANTS Profiler和CLR Profiler等其他工具,最终还是没有成功。Ivony...老大在评论中告诉我说Sampling方式可以获得比Instrumentation更多的信息,不过我觉得Sampling得到的结果并不像我的目标那样干净,因此还是在寻找Instrumentation的方式。不过最终耗费了一个GTSC的支持点数,才被告知——的确应该使用Sampling。

那么我现在就来详细描述一下Profiler的使用方式吧。

首先,我们准备一个Console项目ProfilerSample,其中放入一段测试代码:

点此显示
点此隐藏

static void Main(string[] args)
{
    var array = Enumerable.Range(1, 5).Select(i => new String((char)(i + 97), 5)).ToArray();
    TestConvert(array);
    TestParse(array);
    TestTryParse(array);
}

private static List<Int32> TestParse(String[] strings)
{
    Int32 intValue;
    List<Int32> intList = new List<int>();

    for (int i = 0; i < 100000; i++)
    {
        intList.Clear();

        foreach (String str in strings)
        {
            try
            {
                intValue = Int32.Parse(str);
                intList.Add(intValue);
            }

            catch (System.ArgumentException)
            { }

            catch (System.FormatException)
            { }

            catch (System.OverflowException)
            { }
        }

    }

    return intList;
}

private static List<Int32> TestTryParse(String[] strings)
{
    Int32 intValue;
    List<Int32> intList = new List<int>();
    Boolean ret;

    for (int i = 0; i < 100000; i++)
    {
        intList.Clear();

        foreach (String str in strings)
        {
            ret = Int32.TryParse(str, out intValue);
            if (ret)
            {
                intList.Add(intValue);
            }
        }
    }

    return intList;
}

private static List<Int32> TestConvert(String[] strings)
{
    Int32 intValue;
    List<Int32> intList = new List<int>();

    for (int i = 0; i < 100000; i++)
    {
        intList.Clear();

        foreach (String str in strings)
        {
            try
            {
                intValue = Convert.ToInt32(str);
                intList.Add(intValue);
            }

            catch (System.FormatException)
            { }

            catch (System.OverflowException)
            { }
        }
    }

    return intList;
}

然后在菜单里选择Analyze - Profiler - New Performance Session,并将ProfilerSample加入Targets中:

o_profiler-1.png

请注意这里的Profile方式是Sampling。于是我们Profile这个程序(ProfilerSample),将会得到一个报表,于是我们可以浏览它的Call Tree:

o_profiler-2.png

这里显示的,已经是Expand All后的结果,可以看到调用非常之多。至于Column,除了Function Name之外,我只保留了“Inclusive Samples”和“Inclusive Samples %”两列,它们表示有多少次采样是落在这个方法的“调用树”上的。当然,您还可以选择Exlusive Samples等列,它与Inclusive的区别在于,Exlusive Samples不包括落在当前方法“子过程”里的采样。

此外,如果您看到的结果并不像截图里那么多,可能是由于Noise Reduction Options的设置关系。您可以点击上图工具栏中最右侧的按钮进行设置。

但是,看着这么一大堆信息我们会无从下手。因此,我们将滚动条拖到中段,可以发现ProfilerSample.Program.Main方法。对它点击右键,选择Set Root便会将其设为树装图的根。再折叠一些意义不大的方法(如mscorwks.dll),我们可以得到这样的结果:

o_profiler-3.png

经过观察,可以知道哪个方法,包括框架里的方法消耗的时间比较长。至于Sampling的细节,例如采样的频率,您可以在Performance Session的属性中进行设置。例如,可以选择不同的时钟周期长短进行采样。一般来说,采样频率越高,结果越准确,但这也意味着采样本身可能就会占用较多的时间——还好我们观察的主要是“比例”而不是绝对数量。

不过话说回来,我认为这个做法的目的还是在于观察框架“内部实现”的性能,有点探究“黑盒”的意味。在实际使用过程中,我们可能还是使用Instrumentations为好,因为这样得到的结果比较“干净”:

o_my-profile-result.png

虽然信息较Sampling为少,但是对于我们进行性能优化来说已经足够了。因为此时结果里显示的都是我们自己写的方法,这也是我们唯一可以修改的东西。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值