执行性能测试—起步

程序越来越大,为了让程序更快地响应用户的输入,需要执行性能测试,最近在研究性能测试,就从这篇最基础的文章开始起步吧。VS 2010自带了一个功能强大的性能测试工具—Performance Wizard,在研究过程中,我决定用通过分析最普通的排序操作的程序来开始我的学习过程。

 

程序的功能很简单,接受任何文本文件,排序,然后将结果输出到一个新的文件中。第一个版本很简单,使用最好写的冒泡排序实现:

        #region 常见的排序方法 适合小文件的排序

        static void Main(string[] args)

        {

            if (args.Length != 2)

            {

                Console.WriteLine("Usage: sort <file name> <output file name>");

                return;

            }

 

            string[] sortedLines;

            using (StreamReader reader = new StreamReader(Path.GetFullPath(args[0])))

            {

                var text = reader.ReadToEnd();

                sortedLines = Sort(text);

            }

 

            using (StreamWriter writer = new StreamWriter(Path.GetFullPath(args[1])))

            {

                foreach (var line in sortedLines)

                    writer.WriteLine(line);

            }

        }

 

        #region 使用冒泡排序来测试性能

        // V1: 使用冒泡排序来测试性能

        private static string[] Sort(string text)

        {

            var lines = text.Split(new string[] { "\r\n" }, StringSplitOptions.None);

 

            for (int i = 0; i < lines.Length; ++i)

            {

                for (int j = i + 1; j < lines.Length; ++j)

                {

                    if (string.CompareOrdinal(lines[i], lines[j]) < 0)

                    {

                        var temp = lines[i];

                        lines[i] = lines[j];

                        lines[j] = temp;

                    }

                }

            }

 

            return lines;

        }

        #endregion

 

使用一个大小为2.5 兆的文本文件作为输入数据,并且用下面的步骤执行性能测试:

1.         打开Visual Studio,并点击菜单栏里的“分析(Analyze)”。

2.         点击“启动性能测试向导(Launch Performance Wizard)”。

3.         在“性能测试向导(Performance Wizard)”页面上选择“CPU Sampling (recommended)”。

4.         在后续页面上,使用页面默认的选项做完设置。

 

耐心等待程序执行完以后,Visual studio会提供一个报表,在摘要(Summary)里面—下图,可以看到,程序使用了大约36秒才完成了所有的过程。

 

另外,在Hot Path表格里,也可以看出,String.CompareOrdinal函数所占用的时间是最多的,占整个程序执行的78.44%。而从另外一个统计表Functions,这个统计表显示了在程序执行完毕之前,函数触发样例的次数,注意,这个样例触发的次数和函数被调用的次数没有对应关系,两个样例之间,函数可能被调用了多次,而且多个函数也可能被调用到—这个跟我们使用“CPU Sampling (recommended)”的策略有关,它的优点是快不影响被测程序的运行,缺点就是不够精确。从Functions的统计表里面,可以看到String.CompareOrdinal被调用到的次数是其他函数的好几倍:

 

 

 

既然已经知道冒泡排序是整个程序的瓶颈了,那我们第二个版本就是将冒泡算法改成快速排序,看看有没有改进:

#region 常见的排序方法 适合小文件的排序

        static void Main(string[] args)

        {

            if (args.Length != 2)

            {

                Console.WriteLine("Usage: sort <file name> <output file name>");

                return;

            }

 

            string[] sortedLines;

            using (StreamReader reader = new StreamReader(Path.GetFullPath(args[0])))

            {

                var text = reader.ReadToEnd();

                sortedLines = Sort(text);

            }

 

            using (StreamWriter writer = new StreamWriter(Path.GetFullPath(args[1])))

            {

                foreach (var line in sortedLines)

                    writer.WriteLine(line);

            }

        }

 

        #region 使用快速排序来测试性能

        // V2: 使用快速排序来测试性能

        private static string[] Sort(string text)

        {

            var lines = text.Split(new string[] { "\r\n" }, StringSplitOptions.None);

 

            QuickSort(lines, 0, lines.Length - 1);

 

            return lines;

        }

 

        private static int Partition(string[] lines, int lower, int upper)

        {

            var pivot = lines[upper];

            var newPivot = lower - 1;

 

            for (int i = lower; i < upper; ++i)

            {

                if (string.CompareOrdinal(pivot, lines[i]) > 0)

                {

                    var temp = lines[i];

                    newPivot = newPivot + 1;

                    lines[i] = lines[newPivot];

                    lines[newPivot] = temp;

                }

            }

 

            ++newPivot;

            lines[upper] = lines[newPivot];

            lines[newPivot] = pivot;

            return newPivot;

        }

 

        private static void QuickSort(string[] lines, int lower, int upper)

        {

            if (lower < upper)

            {

                var pivot = Partition(lines, lower, upper);

                QuickSort(lines, lower, pivot - 1);

                QuickSort(lines, pivot + 1, upper);

            }

        }

        #endregion

 

        #endregion

 

 

这次的结果要比上次好很多,这次只用了3秒多就完成了所有的工作,而且在Hot Path里面,String.CompareOrdinal函数在程序执行时间的比重也下降了很多。

 

虽然我们从总的执行时间上来看,看到了很大的性能提高,但是知道那些函数的执行效率提高了,会让你更直观的感觉到后续性能优化的目标。VS 2010支持对比多个性能报告,并给出两个报告之间的差别,例如哪些函数的执行速度有提高之类的:

1.         点击菜单栏里的“分析(Analyze)”。

2.         点击“Compare Performance Report”,在弹出来的对话框里选择两个性能测试的报告。

 

上图里,我在“Column 里面选择了“Exclusive Samples”—因为对比百分比对我来说不够直观。从对比的结果来看,快速排序在各个方面全面胜出—除了Partition函数,因为那是一个新函数。

 

接下来,为了查看快排对大文件排序的性能,我使用了一个700多兆的文本文件进行测试,这次—程序崩溃了,崩溃的原因是OutOfMemoryException……

 

下一篇讲解OutOfMemoryException的分析过程。

 

posted @ 2010-06-20 22:41  donjuan  阅读(1309)  评论(2编辑  收藏